@powerportalspro/react-calendar 12.0.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +294 -498
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +295 -499
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { makeStyles, tokens, useThemeClassName,
|
|
2
|
-
import { ChevronRightRegular, ChevronLeftRegular,
|
|
1
|
+
import { makeStyles, tokens, useThemeClassName, ToolbarButton, Text, mergeClasses, Menu, MenuTrigger, MenuButton, MenuPopover, MenuList, MenuItemRadio, MessageBar, MessageBarBody, Spinner, Tooltip, Button, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, MenuItem, Field, Dropdown, Option, SpinButton, Checkbox, ToggleButton, RadioGroup, Radio, Input } from '@fluentui/react-components';
|
|
2
|
+
import { ChevronRightRegular, ChevronLeftRegular, ArrowRepeatAllRegular, AddRegular, ChevronDownRegular } from '@fluentui/react-icons';
|
|
3
3
|
import FullCalendar, { useCalendarController } from '@fullcalendar/react';
|
|
4
4
|
import dayGridPlugin from '@fullcalendar/react/daygrid';
|
|
5
5
|
import interactionPlugin from '@fullcalendar/react/interaction';
|
|
6
6
|
import listPlugin from '@fullcalendar/react/list';
|
|
7
7
|
import timeGridPlugin from '@fullcalendar/react/timegrid';
|
|
8
8
|
import formaTheme from '@fullcalendar/react/themes/forma';
|
|
9
|
-
import { savedViewControl, SavedViewControlKind, defaultViewId, isViewHidden, TableSecurityPermission,
|
|
10
|
-
import { useDialogService, usePrefixedT, useT, useUserTimeZone, useLocale, usePowerPortalsPro, useLocalization, RecordContext, useRecordContext, useLocalizationLoaded, QueryStatus, useRunWithOverlay, useMainContext } from '@powerportalspro/react';
|
|
11
|
-
import { useSavedViews, useMultiTableViews,
|
|
9
|
+
import { savedViewControl, SavedViewControlKind, MultiTableUses, defaultViewId, MultiTableViewType, isViewHidden, TableSecurityPermission, shownViewTables, findRecordPage, recordPageUrl, getRecordReferenceId, firstDayOfWeek } from '@powerportalspro/core';
|
|
10
|
+
import { useDialogService, usePrefixedT, useT, useUserTimeZone, useLocale, usePowerPortalsPro, useLocalization, replaceQueryParam, useRecordPages, RecordContext, useRecordContext, useLocalizationLoaded, QueryStatus, useRunWithOverlay, useMainContext } from '@powerportalspro/react';
|
|
11
|
+
import { useSavedViews, useMultiTableViews, useMultiTableTableSet, EVERY_TABLE_VIEW_ID, useSavedViewSession, everyRow, ViewToolbar, ViewSearchBox, ViewFilterMenu, ViewRefreshButton, ViewPicker, ViewSort, SavedViewDialogs, MultiTableFilterDialog, ViewLoadMessages, MultiTableRecordPanel, viewLabelOf, followRecordLink, RecordDialogShell, RecordDialogFrame, SaveContextButton, ColumnEdit, StatusReasonEdit, DeleteContextButton, SharedTooltip } from '@powerportalspro/react-fluent';
|
|
12
12
|
import { createContext, useContext, useState, useMemo, useRef, useEffect, useCallback, useId } from 'react';
|
|
13
13
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
14
14
|
|
|
@@ -26,8 +26,6 @@ function useCalendarContext() {
|
|
|
26
26
|
if (!context) throw new Error("useCalendarContext must be used in a <Calendar>, among its toolbar items.");
|
|
27
27
|
return context;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
// src/recurrence-pattern.ts
|
|
31
29
|
var RecurrenceFrequency = {
|
|
32
30
|
Daily: 0,
|
|
33
31
|
Weekly: 1,
|
|
@@ -180,15 +178,6 @@ function describeRecurrence(pattern, start, locale, t) {
|
|
|
180
178
|
}
|
|
181
179
|
return repeats;
|
|
182
180
|
}
|
|
183
|
-
function firstDayOfWeek(locale) {
|
|
184
|
-
try {
|
|
185
|
-
const intlLocale = new Intl.Locale(locale);
|
|
186
|
-
const firstDay = intlLocale.getWeekInfo?.().firstDay ?? intlLocale.weekInfo?.firstDay;
|
|
187
|
-
return firstDay === void 0 ? 0 : firstDay % 7;
|
|
188
|
-
} catch {
|
|
189
|
-
return 0;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
181
|
function weekOrder(locale) {
|
|
193
182
|
const first = firstDayOfWeek(locale);
|
|
194
183
|
return Array.from({ length: 7 }, (_, i) => (first + i) % 7);
|
|
@@ -304,6 +293,7 @@ function RecurrenceEdit({ value, onChange, start, allowNone = true, readOnly = f
|
|
|
304
293
|
const t = usePrefixedT("app.components.calendar.recurrence");
|
|
305
294
|
const id = useId();
|
|
306
295
|
const language = locale ?? navigator.language;
|
|
296
|
+
const rootRef = useRef(null);
|
|
307
297
|
const startDay = useRef(start.weekday);
|
|
308
298
|
useEffect(() => {
|
|
309
299
|
const was = startDay.current;
|
|
@@ -322,7 +312,8 @@ function RecurrenceEdit({ value, onChange, start, allowNone = true, readOnly = f
|
|
|
322
312
|
const pattern = startingPattern(frequency, start);
|
|
323
313
|
onChange(value ? { ...pattern, end: value.end, occurrences: value.occurrences, endDate: value.endDate } : pattern);
|
|
324
314
|
};
|
|
325
|
-
return /* @__PURE__ */ jsxs("div", { className: styles.root, children: [
|
|
315
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: styles.root, children: [
|
|
316
|
+
/* @__PURE__ */ jsx(SharedTooltip, { containerRef: rootRef }),
|
|
326
317
|
/* @__PURE__ */ jsx(Field, { label: t("label"), children: /* @__PURE__ */ jsx(
|
|
327
318
|
Dropdown,
|
|
328
319
|
{
|
|
@@ -395,7 +386,7 @@ function PatternFields({
|
|
|
395
386
|
size: "small",
|
|
396
387
|
checked: pressed,
|
|
397
388
|
disabled: readOnly,
|
|
398
|
-
|
|
389
|
+
"data-ppp-tooltip": dayName(weekday, locale),
|
|
399
390
|
"aria-label": dayName(weekday, locale),
|
|
400
391
|
onClick: () => {
|
|
401
392
|
const days = value.days ^ flag;
|
|
@@ -495,12 +486,28 @@ function AppointmentDetailsDialog({
|
|
|
495
486
|
onClose,
|
|
496
487
|
onSaved,
|
|
497
488
|
children,
|
|
498
|
-
location = "center"
|
|
489
|
+
location = "center",
|
|
490
|
+
showRecordLinks = true,
|
|
491
|
+
onNavigate
|
|
499
492
|
}) {
|
|
500
493
|
const t = usePrefixedT("app.components.calendar");
|
|
501
494
|
const tAll = useT();
|
|
502
495
|
const open = appointment !== null || newAppointment2 !== null;
|
|
503
496
|
const isSeries = appointment?.isSeries === true;
|
|
497
|
+
const recordPages = useRecordPages({ enabled: showRecordLinks });
|
|
498
|
+
const appointmentPage = showRecordLinks && appointment && !isSeries ? findRecordPage(recordPages, "appointment") : void 0;
|
|
499
|
+
const pageUrl = appointmentPage && appointment ? recordPageUrl(appointmentPage, appointment.id) : void 0;
|
|
500
|
+
const openPage = pageUrl !== void 0 && /* @__PURE__ */ jsx(
|
|
501
|
+
Button,
|
|
502
|
+
{
|
|
503
|
+
as: "a",
|
|
504
|
+
href: pageUrl,
|
|
505
|
+
className: "ppp-calendar-open-record",
|
|
506
|
+
onClick: (event) => followRecordLink(event, pageUrl, onNavigate),
|
|
507
|
+
children: tAll("app.buttons.open.label")
|
|
508
|
+
}
|
|
509
|
+
);
|
|
510
|
+
const regardingLinks = { showRecordLinks, ...onNavigate && { onNavigate } };
|
|
504
511
|
const mayCreateSeries = useMayCreateSeries(open && editable && !isSeries && appointment?.recurring !== true);
|
|
505
512
|
const saved = () => {
|
|
506
513
|
onClose();
|
|
@@ -527,16 +534,21 @@ function AppointmentDetailsDialog({
|
|
|
527
534
|
title: appointment ? appointment.subject : t("new-appointment"),
|
|
528
535
|
actions: editable ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
529
536
|
/* @__PURE__ */ jsx(DeleteAction, { seriesId: appointment?.seriesId ?? null, onDeleted: saved }),
|
|
537
|
+
openPage,
|
|
530
538
|
/* @__PURE__ */ jsx(SaveContextButton, { appearance: "primary", onSaved: saved }),
|
|
531
539
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, children: tAll("app.buttons.cancel.label") })
|
|
532
|
-
] }) : /* @__PURE__ */
|
|
533
|
-
|
|
540
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
541
|
+
openPage,
|
|
542
|
+
/* @__PURE__ */ jsx(Button, { appearance: "primary", onClick: onClose, children: t("close") })
|
|
543
|
+
] }),
|
|
544
|
+
children: isSeries ? /* @__PURE__ */ jsx(SeriesRecord, { editable, regardingTables, regardingLinks }) : /* @__PURE__ */ jsx(
|
|
534
545
|
AppointmentRecord,
|
|
535
546
|
{
|
|
536
547
|
recurring: appointment?.recurring ?? false,
|
|
537
548
|
editable,
|
|
538
549
|
creating: !appointment,
|
|
539
550
|
regardingTables,
|
|
551
|
+
regardingLinks,
|
|
540
552
|
mayCreateSeries,
|
|
541
553
|
children
|
|
542
554
|
}
|
|
@@ -629,6 +641,7 @@ function AppointmentRecord({
|
|
|
629
641
|
editable,
|
|
630
642
|
creating,
|
|
631
643
|
regardingTables,
|
|
644
|
+
regardingLinks,
|
|
632
645
|
mayCreateSeries,
|
|
633
646
|
children
|
|
634
647
|
}) {
|
|
@@ -655,7 +668,7 @@ function AppointmentRecord({
|
|
|
655
668
|
!creating && /* @__PURE__ */ jsx(ColumnEdit, { columnName: "organizer", readOnly: true }),
|
|
656
669
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "requiredattendees", readOnly }),
|
|
657
670
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "optionalattendees", readOnly }),
|
|
658
|
-
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables } }),
|
|
671
|
+
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables }, ...regardingLinks }),
|
|
659
672
|
!creating && /* @__PURE__ */ jsx(StatusReasonEdit, { columnName: "statuscode", allowStateChange: true, readOnly }),
|
|
660
673
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "description", readOnly })
|
|
661
674
|
] });
|
|
@@ -744,7 +757,11 @@ function seriesRequests(pattern, appointment, timeZone) {
|
|
|
744
757
|
};
|
|
745
758
|
return [request];
|
|
746
759
|
}
|
|
747
|
-
function SeriesRecord({
|
|
760
|
+
function SeriesRecord({
|
|
761
|
+
editable,
|
|
762
|
+
regardingTables,
|
|
763
|
+
regardingLinks
|
|
764
|
+
}) {
|
|
748
765
|
const styles = useStyles2();
|
|
749
766
|
const t = usePrefixedT("app.components.calendar");
|
|
750
767
|
const ctx = useRecordContext();
|
|
@@ -802,7 +819,7 @@ function SeriesRecord({ editable, regardingTables }) {
|
|
|
802
819
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "organizer", readOnly: true }),
|
|
803
820
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "requiredattendees", readOnly }),
|
|
804
821
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "optionalattendees", readOnly }),
|
|
805
|
-
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables } }),
|
|
822
|
+
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables }, ...regardingLinks }),
|
|
806
823
|
/* @__PURE__ */ jsx(ColumnEdit, { columnName: "description", readOnly })
|
|
807
824
|
] });
|
|
808
825
|
}
|
|
@@ -1217,8 +1234,47 @@ function newAppointment(range, regarding) {
|
|
|
1217
1234
|
}
|
|
1218
1235
|
};
|
|
1219
1236
|
}
|
|
1237
|
+
function offeredViewIds(defaultViewId2, viewIds, multiTableViewIds, customViews) {
|
|
1238
|
+
const ids = [
|
|
1239
|
+
...defaultViewId2 ? [defaultViewId2] : [],
|
|
1240
|
+
...viewIds ?? [],
|
|
1241
|
+
...multiTableViewIds ?? [],
|
|
1242
|
+
...(customViews ?? []).map((view) => view.id)
|
|
1243
|
+
].map((id) => id.toLowerCase());
|
|
1244
|
+
return ids.length === 0 ? [EVERY_TABLE_VIEW_ID] : [...new Set(ids)];
|
|
1245
|
+
}
|
|
1246
|
+
function findCustomView(id, customViews) {
|
|
1247
|
+
if (!id) return void 0;
|
|
1248
|
+
return customViews?.find((view) => view.id.toLowerCase() === id.toLowerCase());
|
|
1249
|
+
}
|
|
1250
|
+
function selectedViewId(offered, picked) {
|
|
1251
|
+
return picked && offered.includes(picked.toLowerCase()) ? picked.toLowerCase() : offered[0];
|
|
1252
|
+
}
|
|
1253
|
+
function offersViews(offered) {
|
|
1254
|
+
return offered.some((id) => id !== EVERY_TABLE_VIEW_ID);
|
|
1255
|
+
}
|
|
1256
|
+
function withSavedViews(pageViews, savedViews, settings, control, shown, offersSavedViews) {
|
|
1257
|
+
if (!offersSavedViews) return [...pageViews];
|
|
1258
|
+
let all = [...new Set([...pageViews, ...savedViews].map((id) => id.toLowerCase()))];
|
|
1259
|
+
const userDefault = defaultViewId(settings, all, control);
|
|
1260
|
+
if (userDefault) all = [userDefault, ...all.filter((id) => id !== userDefault)];
|
|
1261
|
+
const offered = all.filter((id) => id === shown?.toLowerCase() || !isViewHidden(settings, id, control));
|
|
1262
|
+
return offered.length > 0 ? offered : all;
|
|
1263
|
+
}
|
|
1264
|
+
var LAYOUTS = ["day", "workWeek", "week", "month", "agenda"];
|
|
1265
|
+
function readSavedLayout(json) {
|
|
1266
|
+
if (!json?.trim()) return void 0;
|
|
1267
|
+
try {
|
|
1268
|
+
const layout = JSON.parse(json).layout;
|
|
1269
|
+
return LAYOUTS.find((x) => x === layout);
|
|
1270
|
+
} catch {
|
|
1271
|
+
return void 0;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
function writeSavedLayout(layout) {
|
|
1275
|
+
return JSON.stringify({ version: 1, layout });
|
|
1276
|
+
}
|
|
1220
1277
|
var APPOINTMENT_TABLE = "appointment";
|
|
1221
|
-
var EVERY_TABLE_VIEW_ID = "00000000-0000-0000-0000-000000000000";
|
|
1222
1278
|
var SERIES_TABLE2 = "recurringappointmentmaster";
|
|
1223
1279
|
var DEFAULT_CALENDAR_TABLES = [APPOINTMENT_TABLE, "task"];
|
|
1224
1280
|
var CALENDAR_COLUMNS = {
|
|
@@ -1284,10 +1340,10 @@ function drawnTimes(item, dateOnly, timeZone) {
|
|
|
1284
1340
|
return { start: zonedMidnight(first, timeZone), end: zonedMidnight(after, timeZone) };
|
|
1285
1341
|
}
|
|
1286
1342
|
function fromMultiTableItem(item, info, drawn) {
|
|
1287
|
-
const
|
|
1343
|
+
const dates = info?.definition?.calendar;
|
|
1288
1344
|
const changeable = new Set((info?.changeableColumns ?? []).map((x) => x.toLowerCase()));
|
|
1289
|
-
const movable = (Number(item.permissions ?? 0) & TableSecurityPermission.Write) !== 0 && !isClosed(item) && !!
|
|
1290
|
-
const resizable = movable && !!
|
|
1345
|
+
const movable = (Number(item.permissions ?? 0) & TableSecurityPermission.Write) !== 0 && !isClosed(item) && !!dates?.start && changeable.has(dates.start.toLowerCase());
|
|
1346
|
+
const resizable = movable && !!dates?.end && changeable.has(dates.end.toLowerCase());
|
|
1291
1347
|
const isAppointment = item.table === APPOINTMENT_TABLE;
|
|
1292
1348
|
const state = stateOf(item);
|
|
1293
1349
|
const location = valueOf2(item.record, "location");
|
|
@@ -1305,7 +1361,7 @@ function fromMultiTableItem(item, info, drawn) {
|
|
|
1305
1361
|
durationEditable: resizable ? null : false,
|
|
1306
1362
|
showAs: isAppointment ? showAsOf(typeof status === "number" ? status : null, state) : AppointmentShowAs.Busy,
|
|
1307
1363
|
canceled: state === 2,
|
|
1308
|
-
color: definition?.color ?? null,
|
|
1364
|
+
color: info?.definition?.color ?? null,
|
|
1309
1365
|
record: item.record ?? null
|
|
1310
1366
|
};
|
|
1311
1367
|
}
|
|
@@ -1313,86 +1369,23 @@ function stored(moment, dateOnly, timeZone) {
|
|
|
1313
1369
|
return dateOnly ? `${localDate(moment, timeZone)}T00:00:00.000Z` : moment.toISOString();
|
|
1314
1370
|
}
|
|
1315
1371
|
function moveRecord(change, item, info, dateOnly, timeZone) {
|
|
1316
|
-
const
|
|
1317
|
-
if (!
|
|
1372
|
+
const dates = info?.definition?.calendar;
|
|
1373
|
+
if (!dates?.start) return null;
|
|
1318
1374
|
const changeable = new Set((info?.changeableColumns ?? []).map((x) => x.toLowerCase()));
|
|
1319
|
-
const allDayColumn =
|
|
1375
|
+
const allDayColumn = dates.allDay && changeable.has(dates.allDay.toLowerCase()) ? dates.allDay : null;
|
|
1320
1376
|
if (change.allDay !== (item.isAllDay ?? false) && !allDayColumn) return null;
|
|
1321
1377
|
if (dateOnly && !change.allDay) return null;
|
|
1322
1378
|
const end = change.end ?? new Date(change.start.getTime() + (change.allDay ? DAY_MS2 : 30 * MINUTE_MS2));
|
|
1323
1379
|
const drawn = drawnTimes(item, dateOnly, timeZone);
|
|
1324
1380
|
const lengthChanged = end.getTime() - change.start.getTime() !== drawn.end.getTime() - drawn.start.getTime();
|
|
1325
1381
|
const properties = {
|
|
1326
|
-
[
|
|
1382
|
+
[dates.start]: { $type: 2, value: stored(change.start, dateOnly, timeZone) }
|
|
1327
1383
|
};
|
|
1328
|
-
if (
|
|
1329
|
-
properties[
|
|
1384
|
+
if (dates.end && (!item.hasNoEnd || lengthChanged))
|
|
1385
|
+
properties[dates.end] = { $type: 2, value: stored(end, dateOnly, timeZone) };
|
|
1330
1386
|
if (allDayColumn) properties[allDayColumn] = { $type: 0, value: change.allDay };
|
|
1331
1387
|
return { tableName: item.table, id: item.id, properties };
|
|
1332
1388
|
}
|
|
1333
|
-
function tablesOf(tables, registered, allowed, stored2, isStoredView) {
|
|
1334
|
-
let named;
|
|
1335
|
-
if (tables) named = tables.map((x) => x.table ?? "");
|
|
1336
|
-
else if (isStoredView) {
|
|
1337
|
-
if (!stored2) return null;
|
|
1338
|
-
named = [...stored2];
|
|
1339
|
-
} else named = registered.map((x) => x.table ?? "");
|
|
1340
|
-
const expanded = named.flatMap(
|
|
1341
|
-
(table) => table.toLowerCase() === "activitypointer" ? registered.filter((x) => x.isActivity).map((x) => x.table ?? "") : [table.toLowerCase()]
|
|
1342
|
-
);
|
|
1343
|
-
return [...new Set(expanded)].filter(
|
|
1344
|
-
(table) => registered.some((x) => x.table === table) && (!allowed || allowed.has(table))
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
function hiddenByDefault(viewId, shown, defaults) {
|
|
1348
|
-
if (viewId !== EVERY_TABLE_VIEW_ID || !shown.some((table) => defaults.has(table))) return [];
|
|
1349
|
-
return shown.filter((table) => !defaults.has(table));
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
// src/calendar-query.ts
|
|
1353
|
-
function offeredViewIds(defaultViewId2, viewIds, multiTableViewIds, customViews) {
|
|
1354
|
-
const ids = [
|
|
1355
|
-
...defaultViewId2 ? [defaultViewId2] : [],
|
|
1356
|
-
...viewIds ?? [],
|
|
1357
|
-
...multiTableViewIds ?? [],
|
|
1358
|
-
...(customViews ?? []).map((view) => view.id)
|
|
1359
|
-
].map((id) => id.toLowerCase());
|
|
1360
|
-
return ids.length === 0 ? [EVERY_TABLE_VIEW_ID] : [...new Set(ids)];
|
|
1361
|
-
}
|
|
1362
|
-
function findCustomView(id, customViews) {
|
|
1363
|
-
if (!id) return void 0;
|
|
1364
|
-
return customViews?.find((view) => view.id.toLowerCase() === id.toLowerCase());
|
|
1365
|
-
}
|
|
1366
|
-
function selectedViewId(offered, picked) {
|
|
1367
|
-
return picked && offered.includes(picked.toLowerCase()) ? picked.toLowerCase() : offered[0];
|
|
1368
|
-
}
|
|
1369
|
-
function offersViews(offered) {
|
|
1370
|
-
return offered.some((id) => id !== EVERY_TABLE_VIEW_ID);
|
|
1371
|
-
}
|
|
1372
|
-
function everyRow(table) {
|
|
1373
|
-
return `<fetch><entity name="${table}" /></fetch>`;
|
|
1374
|
-
}
|
|
1375
|
-
function withSavedViews(pageViews, savedViews, settings, control, shown, offersSavedViews) {
|
|
1376
|
-
if (!offersSavedViews) return [...pageViews];
|
|
1377
|
-
let all = [...new Set([...pageViews, ...savedViews].map((id) => id.toLowerCase()))];
|
|
1378
|
-
const userDefault = defaultViewId(settings, all, control);
|
|
1379
|
-
if (userDefault) all = [userDefault, ...all.filter((id) => id !== userDefault)];
|
|
1380
|
-
const offered = all.filter((id) => id === shown?.toLowerCase() || !isViewHidden(settings, id, control));
|
|
1381
|
-
return offered.length > 0 ? offered : all;
|
|
1382
|
-
}
|
|
1383
|
-
var LAYOUTS = ["day", "workWeek", "week", "month", "agenda"];
|
|
1384
|
-
function readSavedLayout(json) {
|
|
1385
|
-
if (!json?.trim()) return void 0;
|
|
1386
|
-
try {
|
|
1387
|
-
const layout = JSON.parse(json).layout;
|
|
1388
|
-
return LAYOUTS.find((x) => x === layout);
|
|
1389
|
-
} catch {
|
|
1390
|
-
return void 0;
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
function writeSavedLayout(layout) {
|
|
1394
|
-
return JSON.stringify({ version: 1, layout });
|
|
1395
|
-
}
|
|
1396
1389
|
|
|
1397
1390
|
// ../../node_modules/.pnpm/@fullcalendar+react@7.1.3_react-dom@19.2.5_react@19.2.5__react@19.2.5_temporal-polyfill@1.0.6/node_modules/@fullcalendar/react/skeleton.css
|
|
1398
1391
|
var skeleton_default = `
|
|
@@ -1919,8 +1912,6 @@ function ensureFullCalendarStyles(document2) {
|
|
|
1919
1912
|
ensureStyleSheet(document2, STYLE_ID2, `${skeleton_default}
|
|
1920
1913
|
${theme_default}`);
|
|
1921
1914
|
}
|
|
1922
|
-
|
|
1923
|
-
// src/persisted-calendar-state.ts
|
|
1924
1915
|
var DATE2 = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
1925
1916
|
var GUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1926
1917
|
function isDate(value) {
|
|
@@ -1958,21 +1949,10 @@ function encodePersistedCalendarState(state) {
|
|
|
1958
1949
|
return Object.keys(compact).length > 0 ? JSON.stringify(compact) : null;
|
|
1959
1950
|
}
|
|
1960
1951
|
function writePersistedCalendarState(queryParameterName, state) {
|
|
1961
|
-
if (!queryParameterName
|
|
1962
|
-
|
|
1963
|
-
const params = new URLSearchParams(window.location.search);
|
|
1964
|
-
if (params.get(queryParameterName) === encoded) return;
|
|
1965
|
-
if (encoded === null) params.delete(queryParameterName);
|
|
1966
|
-
else params.set(queryParameterName, encoded);
|
|
1967
|
-
const query = params.toString();
|
|
1968
|
-
window.history.replaceState(
|
|
1969
|
-
window.history.state,
|
|
1970
|
-
"",
|
|
1971
|
-
`${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`
|
|
1972
|
-
);
|
|
1952
|
+
if (!queryParameterName) return;
|
|
1953
|
+
replaceQueryParam(queryParameterName, encodePersistedCalendarState(state) ?? void 0);
|
|
1973
1954
|
}
|
|
1974
1955
|
var plugins = [formaTheme, dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin];
|
|
1975
|
-
var SEARCH_DEBOUNCE_MS = 300;
|
|
1976
1956
|
var layoutKeys = {
|
|
1977
1957
|
day: "layouts.day",
|
|
1978
1958
|
workWeek: "layouts.work-week",
|
|
@@ -1987,32 +1967,6 @@ var useStyles3 = makeStyles({
|
|
|
1987
1967
|
gap: tokens.spacingVerticalS,
|
|
1988
1968
|
minHeight: 0
|
|
1989
1969
|
},
|
|
1990
|
-
// Two groups: the views, navigation and title, then search and the rest at the end. On a narrow
|
|
1991
|
-
// screen the end group wraps below the first as a whole rather than squeezing the title.
|
|
1992
|
-
toolbar: {
|
|
1993
|
-
alignItems: "center",
|
|
1994
|
-
flexWrap: "wrap",
|
|
1995
|
-
justifyContent: "space-between",
|
|
1996
|
-
rowGap: tokens.spacingVerticalXS,
|
|
1997
|
-
columnGap: tokens.spacingHorizontalS,
|
|
1998
|
-
paddingInline: 0
|
|
1999
|
-
},
|
|
2000
|
-
toolbarStart: {
|
|
2001
|
-
display: "flex",
|
|
2002
|
-
alignItems: "center",
|
|
2003
|
-
gap: tokens.spacingHorizontalXS,
|
|
2004
|
-
flex: "1 1 auto",
|
|
2005
|
-
minWidth: 0
|
|
2006
|
-
},
|
|
2007
|
-
toolbarEnd: {
|
|
2008
|
-
display: "flex",
|
|
2009
|
-
flexWrap: "wrap",
|
|
2010
|
-
alignItems: "center",
|
|
2011
|
-
justifyContent: "flex-end",
|
|
2012
|
-
gap: tokens.spacingHorizontalXS,
|
|
2013
|
-
marginInlineStart: "auto",
|
|
2014
|
-
minWidth: 0
|
|
2015
|
-
},
|
|
2016
1970
|
// The period and the moves through it, kept together.
|
|
2017
1971
|
navigation: {
|
|
2018
1972
|
display: "flex",
|
|
@@ -2034,10 +1988,6 @@ var useStyles3 = makeStyles({
|
|
|
2034
1988
|
overflow: "hidden",
|
|
2035
1989
|
textOverflow: "ellipsis"
|
|
2036
1990
|
},
|
|
2037
|
-
// As wide as a grid's view picker.
|
|
2038
|
-
viewPicker: {
|
|
2039
|
-
minWidth: "220px"
|
|
2040
|
-
},
|
|
2041
1991
|
search: {
|
|
2042
1992
|
width: "220px",
|
|
2043
1993
|
maxWidth: "100%"
|
|
@@ -2107,6 +2057,8 @@ function Calendar({
|
|
|
2107
2057
|
defaultLayout = "week",
|
|
2108
2058
|
layouts,
|
|
2109
2059
|
editable = false,
|
|
2060
|
+
showRecordLinks = true,
|
|
2061
|
+
onNavigate,
|
|
2110
2062
|
regardingTables,
|
|
2111
2063
|
height = "600px",
|
|
2112
2064
|
onAppointmentClick,
|
|
@@ -2175,6 +2127,7 @@ function Calendar({
|
|
|
2175
2127
|
);
|
|
2176
2128
|
const viewId = selectedViewId(offered, shownViewId);
|
|
2177
2129
|
if (viewSettled) openedViewRef.current ??= viewId;
|
|
2130
|
+
const tableSet = useMultiTableTableSet({ use: MultiTableUses.Calendar, viewId, tables, defaultTables });
|
|
2178
2131
|
const openingLayoutRef = useRef(void 0);
|
|
2179
2132
|
if (openingLayoutRef.current === void 0 && viewSettled) {
|
|
2180
2133
|
const savedLayout = persisted.l ? void 0 : readSavedLayout(savedCalendarLayout(viewId));
|
|
@@ -2183,8 +2136,7 @@ function Calendar({
|
|
|
2183
2136
|
const initialLayout = openingLayoutRef.current ?? openingLayout(layoutsOffered, persisted.l, defaultLayout);
|
|
2184
2137
|
const viewOpeningLayout = (id) => openingLayout(layoutsOffered, readSavedLayout(savedCalendarLayout(id)), defaultLayout);
|
|
2185
2138
|
const showsSearch = !appointments && allowSearch;
|
|
2186
|
-
const [
|
|
2187
|
-
const [search, setSearch] = useState(searchText);
|
|
2139
|
+
const [search, setSearch] = useState(() => includeSearchInPersistedState ? persisted.q ?? "" : "");
|
|
2188
2140
|
const picksViews = !appointments && offered.length > 1;
|
|
2189
2141
|
const namesViews = picksViews || !appointments && saved.available;
|
|
2190
2142
|
const namedViewIds = saved.available ? [.../* @__PURE__ */ new Set([...offered, ...pageViews])] : offered;
|
|
@@ -2205,10 +2157,10 @@ function Calendar({
|
|
|
2205
2157
|
const multiTable = new Map(viewNames.multiTable);
|
|
2206
2158
|
const missing = multiTableIds.filter((x) => !multiTable.has(x));
|
|
2207
2159
|
if (missing.length > 0) {
|
|
2208
|
-
const registeredViews = (await registeredAsync().catch(() => null))?.views ?? [];
|
|
2160
|
+
const registeredViews = (await tableSet.registeredAsync().catch(() => null))?.views ?? [];
|
|
2209
2161
|
for (const id of missing) {
|
|
2210
2162
|
const known2 = registeredViews.find((view2) => view2.id?.toLowerCase() === id);
|
|
2211
|
-
multiTable.set(id, known2 ? known2.name ?? null : await storedViewName(id));
|
|
2163
|
+
multiTable.set(id, known2 ? known2.name ?? null : (await tableSet.storedViewName(id)).name);
|
|
2212
2164
|
}
|
|
2213
2165
|
}
|
|
2214
2166
|
if (current) setViewNames({ dataverse, multiTable });
|
|
@@ -2235,12 +2187,7 @@ function Calendar({
|
|
|
2235
2187
|
}
|
|
2236
2188
|
if (!viewNames.dataverse.has(id)) return null;
|
|
2237
2189
|
const metadata = viewNames.dataverse.get(id);
|
|
2238
|
-
|
|
2239
|
-
const key = `tables.${metadata.tableName}.views.${id}.label`;
|
|
2240
|
-
const localized = tAll(key);
|
|
2241
|
-
if (localized !== key) return localized;
|
|
2242
|
-
}
|
|
2243
|
-
return metadata?.displayName ?? metadata?.name ?? id;
|
|
2190
|
+
return metadata ? viewLabelOf({ ...metadata, id }, tAll) : id;
|
|
2244
2191
|
};
|
|
2245
2192
|
const showsSavedViewsMenu = allowSavedViews && !appointments && (saved.available || saved.needsSignIn);
|
|
2246
2193
|
const viewOptions = useMemo(() => {
|
|
@@ -2250,11 +2197,8 @@ function Calendar({
|
|
|
2250
2197
|
return label === null ? null : { id, label };
|
|
2251
2198
|
});
|
|
2252
2199
|
if (labeled.some((option) => option === null)) return [];
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
if (viewSort === ViewSort.NameDescending) options2.sort((a, b) => b.label.localeCompare(a.label, locale));
|
|
2256
|
-
return options2;
|
|
2257
|
-
}, [offered, customViewsKey, saved.views, multiSaved.views, viewNames, viewSort, tAll, locale, showsSavedViewsMenu]);
|
|
2200
|
+
return labeled;
|
|
2201
|
+
}, [offered, customViewsKey, saved.views, multiSaved.views, viewNames, tAll, showsSavedViewsMenu]);
|
|
2258
2202
|
const showsViewPicker = !appointments && viewOptions.length > (showsSavedViewsMenu ? 0 : 1);
|
|
2259
2203
|
useEffect(() => {
|
|
2260
2204
|
ensureFullCalendarStyles(document);
|
|
@@ -2289,7 +2233,7 @@ function Calendar({
|
|
|
2289
2233
|
useEffect(() => () => void (latestStart.current = -1), []);
|
|
2290
2234
|
const user = authState.status === "authenticated" ? authState.user?.userId : null;
|
|
2291
2235
|
const tablesKey = (tables ?? []).map((table) => table.trim().toLowerCase()).join(",");
|
|
2292
|
-
const allowedTables =
|
|
2236
|
+
const allowedTables = tableSet.allowed;
|
|
2293
2237
|
const mayCreateAppointments = () => {
|
|
2294
2238
|
let asked = mayCreate.current;
|
|
2295
2239
|
if (!asked || asked.user !== user) {
|
|
@@ -2349,33 +2293,9 @@ function Calendar({
|
|
|
2349
2293
|
const [refreshes, setRefreshes] = useState(0);
|
|
2350
2294
|
const latestLoad = useRef(null);
|
|
2351
2295
|
useEffect(() => () => latestLoad.current?.abort(), []);
|
|
2352
|
-
const
|
|
2353
|
-
const
|
|
2354
|
-
const
|
|
2355
|
-
let asked = registeredRef.current;
|
|
2356
|
-
if (!asked || asked.user !== user) {
|
|
2357
|
-
const answer = ppp.getMultiTableTablesAsync();
|
|
2358
|
-
asked = registeredRef.current = { user, answer };
|
|
2359
|
-
answer.then(
|
|
2360
|
-
(response) => registeredRef.current?.answer === answer && setRegistered(response),
|
|
2361
|
-
() => {
|
|
2362
|
-
if (registeredRef.current?.answer === answer) registeredRef.current = null;
|
|
2363
|
-
}
|
|
2364
|
-
);
|
|
2365
|
-
}
|
|
2366
|
-
return asked.answer;
|
|
2367
|
-
};
|
|
2368
|
-
const infoOf = (table) => registered?.tables?.find((x) => x.table === table);
|
|
2369
|
-
const storedViewName = async (id) => {
|
|
2370
|
-
try {
|
|
2371
|
-
const stored2 = await ppp.retrieveRecordAsync("ppp_multitableview", id, ["ppp_name"]);
|
|
2372
|
-
const name = stored2.properties?.["ppp_name"]?.value;
|
|
2373
|
-
return typeof name === "string" ? name : null;
|
|
2374
|
-
} catch {
|
|
2375
|
-
return null;
|
|
2376
|
-
}
|
|
2377
|
-
};
|
|
2378
|
-
const storedViewTables = useRef(/* @__PURE__ */ new Map());
|
|
2296
|
+
const registeredAsync = tableSet.registeredAsync;
|
|
2297
|
+
const infoOf = tableSet.infoOf;
|
|
2298
|
+
const tableLabel = tableSet.tableLabel;
|
|
2379
2299
|
const isStoredView = (id, response) => isMultiTableView(id) && !(response.views ?? []).some((view2) => view2.id?.toLowerCase() === id);
|
|
2380
2300
|
const viewTablesAsync = async (id) => {
|
|
2381
2301
|
if (id === EVERY_TABLE_VIEW_ID) return null;
|
|
@@ -2392,35 +2312,15 @@ function Calendar({
|
|
|
2392
2312
|
console.warn(`[Calendar] The view ${id} doesn't exist or is on a table the user may not read, so it shows nothing.`);
|
|
2393
2313
|
return [];
|
|
2394
2314
|
};
|
|
2315
|
+
const knownTablesOf = (id, viewTables, response) => tableSet.tablesOf(viewTables, isStoredView(id, response) ? id : null);
|
|
2395
2316
|
const defaultsKey = defaultTables.map((table) => table.trim().toLowerCase()).join(",");
|
|
2396
|
-
const
|
|
2397
|
-
const
|
|
2398
|
-
const [hiddenChoice, setHiddenChoice] = useState(null);
|
|
2399
|
-
const hiddenIn = (id, of) => hiddenChoice && hiddenChoice.viewId === id ? hiddenChoice.tables : hiddenByDefault(id, of, new Set(defaultsKey.split(",").filter(Boolean)));
|
|
2400
|
-
const hidden = hiddenIn(viewId, known);
|
|
2401
|
-
const shownIn = (id, of, byView = false) => {
|
|
2402
|
-
const off = byView ? hiddenByDefault(id, of, new Set(defaultsKey.split(",").filter(Boolean))) : hiddenIn(id, of);
|
|
2403
|
-
return of.length < 2 ? [...of] : of.filter((table) => !off.includes(table));
|
|
2404
|
-
};
|
|
2405
|
-
const shownTables = shownIn(viewId, known);
|
|
2406
|
-
const kinds = known.length > 1 ? known : [];
|
|
2407
|
-
const hiddenAtOpen = hiddenByDefault(viewId, known, new Set(defaultsKey.split(",").filter(Boolean)));
|
|
2408
|
-
const tablesChanged = kinds.some((table) => hidden.includes(table) !== hiddenAtOpen.includes(table));
|
|
2409
|
-
const showTable = (table, shown) => {
|
|
2410
|
-
const next = shown ? hidden.filter((x) => x !== table) : [.../* @__PURE__ */ new Set([...hidden, table])];
|
|
2411
|
-
setHiddenChoice({ viewId, tables: next });
|
|
2412
|
-
};
|
|
2413
|
-
useLocalization(known.map((table) => `tables.${table}`));
|
|
2414
|
-
const tableLabel = (table) => {
|
|
2415
|
-
const key = `tables.${table}.label`;
|
|
2416
|
-
const label = tAll(key);
|
|
2417
|
-
return label !== key ? label : table;
|
|
2418
|
-
};
|
|
2317
|
+
const known = tableSet.known;
|
|
2318
|
+
const shownTables = tableSet.shown;
|
|
2419
2319
|
const rows = useRef(/* @__PURE__ */ new Map());
|
|
2420
2320
|
const dateOnly = useRef(/* @__PURE__ */ new Map());
|
|
2421
2321
|
const learnDateOnly = async (tables2, response) => {
|
|
2422
2322
|
for (const table of [...new Set(tables2)].filter((x) => !dateOnly.current.has(x))) {
|
|
2423
|
-
const start = response.tables?.find((x) => x.table === table)?.definition?.start;
|
|
2323
|
+
const start = response.tables?.find((x) => x.table === table)?.definition?.calendar?.start;
|
|
2424
2324
|
try {
|
|
2425
2325
|
const metadata = await tableMetadataCache.getAsync(table);
|
|
2426
2326
|
const column = metadata?.columns?.find((x) => x.columnName === start);
|
|
@@ -2431,22 +2331,12 @@ function Calendar({
|
|
|
2431
2331
|
}
|
|
2432
2332
|
};
|
|
2433
2333
|
const [failures, setFailures] = useState([]);
|
|
2434
|
-
const showsFilterButton = !appointments && allowFiltering && !(registered && isStoredView(viewId, registered));
|
|
2435
|
-
const
|
|
2436
|
-
useEffect(() => {
|
|
2437
|
-
setUserFilter((current) => current && current.viewId !== viewId ? null : current);
|
|
2438
|
-
setHiddenChoice((current) => current && current.viewId !== viewId ? null : current);
|
|
2439
|
-
}, [viewId]);
|
|
2440
|
-
const filtered = userFilter && userFilter.viewId === viewId ? userFilter : null;
|
|
2441
|
-
const [filterDialog, setFilterDialog] = useState(null);
|
|
2334
|
+
const showsFilterButton = !appointments && allowFiltering && !(tableSet.registered && isStoredView(viewId, tableSet.registered));
|
|
2335
|
+
const filtered = tableSet.filter;
|
|
2442
2336
|
const filterTablesAsync = async (id) => {
|
|
2443
|
-
|
|
2444
|
-
const tablesShown = await viewTablesAsync(id) ?? (id === EVERY_TABLE_VIEW_ID ? (tablesOf(null
|
|
2445
|
-
return
|
|
2446
|
-
};
|
|
2447
|
-
const isShownTable = (table, named, shownNow, response) => {
|
|
2448
|
-
const lower = (x) => x.toLowerCase();
|
|
2449
|
-
return lower(table) === "activitypointer" ? shownNow.some((x) => response.tables?.find((info) => info.table === x)?.isActivity && !named.map(lower).includes(lower(x))) : shownNow.map(lower).includes(lower(table));
|
|
2337
|
+
await registeredAsync();
|
|
2338
|
+
const tablesShown = await viewTablesAsync(id) ?? (id === EVERY_TABLE_VIEW_ID ? (tableSet.tablesOf(null) ?? []).map((table) => ({ table })) : []);
|
|
2339
|
+
return tableSet.filterQueries(tablesShown);
|
|
2450
2340
|
};
|
|
2451
2341
|
const openFilter = async () => {
|
|
2452
2342
|
const id = viewId;
|
|
@@ -2454,36 +2344,14 @@ function Calendar({
|
|
|
2454
2344
|
try {
|
|
2455
2345
|
const response = await registeredAsync();
|
|
2456
2346
|
const tablesShown = await filterTablesAsync(id);
|
|
2457
|
-
const knownNow =
|
|
2458
|
-
|
|
2459
|
-
response.tables ?? [],
|
|
2460
|
-
allowedTables,
|
|
2461
|
-
storedViewTables.current.get(id),
|
|
2462
|
-
isStoredView(id, response)
|
|
2463
|
-
) ?? [];
|
|
2464
|
-
const shownNow = shownIn(id, knownNow);
|
|
2465
|
-
const named = tablesShown.map((x) => x.table.table ?? "");
|
|
2466
|
-
const tabs = multiTableFilterTabs(
|
|
2467
|
-
tablesShown,
|
|
2468
|
-
(table) => isShownTable(table, named, shownNow, response),
|
|
2469
|
-
tableLabel,
|
|
2470
|
-
filtered?.criteria
|
|
2471
|
-
);
|
|
2472
|
-
const shownByView = shownIn(id, knownNow, true);
|
|
2473
|
-
const viewTabs = multiTableFilterTabs(tablesShown, (table) => isShownTable(table, named, shownByView, response), tableLabel);
|
|
2474
|
-
if (tabs.length > 0 && id === viewId) setFilterDialog({ viewId: id, tables: tablesShown, tabs, viewTabs });
|
|
2347
|
+
const knownNow = knownTablesOf(id, await viewTablesAsync(id) ?? null, response) ?? [];
|
|
2348
|
+
tableSet.openFilter(id, tablesShown, knownNow, tableLabel);
|
|
2475
2349
|
} catch (error) {
|
|
2476
2350
|
console.warn("[Calendar] The filters of the view shown could not be read.", error);
|
|
2477
2351
|
}
|
|
2478
2352
|
};
|
|
2479
2353
|
const applyFilter = (criteria, restoreView) => {
|
|
2480
|
-
|
|
2481
|
-
setFilterDialog(null);
|
|
2482
|
-
if (!dialog2 || dialog2.viewId !== viewId) return;
|
|
2483
|
-
const filter = applyMultiTableFilter(dialog2.tables, restoreView ? dialog2.viewTabs : dialog2.tabs, criteria);
|
|
2484
|
-
setUserFilter(filter ? { viewId, tables: filter.tables, criteria: filter.criteria } : null);
|
|
2485
|
-
if (!restoreView) return;
|
|
2486
|
-
setHiddenChoice(null);
|
|
2354
|
+
if (!tableSet.applyFilter(criteria, restoreView) || !restoreView) return;
|
|
2487
2355
|
const layout = viewOpeningLayout(viewId);
|
|
2488
2356
|
if (layout !== currentLayout && layoutsOffered.includes(layout)) controller.changeView(toFullCalendarView(layout));
|
|
2489
2357
|
};
|
|
@@ -2496,7 +2364,7 @@ function Calendar({
|
|
|
2496
2364
|
customViewsKey,
|
|
2497
2365
|
filtered?.tables ?? null,
|
|
2498
2366
|
searched,
|
|
2499
|
-
hiddenChoice,
|
|
2367
|
+
tableSet.hiddenChoice,
|
|
2500
2368
|
tablesKey,
|
|
2501
2369
|
defaultsKey,
|
|
2502
2370
|
matchParties ?? null,
|
|
@@ -2526,14 +2394,10 @@ function Calendar({
|
|
|
2526
2394
|
openingViewRef.current = offered[0];
|
|
2527
2395
|
if (viewSettled && previous !== void 0 && previous !== offered[0]) persist();
|
|
2528
2396
|
}, [offered[0]]);
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
persist({ search: searchText });
|
|
2534
|
-
}, SEARCH_DEBOUNCE_MS);
|
|
2535
|
-
return () => clearTimeout(timer);
|
|
2536
|
-
}, [searchText]);
|
|
2397
|
+
const searchFor = (text) => {
|
|
2398
|
+
setSearch(text);
|
|
2399
|
+
persist({ search: text });
|
|
2400
|
+
};
|
|
2537
2401
|
const events = useMemo(() => {
|
|
2538
2402
|
if (appointments) return appointments.map(toEventInput);
|
|
2539
2403
|
return async (info) => {
|
|
@@ -2546,8 +2410,8 @@ function Calendar({
|
|
|
2546
2410
|
const response = await registeredAsync();
|
|
2547
2411
|
const viewTables = await viewTablesAsync(id);
|
|
2548
2412
|
const stored2 = isStoredView(id, response);
|
|
2549
|
-
let knownNow =
|
|
2550
|
-
if (latestLoad.current === load && knownNow)
|
|
2413
|
+
let knownNow = knownTablesOf(id, viewTables, response);
|
|
2414
|
+
if (latestLoad.current === load && knownNow) tableSet.setKnown(id, knownNow);
|
|
2551
2415
|
if (knownNow?.length === 0) {
|
|
2552
2416
|
if (latestLoad.current === load) {
|
|
2553
2417
|
setFailed(false);
|
|
@@ -2563,7 +2427,7 @@ function Calendar({
|
|
|
2563
2427
|
viewId: filtered || !isMultiTableView(id) ? null : id,
|
|
2564
2428
|
tables: filtered ? [...filtered.tables] : viewTables && viewTables.length > 0 ? [...viewTables] : null,
|
|
2565
2429
|
// A view whose tables aren't known yet is read as the calendar allows.
|
|
2566
|
-
includeTables: knownNow ? shownIn(id, knownNow) : allowedTables ? [...allowedTables] : null,
|
|
2430
|
+
includeTables: knownNow ? tableSet.shownIn(id, knownNow) : allowedTables ? [...allowedTables] : null,
|
|
2567
2431
|
regarding: regarding ? { tableName: regarding.tableName, id: regarding.id } : null,
|
|
2568
2432
|
matchParties: matchParties ?? null,
|
|
2569
2433
|
series: series ?? null,
|
|
@@ -2572,9 +2436,8 @@ function Calendar({
|
|
|
2572
2436
|
};
|
|
2573
2437
|
const range = await ppp.loadMultiTableRangeAsync(request, load.signal);
|
|
2574
2438
|
if (!knownNow && stored2) {
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
if (latestLoad.current === load) setKnownTables({ viewId: id, tables: knownNow });
|
|
2439
|
+
knownNow = tableSet.learnTables(id, range.tables ?? []);
|
|
2440
|
+
if (latestLoad.current === load) tableSet.setKnown(id, knownNow);
|
|
2578
2441
|
}
|
|
2579
2442
|
const items = range.items ?? [];
|
|
2580
2443
|
await learnDateOnly(items.map((item) => item.table ?? ""), response);
|
|
@@ -2691,13 +2554,10 @@ function Calendar({
|
|
|
2691
2554
|
const shownSaved = findSaved(viewId);
|
|
2692
2555
|
const shownSavedMulti = findSavedMulti(viewId);
|
|
2693
2556
|
const showsAppointmentsAlone = shownTables.length === 1 && shownTables[0] === APPOINTMENT_TABLE;
|
|
2694
|
-
const canSaveView = shownTables.length > 0 && !(registered && isStoredView(viewId, registered));
|
|
2695
|
-
const viewChanged = !!filtered || tablesChanged || currentLayout !== viewOpeningLayout(viewId);
|
|
2557
|
+
const canSaveView = shownTables.length > 0 && !(tableSet.registered && isStoredView(viewId, tableSet.registered));
|
|
2558
|
+
const viewChanged = !!filtered || tableSet.tablesChanged || currentLayout !== viewOpeningLayout(viewId);
|
|
2696
2559
|
const savedViewChanged = (!!shownSaved || !!shownSavedMulti) && canSaveView && viewChanged;
|
|
2697
2560
|
const isUserDefault = !!viewId && defaultViewId(saved.settings, offered, savedViewsControl) === viewId;
|
|
2698
|
-
const [savingView, setSavingView] = useState(false);
|
|
2699
|
-
const [nameDialog, setNameDialog] = useState(null);
|
|
2700
|
-
const [manageViewsOpen, setManageViewsOpen] = useState(false);
|
|
2701
2561
|
const currentQuery = async () => {
|
|
2702
2562
|
if (!showsAppointmentsAlone || !viewId) return void 0;
|
|
2703
2563
|
const own = filtered?.tables.find((x) => x.table === APPOINTMENT_TABLE);
|
|
@@ -2710,261 +2570,195 @@ function Calendar({
|
|
|
2710
2570
|
const tablesNow = filtered ? [...filtered.tables] : (await filterTablesAsync(viewId)).map((x) => x.table);
|
|
2711
2571
|
return shownViewTables(tablesNow, known, shownTables, (table) => !!response.tables?.find((info) => info.table === table)?.isActivity);
|
|
2712
2572
|
};
|
|
2713
|
-
const runSavedViewChange = async (change) => {
|
|
2714
|
-
if (savingView) return;
|
|
2715
|
-
setSavingView(true);
|
|
2716
|
-
try {
|
|
2717
|
-
await change();
|
|
2718
|
-
} catch (error) {
|
|
2719
|
-
console.warn("[Calendar] A change to the user\u2019s saved views failed.", error);
|
|
2720
|
-
await dialog.showErrorAsync(tAll("app.components.grid.saved-views-error"));
|
|
2721
|
-
} finally {
|
|
2722
|
-
setSavingView(false);
|
|
2723
|
-
}
|
|
2724
|
-
};
|
|
2725
|
-
const signedIn = async (action) => {
|
|
2726
|
-
if (!saved.needsSignIn) {
|
|
2727
|
-
await action();
|
|
2728
|
-
return;
|
|
2729
|
-
}
|
|
2730
|
-
const result = await dialog.showConfirmationAsync(tAll("app.components.grid.saved-views-sign-in-message"), {
|
|
2731
|
-
title: tAll("app.components.grid.saved-views-sign-in-title"),
|
|
2732
|
-
primaryText: tAll("app.buttons.login.label"),
|
|
2733
|
-
secondaryText: tAll("app.buttons.cancel.label")
|
|
2734
|
-
});
|
|
2735
|
-
if (result.canceled) return;
|
|
2736
|
-
const returnUrl = window.location.pathname + window.location.search + window.location.hash;
|
|
2737
|
-
window.location.assign(`${signInUrl}${signInUrl.includes("?") ? "&" : "?"}ReturnUrl=${encodeURIComponent(returnUrl)}`);
|
|
2738
|
-
};
|
|
2739
2573
|
const showSavedView = (id) => {
|
|
2740
|
-
|
|
2741
|
-
setHiddenChoice(null);
|
|
2574
|
+
tableSet.reset();
|
|
2742
2575
|
setPickedViewId(id);
|
|
2743
2576
|
persist({ viewId: id });
|
|
2744
2577
|
};
|
|
2745
|
-
const saveView = () => runSavedViewChange(async () => {
|
|
2746
|
-
if (shownSavedMulti) {
|
|
2747
|
-
const tables2 = await currentTables();
|
|
2748
|
-
if (tables2.length === 0) return;
|
|
2749
|
-
await multiSaved.update(shownSavedMulti.id, { tables: tables2, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2750
|
-
} else {
|
|
2751
|
-
if (!shownSaved) return;
|
|
2752
|
-
const fetchXml = await currentQuery();
|
|
2753
|
-
if (!fetchXml) return;
|
|
2754
|
-
await saved.update(shownSaved.id, { fetchXml, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2755
|
-
}
|
|
2756
|
-
setUserFilter(null);
|
|
2757
|
-
setHiddenChoice(null);
|
|
2758
|
-
});
|
|
2759
|
-
const saveViewAs = (name) => runSavedViewChange(async () => {
|
|
2760
|
-
const fetchXml = showsAppointmentsAlone ? await currentQuery() : void 0;
|
|
2761
|
-
if (fetchXml) {
|
|
2762
|
-
const view3 = await saved.create(name, fetchXml, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2763
|
-
showSavedView(view3.id.toLowerCase());
|
|
2764
|
-
return;
|
|
2765
|
-
}
|
|
2766
|
-
const tables2 = await currentTables();
|
|
2767
|
-
if (tables2.length === 0) return;
|
|
2768
|
-
const view2 = await multiSaved.create(name, tables2, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2769
|
-
showSavedView(view2.id.toLowerCase());
|
|
2770
|
-
});
|
|
2771
|
-
const cloneView = (id, name) => runSavedViewChange(async () => {
|
|
2772
|
-
const own = findSaved(id);
|
|
2773
|
-
const custom = findCustomView(id, customViewDefinitions)?.tables;
|
|
2774
|
-
const only = custom?.length === 1 && custom[0].table === APPOINTMENT_TABLE && (custom[0].viewType ?? MultiTableViewType.FetchXml) === MultiTableViewType.FetchXml ? custom[0].fetchXml ?? everyRow(APPOINTMENT_TABLE) : void 0;
|
|
2775
|
-
const ownMulti = findSavedMulti(id);
|
|
2776
|
-
const dataverse = own || only || ownMulti || custom ? void 0 : await viewMetadataCache.getAsync(id);
|
|
2777
|
-
const fetchXml = own?.definition.fetchXml ?? only ?? (dataverse?.tableName.toLowerCase() === APPOINTMENT_TABLE ? dataverse.fetchXml : void 0);
|
|
2778
|
-
if (fetchXml) {
|
|
2779
|
-
await saved.create(name, fetchXml, { gridLayout: own?.gridLayout, calendarLayout: own?.calendarLayout });
|
|
2780
|
-
return;
|
|
2781
|
-
}
|
|
2782
|
-
const tables2 = ownMulti?.tables ?? await viewTablesAsync(id) ?? (id === EVERY_TABLE_VIEW_ID ? known.map((table) => ({ table })) : null);
|
|
2783
|
-
if (!tables2 || tables2.length === 0) return;
|
|
2784
|
-
await multiSaved.create(name, tables2, { calendarLayout: ownMulti?.calendarLayout });
|
|
2785
|
-
});
|
|
2786
|
-
const renameView = (id, name) => runSavedViewChange(async () => void (findSavedMulti(id) ? await multiSaved.update(id, { name }) : await saved.update(id, { name })));
|
|
2787
|
-
const deleteView = async (id) => {
|
|
2788
|
-
const result = await dialog.showConfirmationAsync(
|
|
2789
|
-
tAll("app.components.grid.saved-views-delete-message", [findSaved(id)?.name ?? findSavedMulti(id)?.name ?? ""]),
|
|
2790
|
-
{
|
|
2791
|
-
title: tAll("app.components.grid.saved-views-delete-title"),
|
|
2792
|
-
primaryText: tAll("app.components.grid.saved-views-delete"),
|
|
2793
|
-
secondaryText: tAll("app.buttons.cancel.label")
|
|
2794
|
-
}
|
|
2795
|
-
);
|
|
2796
|
-
if (result.canceled) return;
|
|
2797
|
-
await runSavedViewChange(async () => {
|
|
2798
|
-
if (findSavedMulti(id)) {
|
|
2799
|
-
await multiSaved.remove(id);
|
|
2800
|
-
await saved.reloadSettings();
|
|
2801
|
-
} else {
|
|
2802
|
-
await saved.remove(id);
|
|
2803
|
-
}
|
|
2804
|
-
if (id.toLowerCase() === viewId) setUserFilter(null);
|
|
2805
|
-
});
|
|
2806
|
-
};
|
|
2807
|
-
const setDefault = (id, isDefault) => runSavedViewChange(() => saved.setDefault(id, isDefault, viewLabel(id)));
|
|
2808
|
-
const setHidden = (id, isHidden) => runSavedViewChange(() => saved.setHidden(id, isHidden, viewLabel(id)));
|
|
2809
2578
|
function viewLabel(id) {
|
|
2810
2579
|
return labelOf(id.toLowerCase()) ?? findSaved(id)?.name ?? findSavedMulti(id)?.name ?? id;
|
|
2811
2580
|
}
|
|
2812
|
-
const
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
id,
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
{
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
onOptionSelect: (_, data) => pickView(data.optionValue),
|
|
2843
|
-
children: viewOptions.map((option) => /* @__PURE__ */ jsx(Option, { value: option.id, text: option.label, children: option.label }, option.id))
|
|
2581
|
+
const session = useSavedViewSession({
|
|
2582
|
+
saved,
|
|
2583
|
+
signInUrl,
|
|
2584
|
+
operations: {
|
|
2585
|
+
shownViewId: viewId,
|
|
2586
|
+
savedViewName: (id) => findSaved(id)?.name ?? findSavedMulti(id)?.name,
|
|
2587
|
+
managedViewName: viewLabel,
|
|
2588
|
+
// Every view for the Manage views panel, the hidden ones among them.
|
|
2589
|
+
managedViews: () => {
|
|
2590
|
+
const all = [.../* @__PURE__ */ new Set([...pageViews, ...savedIds.map((x) => x.toLowerCase())])];
|
|
2591
|
+
const userDefault = defaultViewId(saved.settings, all, savedViewsControl);
|
|
2592
|
+
return all.map((id) => ({
|
|
2593
|
+
id,
|
|
2594
|
+
name: viewLabel(id),
|
|
2595
|
+
isSaved: !!findSaved(id) || !!findSavedMulti(id),
|
|
2596
|
+
isDefault: id === userDefault,
|
|
2597
|
+
isHidden: isViewHidden(saved.settings, id, savedViewsControl),
|
|
2598
|
+
isShown: id === viewId
|
|
2599
|
+
}));
|
|
2600
|
+
},
|
|
2601
|
+
save: async () => {
|
|
2602
|
+
if (shownSavedMulti) {
|
|
2603
|
+
const tables2 = await currentTables();
|
|
2604
|
+
if (tables2.length === 0) return;
|
|
2605
|
+
await multiSaved.update(shownSavedMulti.id, { tables: tables2, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2606
|
+
} else {
|
|
2607
|
+
if (!shownSaved) return;
|
|
2608
|
+
const fetchXml = await currentQuery();
|
|
2609
|
+
if (!fetchXml) return;
|
|
2610
|
+
await saved.update(shownSaved.id, { fetchXml, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2844
2611
|
}
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2612
|
+
tableSet.reset();
|
|
2613
|
+
},
|
|
2614
|
+
saveAs: async (name) => {
|
|
2615
|
+
const fetchXml = showsAppointmentsAlone ? await currentQuery() : void 0;
|
|
2616
|
+
if (fetchXml) {
|
|
2617
|
+
const view3 = await saved.create(name, fetchXml, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2618
|
+
showSavedView(view3.id.toLowerCase());
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
const tables2 = await currentTables();
|
|
2622
|
+
if (tables2.length === 0) return;
|
|
2623
|
+
const view2 = await multiSaved.create(name, tables2, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2624
|
+
showSavedView(view2.id.toLowerCase());
|
|
2625
|
+
},
|
|
2626
|
+
clone: async (id, name) => {
|
|
2627
|
+
const own = findSaved(id);
|
|
2628
|
+
const custom = findCustomView(id, customViewDefinitions)?.tables;
|
|
2629
|
+
const only = custom?.length === 1 && custom[0].table === APPOINTMENT_TABLE && (custom[0].viewType ?? MultiTableViewType.FetchXml) === MultiTableViewType.FetchXml ? custom[0].fetchXml ?? everyRow(APPOINTMENT_TABLE) : void 0;
|
|
2630
|
+
const ownMulti = findSavedMulti(id);
|
|
2631
|
+
const dataverse = own || only || ownMulti || custom ? void 0 : await viewMetadataCache.getAsync(id);
|
|
2632
|
+
const fetchXml = own?.definition.fetchXml ?? only ?? (dataverse?.tableName.toLowerCase() === APPOINTMENT_TABLE ? dataverse.fetchXml : void 0);
|
|
2633
|
+
if (fetchXml) {
|
|
2634
|
+
await saved.create(name, fetchXml, { gridLayout: own?.gridLayout, calendarLayout: own?.calendarLayout });
|
|
2635
|
+
return;
|
|
2636
|
+
}
|
|
2637
|
+
const tables2 = ownMulti?.tables ?? await viewTablesAsync(id) ?? (id === EVERY_TABLE_VIEW_ID ? known.map((table) => ({ table })) : null);
|
|
2638
|
+
if (!tables2 || tables2.length === 0) return;
|
|
2639
|
+
await multiSaved.create(name, tables2, { calendarLayout: ownMulti?.calendarLayout });
|
|
2640
|
+
},
|
|
2641
|
+
rename: async (id, name) => void (findSavedMulti(id) ? await multiSaved.update(id, { name }) : await saved.update(id, { name })),
|
|
2642
|
+
remove: async (id) => {
|
|
2643
|
+
if (findSavedMulti(id)) {
|
|
2644
|
+
await multiSaved.remove(id);
|
|
2645
|
+
await saved.reloadSettings();
|
|
2646
|
+
} else {
|
|
2647
|
+
await saved.remove(id);
|
|
2648
|
+
}
|
|
2649
|
+
if (id.toLowerCase() === viewId) tableSet.clearFilter();
|
|
2650
|
+
},
|
|
2651
|
+
openView: (id) => pickView(id)
|
|
2652
|
+
}
|
|
2653
|
+
});
|
|
2654
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.root, style: { height }, children: [
|
|
2655
|
+
/* @__PURE__ */ jsxs(
|
|
2656
|
+
ViewToolbar,
|
|
2657
|
+
{
|
|
2658
|
+
className: "ppp-calendar-toolbar",
|
|
2659
|
+
ariaLabel: t("toolbar"),
|
|
2660
|
+
start: showsViewPicker && /* @__PURE__ */ jsx(
|
|
2661
|
+
ViewPicker,
|
|
2662
|
+
{
|
|
2663
|
+
className: "ppp-calendar-view-picker",
|
|
2664
|
+
options: viewOptions,
|
|
2665
|
+
sort: viewSort,
|
|
2666
|
+
value: viewId,
|
|
2667
|
+
onChange: pickView,
|
|
2668
|
+
isUserView: (id) => saved.available && (!!findSaved(id) || !!findSavedMulti(id))
|
|
2669
|
+
}
|
|
2670
|
+
),
|
|
2671
|
+
children: [
|
|
2672
|
+
/* @__PURE__ */ jsxs("div", { className: mergeClasses("ppp-calendar-navigation", styles.navigation), children: [
|
|
2673
|
+
/* @__PURE__ */ jsx(
|
|
2674
|
+
ToolbarButton,
|
|
2675
|
+
{
|
|
2676
|
+
appearance: "subtle",
|
|
2677
|
+
disabled: buttons?.today?.isDisabled ?? false,
|
|
2678
|
+
onClick: () => controller.today(),
|
|
2679
|
+
children: t("today")
|
|
2680
|
+
}
|
|
2681
|
+
),
|
|
2682
|
+
/* @__PURE__ */ jsx(
|
|
2683
|
+
ToolbarButton,
|
|
2684
|
+
{
|
|
2685
|
+
appearance: "subtle",
|
|
2686
|
+
icon: direction === "rtl" ? /* @__PURE__ */ jsx(ChevronRightRegular, {}) : /* @__PURE__ */ jsx(ChevronLeftRegular, {}),
|
|
2687
|
+
"aria-label": t("previous"),
|
|
2688
|
+
onClick: () => controller.prev()
|
|
2689
|
+
}
|
|
2690
|
+
),
|
|
2691
|
+
/* @__PURE__ */ jsx(
|
|
2692
|
+
ToolbarButton,
|
|
2693
|
+
{
|
|
2694
|
+
appearance: "subtle",
|
|
2695
|
+
icon: direction === "rtl" ? /* @__PURE__ */ jsx(ChevronLeftRegular, {}) : /* @__PURE__ */ jsx(ChevronRightRegular, {}),
|
|
2696
|
+
"aria-label": t("next"),
|
|
2697
|
+
onClick: () => controller.next()
|
|
2698
|
+
}
|
|
2699
|
+
),
|
|
2700
|
+
/* @__PURE__ */ jsx(Text, { className: styles.title, as: "h2", "aria-live": "polite", children: view?.title })
|
|
2701
|
+
] }),
|
|
2702
|
+
children !== void 0 && /* @__PURE__ */ jsx(CalendarContext.Provider, { value: calendarContext, children }),
|
|
2703
|
+
layoutsOffered.length > 1 && /* @__PURE__ */ jsxs(Menu, { checkedValues: { layout: [currentLayout] }, onCheckedValueChange: onLayoutChecked, children: [
|
|
2704
|
+
/* @__PURE__ */ jsx(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(MenuButton, { className: "ppp-calendar-layout", appearance: "subtle", children: t(layoutKeys[currentLayout]) }) }),
|
|
2705
|
+
/* @__PURE__ */ jsx(MenuPopover, { children: /* @__PURE__ */ jsx(MenuList, { children: layoutsOffered.map((layout) => /* @__PURE__ */ jsx(MenuItemRadio, { name: "layout", value: layout, children: t(layoutKeys[layout]) }, layout)) }) })
|
|
2706
|
+
] }),
|
|
2707
|
+
showsSearch && /* @__PURE__ */ jsx(
|
|
2708
|
+
ViewSearchBox,
|
|
2850
2709
|
{
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2710
|
+
className: mergeClasses("ppp-calendar-search", styles.search),
|
|
2711
|
+
placeholder: t("search-placeholder"),
|
|
2712
|
+
value: search,
|
|
2713
|
+
onChange: searchFor
|
|
2855
2714
|
}
|
|
2856
2715
|
),
|
|
2857
2716
|
/* @__PURE__ */ jsx(
|
|
2858
|
-
|
|
2717
|
+
ViewFilterMenu,
|
|
2859
2718
|
{
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2719
|
+
changed: viewChanged,
|
|
2720
|
+
onEditFilters: showsFilterButton ? () => void openFilter() : void 0,
|
|
2721
|
+
tables: appointments ? void 0 : tableSet.menuTables(tableLabel),
|
|
2722
|
+
onTableShownChange: tableSet.showTable,
|
|
2723
|
+
savedViews: session.menu({
|
|
2724
|
+
canSave: savedViewChanged,
|
|
2725
|
+
canSaveAs: canSaveView && viewChanged,
|
|
2726
|
+
canSetDefault: !!viewId && !isUserDefault
|
|
2727
|
+
})
|
|
2864
2728
|
}
|
|
2865
2729
|
),
|
|
2866
|
-
/* @__PURE__ */ jsx(
|
|
2867
|
-
|
|
2730
|
+
!appointments && /* @__PURE__ */ jsx(
|
|
2731
|
+
ViewRefreshButton,
|
|
2868
2732
|
{
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
onClick: () => controller.next()
|
|
2733
|
+
className: "ppp-calendar-refresh",
|
|
2734
|
+
disabled: loading,
|
|
2735
|
+
onClick: () => setRefreshes((count) => count + 1)
|
|
2873
2736
|
}
|
|
2874
|
-
)
|
|
2875
|
-
|
|
2876
|
-
] }),
|
|
2877
|
-
children !== void 0 && /* @__PURE__ */ jsx(CalendarContext.Provider, { value: calendarContext, children }),
|
|
2878
|
-
layoutsOffered.length > 1 && /* @__PURE__ */ jsxs(Menu, { checkedValues: { layout: [currentLayout] }, onCheckedValueChange: onLayoutChecked, children: [
|
|
2879
|
-
/* @__PURE__ */ jsx(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(MenuButton, { className: "ppp-calendar-layout", appearance: "subtle", children: t(layoutKeys[currentLayout]) }) }),
|
|
2880
|
-
/* @__PURE__ */ jsx(MenuPopover, { children: /* @__PURE__ */ jsx(MenuList, { children: layoutsOffered.map((layout) => /* @__PURE__ */ jsx(MenuItemRadio, { name: "layout", value: layout, children: t(layoutKeys[layout]) }, layout)) }) })
|
|
2881
|
-
] }),
|
|
2882
|
-
showsSearch && /* @__PURE__ */ jsx(
|
|
2883
|
-
SearchBox,
|
|
2884
|
-
{
|
|
2885
|
-
className: mergeClasses("ppp-calendar-search", styles.search),
|
|
2886
|
-
placeholder: t("search-placeholder"),
|
|
2887
|
-
"aria-label": t("search-placeholder"),
|
|
2888
|
-
value: searchText,
|
|
2889
|
-
onChange: (_, data) => setSearchText(data.value)
|
|
2890
|
-
}
|
|
2891
|
-
),
|
|
2892
|
-
/* @__PURE__ */ jsx(
|
|
2893
|
-
ViewFilterMenu,
|
|
2894
|
-
{
|
|
2895
|
-
changed: viewChanged,
|
|
2896
|
-
onEditFilters: showsFilterButton ? () => void openFilter() : void 0,
|
|
2897
|
-
tables: appointments ? void 0 : kinds.map((table) => ({ table, label: tableLabel(table), shown: !hidden.includes(table) })),
|
|
2898
|
-
onTableShownChange: showTable,
|
|
2899
|
-
savedViews: showsSavedViewsMenu ? {
|
|
2900
|
-
canSave: savedViewChanged,
|
|
2901
|
-
canSaveAs: canSaveView && viewChanged,
|
|
2902
|
-
canSetDefault: !!viewId && !isUserDefault,
|
|
2903
|
-
busy: savingView,
|
|
2904
|
-
onSave: () => void signedIn(saveView),
|
|
2905
|
-
onSaveAs: () => void signedIn(() => setNameDialog({ kind: "saveAs", viewId: viewId ?? "", name: "" })),
|
|
2906
|
-
onSetDefault: () => void signedIn(() => viewId ? setDefault(viewId, true) : void 0),
|
|
2907
|
-
onManage: () => void signedIn(() => setManageViewsOpen(true))
|
|
2908
|
-
} : void 0
|
|
2909
|
-
}
|
|
2910
|
-
),
|
|
2911
|
-
!appointments && /* @__PURE__ */ jsx(Tooltip, { content: tAll("app.buttons.refresh.label"), relationship: "label", withArrow: true, children: /* @__PURE__ */ jsx(
|
|
2912
|
-
ToolbarButton,
|
|
2913
|
-
{
|
|
2914
|
-
className: "ppp-calendar-refresh",
|
|
2915
|
-
appearance: "subtle",
|
|
2916
|
-
icon: /* @__PURE__ */ jsx(ArrowClockwiseRegular, {}),
|
|
2917
|
-
disabled: loading,
|
|
2918
|
-
onClick: () => setRefreshes((count) => count + 1)
|
|
2919
|
-
}
|
|
2920
|
-
) })
|
|
2921
|
-
] })
|
|
2922
|
-
] }),
|
|
2923
|
-
/* @__PURE__ */ jsx(
|
|
2924
|
-
GridSaveViewDialog,
|
|
2925
|
-
{
|
|
2926
|
-
open: nameDialog !== null,
|
|
2927
|
-
title: tAll(
|
|
2928
|
-
nameDialog?.kind === "rename" ? "app.components.grid.saved-views-rename-title" : nameDialog?.kind === "clone" ? "app.components.grid.saved-views-clone-title" : "app.components.grid.saved-views-save-as-title"
|
|
2929
|
-
),
|
|
2930
|
-
name: nameDialog?.name ?? "",
|
|
2931
|
-
onSave: onNameDialogSave,
|
|
2932
|
-
onCancel: () => setNameDialog(null)
|
|
2737
|
+
)
|
|
2738
|
+
]
|
|
2933
2739
|
}
|
|
2934
2740
|
),
|
|
2935
|
-
|
|
2936
|
-
|
|
2741
|
+
/* @__PURE__ */ jsx(SavedViewDialogs, { session }),
|
|
2742
|
+
/* @__PURE__ */ jsx(
|
|
2743
|
+
MultiTableFilterDialog,
|
|
2937
2744
|
{
|
|
2938
|
-
open:
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
setManageViewsOpen(false);
|
|
2944
|
-
pickView(id);
|
|
2945
|
-
},
|
|
2946
|
-
onSetDefault: (id, isDefault) => void setDefault(id, isDefault),
|
|
2947
|
-
onSetHidden: (id, isHidden) => void setHidden(id, isHidden),
|
|
2948
|
-
onRename: (id) => setNameDialog({ kind: "rename", viewId: id, name: findSaved(id)?.name ?? findSavedMulti(id)?.name ?? "" }),
|
|
2949
|
-
onClone: (id) => setNameDialog({ kind: "clone", viewId: id, name: tAll("app.components.grid.saved-views-copy-of", [viewLabel(id)]) }),
|
|
2950
|
-
onDelete: (id) => void deleteView(id)
|
|
2745
|
+
open: tableSet.filterDialog !== null,
|
|
2746
|
+
tabs: tableSet.filterDialog?.tabs ?? [],
|
|
2747
|
+
viewTabs: tableSet.filterDialog?.viewTabs,
|
|
2748
|
+
onApply: applyFilter,
|
|
2749
|
+
onCancel: tableSet.closeFilter
|
|
2951
2750
|
}
|
|
2952
2751
|
),
|
|
2953
2752
|
/* @__PURE__ */ jsx(
|
|
2954
|
-
|
|
2753
|
+
ViewLoadMessages,
|
|
2955
2754
|
{
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2755
|
+
failed,
|
|
2756
|
+
errorText: t("error"),
|
|
2757
|
+
failedTables: failures.length > 0 ? t("failed-tables", [failures.map((x) => tableLabel(x.table ?? "")).join(", ")]) : null,
|
|
2758
|
+
retryText: t("retry"),
|
|
2759
|
+
onRetry: () => setRefreshes((count) => count + 1)
|
|
2961
2760
|
}
|
|
2962
2761
|
),
|
|
2963
|
-
failed ? /* @__PURE__ */ jsx(MessageBar, { intent: "error", children: /* @__PURE__ */ jsx(MessageBarBody, { children: t("error") }) }) : failures.length > 0 && // A table that couldn't be read leaves the rest of the range as it is.
|
|
2964
|
-
/* @__PURE__ */ jsxs(MessageBar, { intent: "warning", children: [
|
|
2965
|
-
/* @__PURE__ */ jsx(MessageBarBody, { children: t("failed-tables", [failures.map((x) => tableLabel(x.table ?? "")).join(", ")]) }),
|
|
2966
|
-
/* @__PURE__ */ jsx(MessageBarActions, { children: /* @__PURE__ */ jsx(Button, { size: "small", onClick: () => setRefreshes((count) => count + 1), children: t("retry") }) })
|
|
2967
|
-
] }),
|
|
2968
2762
|
truncated && /* @__PURE__ */ jsx(MessageBar, { intent: "warning", children: /* @__PURE__ */ jsx(MessageBarBody, { children: t("truncated") }) }),
|
|
2969
2763
|
/* @__PURE__ */ jsxs("div", { className: styles.body, children: [
|
|
2970
2764
|
/* @__PURE__ */ jsx("div", { className: styles.surface, children: viewSettled && /* @__PURE__ */ jsx(
|
|
@@ -3026,6 +2820,8 @@ function Calendar({
|
|
|
3026
2820
|
editable,
|
|
3027
2821
|
regardingTables,
|
|
3028
2822
|
location: dialogLocation,
|
|
2823
|
+
showRecordLinks,
|
|
2824
|
+
onNavigate,
|
|
3029
2825
|
onClose: () => {
|
|
3030
2826
|
setOpenAppointment(null);
|
|
3031
2827
|
setCreating(null);
|