mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-07-16 17:48:51 +02:00
Merge branch '22-semi-offline-room-finder' into 'main'
Resolve "semi offline room finder: episode v - the cache stacks back" See merge request htwk-software/htwkalender-pwa!26
This commit is contained in:
@ -29,6 +29,7 @@ type RoomOccupancy struct {
|
|||||||
|
|
||||||
type RoomOccupancyList struct {
|
type RoomOccupancyList struct {
|
||||||
Start time.Time `bson:"start"`
|
Start time.Time `bson:"start"`
|
||||||
|
Updated time.Time `bson:"updated"`
|
||||||
Granularity int `bson:"granularity"`
|
Granularity int `bson:"granularity"`
|
||||||
Blocks int `bson:"blocks"`
|
Blocks int `bson:"blocks"`
|
||||||
Rooms []RoomOccupancy `bson:"rooms"`
|
Rooms []RoomOccupancy `bson:"rooms"`
|
||||||
|
@ -119,21 +119,6 @@ paths:
|
|||||||
/api/schedule/rooms:
|
/api/schedule/rooms:
|
||||||
get:
|
get:
|
||||||
summary: Get Room Occupancy
|
summary: Get Room Occupancy
|
||||||
parameters:
|
|
||||||
- name: from
|
|
||||||
in: query
|
|
||||||
description: date
|
|
||||||
example: "2024-12-24T00:00:00.000Z"
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
- name: to
|
|
||||||
in: query
|
|
||||||
description: date
|
|
||||||
example: "2024-12-25T00:00:00.000Z"
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Successful response
|
description: Successful response
|
||||||
@ -294,6 +279,9 @@ components:
|
|||||||
start:
|
start:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
updated:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
granularity:
|
granularity:
|
||||||
type: integer
|
type: integer
|
||||||
blocks:
|
blocks:
|
||||||
@ -306,9 +294,9 @@ components:
|
|||||||
occupancy:
|
occupancy:
|
||||||
type: string
|
type: string
|
||||||
format: binary
|
format: binary
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- occupancy
|
- occupancy
|
||||||
required:
|
required:
|
||||||
- start
|
- start
|
||||||
- granularity
|
- granularity
|
||||||
|
@ -181,9 +181,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/schedule/rooms",
|
Path: "/api/schedule/rooms",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
from := c.QueryParam("from")
|
rooms, err := room.GetRoomOccupancyList(app, RoomOccupancyGranularity)
|
||||||
to := c.QueryParam("to")
|
|
||||||
rooms, err := room.GetRoomOccupancyList(app, from, to, RoomOccupancyGranularity)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get room occupancy: %v", "error", err)
|
slog.Error("Failed to get room occupancy: %v", "error", err)
|
||||||
|
@ -16,15 +16,46 @@
|
|||||||
|
|
||||||
package functions
|
package functions
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const START_OF_SUMMER_SEMESTER_MONTH = time.April
|
||||||
|
const START_OF_WINTER_SEMESTER_MONTH = time.October
|
||||||
|
|
||||||
// GetCurrentSemesterString returns the current semester as string
|
// GetCurrentSemesterString returns the current semester as string
|
||||||
// if current month is between 10 and 03 -> winter semester "ws"
|
// if current month is between 10 and 03 -> winter semester "ws"
|
||||||
func GetCurrentSemesterString() string {
|
func GetCurrentSemesterString() string {
|
||||||
|
|
||||||
if time.Now().Month() >= 10 || time.Now().Month() <= 3 {
|
if now := time.Now(); isBeforeSummerSemester(now) || isAfterSummerSemester(now) {
|
||||||
return "ws"
|
return "ws"
|
||||||
} else {
|
} else {
|
||||||
return "ss"
|
return "ss"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSemesterStart gibt das Startdatum des aktuellen Semesters zurück
|
||||||
|
func GetSemesterStart(date time.Time) time.Time {
|
||||||
|
if isBeforeSummerSemester(date) {
|
||||||
|
return time.Date(date.Year()-1, START_OF_WINTER_SEMESTER_MONTH, 1, 0, 0, 0, 0, date.Location())
|
||||||
|
} else if isAfterSummerSemester(date) {
|
||||||
|
return time.Date(date.Year(), START_OF_WINTER_SEMESTER_MONTH, 1, 0, 0, 0, 0, date.Location())
|
||||||
|
} else {
|
||||||
|
return time.Date(date.Year(), START_OF_SUMMER_SEMESTER_MONTH, 1, 0, 0, 0, 0, date.Location())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if is in last month of semester
|
||||||
|
func IsLastMonthOfSemester(date time.Time) bool {
|
||||||
|
return date.Month() == START_OF_WINTER_SEMESTER_MONTH-1 || date.Month() == START_OF_SUMMER_SEMESTER_MONTH-1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given date is before the start of summer semester
|
||||||
|
func isBeforeSummerSemester(date time.Time) bool {
|
||||||
|
return date.Month() < START_OF_SUMMER_SEMESTER_MONTH
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given date is after the end of summer semester
|
||||||
|
func isAfterSummerSemester(date time.Time) bool {
|
||||||
|
return date.Month() >= START_OF_WINTER_SEMESTER_MONTH
|
||||||
|
}
|
||||||
|
@ -68,15 +68,14 @@ func GetRoomSchedule(app *pocketbase.PocketBase, room string, from string, to st
|
|||||||
* @return room occupancy list
|
* @return room occupancy list
|
||||||
* @return error if the database query fails
|
* @return error if the database query fails
|
||||||
*/
|
*/
|
||||||
func GetRoomOccupancyList(app *pocketbase.PocketBase, from string, to string, granularity int) (model.RoomOccupancyList, error) {
|
func GetRoomOccupancyList(app *pocketbase.PocketBase, granularity int) (model.RoomOccupancyList, error) {
|
||||||
// try parsing the time strings
|
|
||||||
fromTime, err := time.Parse(time.RFC3339, from)
|
now := time.Now()
|
||||||
if err != nil {
|
fromTime := functions.GetSemesterStart(now)
|
||||||
return model.RoomOccupancyList{}, err
|
toTime := functions.GetSemesterStart(now.AddDate(0, 6, 0))
|
||||||
}
|
|
||||||
toTime, err := time.Parse(time.RFC3339, to)
|
if functions.IsLastMonthOfSemester(now) {
|
||||||
if err != nil {
|
toTime = functions.GetSemesterStart(now.AddDate(1, 0, 0))
|
||||||
return model.RoomOccupancyList{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the number of blocks for the given time range and granularity
|
// calculate the number of blocks for the given time range and granularity
|
||||||
@ -142,6 +141,7 @@ func getRelevantRooms(app *pocketbase.PocketBase) ([]string, error) {
|
|||||||
func emptyRoomOccupancyList(from time.Time, granularity int, blockCount int) model.RoomOccupancyList {
|
func emptyRoomOccupancyList(from time.Time, granularity int, blockCount int) model.RoomOccupancyList {
|
||||||
return model.RoomOccupancyList{
|
return model.RoomOccupancyList{
|
||||||
Start: from,
|
Start: from,
|
||||||
|
Updated: time.Now(),
|
||||||
Granularity: granularity,
|
Granularity: granularity,
|
||||||
Blocks: blockCount,
|
Blocks: blockCount,
|
||||||
Rooms: []model.RoomOccupancy{},
|
Rooms: []model.RoomOccupancy{},
|
||||||
|
@ -26,3 +26,38 @@ self.addEventListener("install", (event) => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Custom precaching logic for the /api/schedule/rooms endpoint
|
||||||
|
self.addEventListener("install", (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.open("room-schedule-cache").then((cache) => {
|
||||||
|
return fetch("/api/schedule/rooms")
|
||||||
|
.then((response) => {
|
||||||
|
if (response.ok) {
|
||||||
|
return cache.put("/api/schedule/rooms", response);
|
||||||
|
}
|
||||||
|
throw new Error("Failed to fetch /api/schedule/rooms");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Precaching /api/schedule/rooms failed:", error);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// StaleWhileRevalidate strategy for the /api/schedule/rooms endpoint
|
||||||
|
self.addEventListener("fetch", (event) => {
|
||||||
|
if (event.request.url.includes("/api/schedule/rooms")) {
|
||||||
|
event.respondWith(
|
||||||
|
caches.open("room-schedule-cache").then((cache) => {
|
||||||
|
return cache.match(event.request).then((response) => {
|
||||||
|
const fetchPromise = fetch(event.request).then((networkResponse) => {
|
||||||
|
cache.put(event.request, networkResponse.clone());
|
||||||
|
return networkResponse;
|
||||||
|
});
|
||||||
|
return response || fetchPromise;
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
import { BSON } from "bson";
|
import { BSON } from "bson";
|
||||||
import { RoomOccupancyList } from "@/model/roomOccupancyList.ts";
|
import { RoomOccupancyList } from "@/model/roomOccupancyList.ts";
|
||||||
import { addMonths } from "date-fns";
|
|
||||||
import { formatYearMonthDay } from "@/helpers/dates";
|
import { formatYearMonthDay } from "@/helpers/dates";
|
||||||
|
|
||||||
const END_OF_SUMMER_SEMESTER = "0930";
|
const END_OF_SUMMER_SEMESTER = "0930";
|
||||||
@ -59,32 +58,19 @@ export function getSemesterStart(date: Date): Date {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the room occupancy for a given date range.
|
* Fetches the room occupancy for a given date range.
|
||||||
* @param from_date the start date of the date range
|
* @returns RoomOccupancyList - the room occupancy list containing all rooms
|
||||||
* @param to_date the end date of the date range
|
|
||||||
* @returns RoomOccupancyList - the room occupancy list
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export async function fetchRoomOccupancy(
|
export async function fetchRoomOccupancy(): Promise<RoomOccupancyList> {
|
||||||
from_date?: string,
|
|
||||||
to_date?: string,
|
|
||||||
): Promise<RoomOccupancyList> {
|
|
||||||
if (from_date == undefined) {
|
|
||||||
const new_from_date = getSemesterStart(new Date());
|
|
||||||
from_date = new_from_date.toISOString();
|
|
||||||
}
|
|
||||||
if (to_date == undefined) {
|
|
||||||
const new_to_date = getSemesterStart(addMonths(new Date(), 6));
|
|
||||||
to_date = new_to_date.toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
let roomOccupancyList: RoomOccupancyList = new RoomOccupancyList(
|
let roomOccupancyList: RoomOccupancyList = new RoomOccupancyList(
|
||||||
new Date(),
|
new Date(),
|
||||||
0,
|
new Date(2000, 0, 1),
|
||||||
0,
|
0,
|
||||||
[],
|
0,
|
||||||
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
await fetch("/api/schedule/rooms?from=" + from_date + "&to=" + to_date)
|
await fetch("/api/schedule/rooms")
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
return response.arrayBuffer();
|
return response.arrayBuffer();
|
||||||
})
|
})
|
||||||
|
@ -27,8 +27,6 @@ import { useI18n } from "vue-i18n";
|
|||||||
import allLocales from "@fullcalendar/core/locales-all";
|
import allLocales from "@fullcalendar/core/locales-all";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { formatYearMonthDay } from "@/helpers/dates";
|
import { formatYearMonthDay } from "@/helpers/dates";
|
||||||
import { useQuery } from "@tanstack/vue-query";
|
|
||||||
import { fetchRoomOccupancy } from "@/api/fetchRoomOccupancy";
|
|
||||||
import { isValid } from "date-fns";
|
import { isValid } from "date-fns";
|
||||||
import { RoomOccupancyList } from "@/model/roomOccupancyList";
|
import { RoomOccupancyList } from "@/model/roomOccupancyList";
|
||||||
|
|
||||||
@ -39,6 +37,10 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
occupancy: {
|
||||||
|
type: RoomOccupancyList,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const date: Ref<Date> = ref(new Date());
|
const date: Ref<Date> = ref(new Date());
|
||||||
@ -56,6 +58,7 @@ function setDateFromQuery() {
|
|||||||
const day = queryDate.substring(6, 8);
|
const day = queryDate.substring(6, 8);
|
||||||
date.value = new Date(`${year}-${month}-${day}`);
|
date.value = new Date(`${year}-${month}-${day}`);
|
||||||
if (!isValid(date.value)) {
|
if (!isValid(date.value)) {
|
||||||
|
console.error("Invalid date in URL, using current date instead.");
|
||||||
date.value = new Date();
|
date.value = new Date();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,6 +80,9 @@ const selectedRoom = computed(() => props.room);
|
|||||||
* @returns Anonymized occupancy events
|
* @returns Anonymized occupancy events
|
||||||
*/
|
*/
|
||||||
function transformData(data: RoomOccupancyList) {
|
function transformData(data: RoomOccupancyList) {
|
||||||
|
if (!data || !selectedRoom.value || !currentDateFrom.value || !currentDateTo.value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
return data
|
return data
|
||||||
.decodeOccupancy(
|
.decodeOccupancy(
|
||||||
selectedRoom.value,
|
selectedRoom.value,
|
||||||
@ -89,15 +95,9 @@ function transformData(data: RoomOccupancyList) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data: occupancy } = useQuery({
|
|
||||||
queryKey: ["roomOccupancy"], //, selectedRoom, currentDateFrom, currentDateTo],
|
|
||||||
queryFn: () => fetchRoomOccupancy(),
|
|
||||||
staleTime: 12 * 3600000, // 12 hours
|
|
||||||
});
|
|
||||||
|
|
||||||
const occupations = computed(() => {
|
const occupations = computed(() => {
|
||||||
if (!occupancy.value) return;
|
if (!props.occupancy) return;
|
||||||
return transformData(occupancy.value);
|
return transformData(props.occupancy);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(occupations, () => fullCalendar.value?.getApi().refetchEvents());
|
watch(occupations, () => fullCalendar.value?.getApi().refetchEvents());
|
||||||
|
@ -33,7 +33,9 @@
|
|||||||
"noRoomsAvailable": "Keine Räume verfügbar",
|
"noRoomsAvailable": "Keine Räume verfügbar",
|
||||||
"available": "verfügbar",
|
"available": "verfügbar",
|
||||||
"occupied": "belegt",
|
"occupied": "belegt",
|
||||||
"stub": "bitte online prüfen"
|
"stub": "bitte online prüfen",
|
||||||
|
"lastUpdate": "Zeitpunkt der letzten Aktualisierung",
|
||||||
|
"noData": "Es konnten keine Daten geladen werden."
|
||||||
},
|
},
|
||||||
"freeRooms": {
|
"freeRooms": {
|
||||||
"freeRooms": "Freie Räume",
|
"freeRooms": "Freie Räume",
|
||||||
|
@ -33,7 +33,9 @@
|
|||||||
"noRoomsAvailable": "no rooms listed",
|
"noRoomsAvailable": "no rooms listed",
|
||||||
"available": "available",
|
"available": "available",
|
||||||
"occupied": "occupied",
|
"occupied": "occupied",
|
||||||
"stub": "please check online"
|
"stub": "please check online",
|
||||||
|
"lastUpdate": "time of last update",
|
||||||
|
"noData": "could not load data"
|
||||||
},
|
},
|
||||||
"freeRooms": {
|
"freeRooms": {
|
||||||
"freeRooms": "free rooms",
|
"freeRooms": "free rooms",
|
||||||
|
@ -33,7 +33,9 @@
|
|||||||
"noRoomsAvailable": "利用可能な部屋がありません",
|
"noRoomsAvailable": "利用可能な部屋がありません",
|
||||||
"available": "利用可能",
|
"available": "利用可能",
|
||||||
"occupied": "占有中",
|
"occupied": "占有中",
|
||||||
"stub": "オンラインでご確認ください。"
|
"stub": "オンラインでご確認ください。",
|
||||||
|
"lastUpdate": "最終更新時刻",
|
||||||
|
"noData": "データをロードできませんでした。"
|
||||||
},
|
},
|
||||||
"freeRooms": {
|
"freeRooms": {
|
||||||
"freeRooms": "空いている部屋",
|
"freeRooms": "空いている部屋",
|
||||||
|
@ -65,6 +65,7 @@ class RoomOccupancy {
|
|||||||
export class RoomOccupancyList {
|
export class RoomOccupancyList {
|
||||||
constructor(
|
constructor(
|
||||||
public start: Date,
|
public start: Date,
|
||||||
|
public updated: Date,
|
||||||
public granularity: number,
|
public granularity: number,
|
||||||
public blocks: number,
|
public blocks: number,
|
||||||
public rooms: RoomOccupancy[],
|
public rooms: RoomOccupancy[],
|
||||||
@ -319,6 +320,7 @@ export class RoomOccupancyList {
|
|||||||
public static fromJSON(json: Document): RoomOccupancyList {
|
public static fromJSON(json: Document): RoomOccupancyList {
|
||||||
return new RoomOccupancyList(
|
return new RoomOccupancyList(
|
||||||
json.start,
|
json.start,
|
||||||
|
json.updated,
|
||||||
json.granularity,
|
json.granularity,
|
||||||
json.blocks,
|
json.blocks,
|
||||||
json.rooms.map(
|
json.rooms.map(
|
||||||
|
@ -18,16 +18,29 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Ref, computed, ref, watch } from "vue";
|
import { Ref, computed, ref, watch } from "vue";
|
||||||
import { fetchRoom } from "../api/fetchRoom.ts";
|
|
||||||
import DynamicPage from "./DynamicPage.vue";
|
import DynamicPage from "./DynamicPage.vue";
|
||||||
import RoomOccupationOffline from "../components/RoomOccupationOffline.vue";
|
import RoomOccupationOffline from "../components/RoomOccupationOffline.vue";
|
||||||
import { computedAsync } from "@vueuse/core";
|
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
||||||
|
import { fetchRoomOccupancy } from "@/api/fetchRoomOccupancy.ts";
|
||||||
|
|
||||||
type Room = {
|
type Room = {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const { data: occupancy } = useQuery({
|
||||||
|
queryKey: ["roomOccupancy"],
|
||||||
|
queryFn: () => fetchRoomOccupancy(),
|
||||||
|
staleTime: 12 * 3600000, // 12 hours
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manually refetch the room occupancy data
|
||||||
|
function refetchRoomOccupancy() {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["roomOccupancy"] });
|
||||||
|
}
|
||||||
|
|
||||||
const selectedRoom: Ref<Room> = ref({ name: "" });
|
const selectedRoom: Ref<Room> = ref({ name: "" });
|
||||||
|
|
||||||
// Watch for changes in URL parameter
|
// Watch for changes in URL parameter
|
||||||
@ -38,21 +51,15 @@ router.afterEach(async (to) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const rooms = computedAsync<Set<string>>(async () => {
|
const rooms = computed<Set<string>>(() => {
|
||||||
let rooms: Set<string> = new Set();
|
const rooms: Set<string> = new Set();
|
||||||
return await fetchRoom()
|
|
||||||
.then((data) => {
|
occupancy.value?.rooms.forEach((room) => {
|
||||||
rooms = new Set(data);
|
rooms.add(room.name);
|
||||||
return rooms;
|
});
|
||||||
})
|
|
||||||
.finally(() => {
|
return rooms;
|
||||||
const room = router.currentRoute.value.query.room;
|
});
|
||||||
if (room && typeof room === "string") {
|
|
||||||
// check if room is available in roomsList
|
|
||||||
setRoomFromList(room, rooms);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, new Set());
|
|
||||||
|
|
||||||
const roomsList = computed(() => {
|
const roomsList = computed(() => {
|
||||||
return Array.from(rooms.value).map((room) => {
|
return Array.from(rooms.value).map((room) => {
|
||||||
@ -102,7 +109,16 @@ watch(selectedRoom, (newRoom: Room) => {
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<RoomOccupationOffline :room="selectedRoom.name" />
|
<RoomOccupationOffline v-if="occupancy" :room="selectedRoom.name" :occupancy="occupancy"/>
|
||||||
|
<div v-else>
|
||||||
|
<p>{{ $t('roomFinderPage.noData') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--last update date-->
|
||||||
|
<div class="flex align-items-baseline justify-content-end text-right text-xs text-gray-500">
|
||||||
|
<span v-if="occupancy">{{ $t("roomFinderPage.lastUpdate") }}: {{ $d(occupancy.updated, 'long') }}</span>
|
||||||
|
<Button size="small" icon="pi pi-refresh" class="p-button-text p-button-sm" @click="refetchRoomOccupancy" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</DynamicPage>
|
</DynamicPage>
|
||||||
</template>
|
</template>
|
||||||
|
@ -89,7 +89,7 @@ export default defineConfig({
|
|||||||
registerType: "autoUpdate",
|
registerType: "autoUpdate",
|
||||||
strategies: "injectManifest",
|
strategies: "injectManifest",
|
||||||
injectManifest: {
|
injectManifest: {
|
||||||
globPatterns: ["**/*.{js,css,html,png,svg}"],
|
globPatterns: ["**/*.{js,css,html,ico,png,svg,json,vue,txt,woff2}", "/api/schedule/rooms"],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
Reference in New Issue
Block a user