@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.cjs
CHANGED
|
@@ -37,8 +37,6 @@ function useCalendarContext() {
|
|
|
37
37
|
if (!context) throw new Error("useCalendarContext must be used in a <Calendar>, among its toolbar items.");
|
|
38
38
|
return context;
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
// src/recurrence-pattern.ts
|
|
42
40
|
var RecurrenceFrequency = {
|
|
43
41
|
Daily: 0,
|
|
44
42
|
Weekly: 1,
|
|
@@ -191,17 +189,8 @@ function describeRecurrence(pattern, start, locale, t) {
|
|
|
191
189
|
}
|
|
192
190
|
return repeats;
|
|
193
191
|
}
|
|
194
|
-
function firstDayOfWeek(locale) {
|
|
195
|
-
try {
|
|
196
|
-
const intlLocale = new Intl.Locale(locale);
|
|
197
|
-
const firstDay = intlLocale.getWeekInfo?.().firstDay ?? intlLocale.weekInfo?.firstDay;
|
|
198
|
-
return firstDay === void 0 ? 0 : firstDay % 7;
|
|
199
|
-
} catch {
|
|
200
|
-
return 0;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
192
|
function weekOrder(locale) {
|
|
204
|
-
const first = firstDayOfWeek(locale);
|
|
193
|
+
const first = core.firstDayOfWeek(locale);
|
|
205
194
|
return Array.from({ length: 7 }, (_, i) => (first + i) % 7);
|
|
206
195
|
}
|
|
207
196
|
function dayName(weekday, locale, width = "long") {
|
|
@@ -315,6 +304,7 @@ function RecurrenceEdit({ value, onChange, start, allowNone = true, readOnly = f
|
|
|
315
304
|
const t = react$1.usePrefixedT("app.components.calendar.recurrence");
|
|
316
305
|
const id = react.useId();
|
|
317
306
|
const language = locale ?? navigator.language;
|
|
307
|
+
const rootRef = react.useRef(null);
|
|
318
308
|
const startDay = react.useRef(start.weekday);
|
|
319
309
|
react.useEffect(() => {
|
|
320
310
|
const was = startDay.current;
|
|
@@ -333,7 +323,8 @@ function RecurrenceEdit({ value, onChange, start, allowNone = true, readOnly = f
|
|
|
333
323
|
const pattern = startingPattern(frequency, start);
|
|
334
324
|
onChange(value ? { ...pattern, end: value.end, occurrences: value.occurrences, endDate: value.endDate } : pattern);
|
|
335
325
|
};
|
|
336
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.root, children: [
|
|
326
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: styles.root, children: [
|
|
327
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.SharedTooltip, { containerRef: rootRef }),
|
|
337
328
|
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Field, { label: t("label"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
338
329
|
reactComponents.Dropdown,
|
|
339
330
|
{
|
|
@@ -406,7 +397,7 @@ function PatternFields({
|
|
|
406
397
|
size: "small",
|
|
407
398
|
checked: pressed,
|
|
408
399
|
disabled: readOnly,
|
|
409
|
-
|
|
400
|
+
"data-ppp-tooltip": dayName(weekday, locale),
|
|
410
401
|
"aria-label": dayName(weekday, locale),
|
|
411
402
|
onClick: () => {
|
|
412
403
|
const days = value.days ^ flag;
|
|
@@ -506,12 +497,28 @@ function AppointmentDetailsDialog({
|
|
|
506
497
|
onClose,
|
|
507
498
|
onSaved,
|
|
508
499
|
children,
|
|
509
|
-
location = "center"
|
|
500
|
+
location = "center",
|
|
501
|
+
showRecordLinks = true,
|
|
502
|
+
onNavigate
|
|
510
503
|
}) {
|
|
511
504
|
const t = react$1.usePrefixedT("app.components.calendar");
|
|
512
505
|
const tAll = react$1.useT();
|
|
513
506
|
const open = appointment !== null || newAppointment2 !== null;
|
|
514
507
|
const isSeries = appointment?.isSeries === true;
|
|
508
|
+
const recordPages = react$1.useRecordPages({ enabled: showRecordLinks });
|
|
509
|
+
const appointmentPage = showRecordLinks && appointment && !isSeries ? core.findRecordPage(recordPages, "appointment") : void 0;
|
|
510
|
+
const pageUrl = appointmentPage && appointment ? core.recordPageUrl(appointmentPage, appointment.id) : void 0;
|
|
511
|
+
const openPage = pageUrl !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
512
|
+
reactComponents.Button,
|
|
513
|
+
{
|
|
514
|
+
as: "a",
|
|
515
|
+
href: pageUrl,
|
|
516
|
+
className: "ppp-calendar-open-record",
|
|
517
|
+
onClick: (event) => reactFluent.followRecordLink(event, pageUrl, onNavigate),
|
|
518
|
+
children: tAll("app.buttons.open.label")
|
|
519
|
+
}
|
|
520
|
+
);
|
|
521
|
+
const regardingLinks = { showRecordLinks, ...onNavigate && { onNavigate } };
|
|
515
522
|
const mayCreateSeries = useMayCreateSeries(open && editable && !isSeries && appointment?.recurring !== true);
|
|
516
523
|
const saved = () => {
|
|
517
524
|
onClose();
|
|
@@ -538,16 +545,21 @@ function AppointmentDetailsDialog({
|
|
|
538
545
|
title: appointment ? appointment.subject : t("new-appointment"),
|
|
539
546
|
actions: editable ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
540
547
|
/* @__PURE__ */ jsxRuntime.jsx(DeleteAction, { seriesId: appointment?.seriesId ?? null, onDeleted: saved }),
|
|
548
|
+
openPage,
|
|
541
549
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.SaveContextButton, { appearance: "primary", onSaved: saved }),
|
|
542
550
|
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { onClick: onClose, children: tAll("app.buttons.cancel.label") })
|
|
543
|
-
] }) : /* @__PURE__ */ jsxRuntime.
|
|
544
|
-
|
|
551
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
552
|
+
openPage,
|
|
553
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { appearance: "primary", onClick: onClose, children: t("close") })
|
|
554
|
+
] }),
|
|
555
|
+
children: isSeries ? /* @__PURE__ */ jsxRuntime.jsx(SeriesRecord, { editable, regardingTables, regardingLinks }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
545
556
|
AppointmentRecord,
|
|
546
557
|
{
|
|
547
558
|
recurring: appointment?.recurring ?? false,
|
|
548
559
|
editable,
|
|
549
560
|
creating: !appointment,
|
|
550
561
|
regardingTables,
|
|
562
|
+
regardingLinks,
|
|
551
563
|
mayCreateSeries,
|
|
552
564
|
children
|
|
553
565
|
}
|
|
@@ -640,6 +652,7 @@ function AppointmentRecord({
|
|
|
640
652
|
editable,
|
|
641
653
|
creating,
|
|
642
654
|
regardingTables,
|
|
655
|
+
regardingLinks,
|
|
643
656
|
mayCreateSeries,
|
|
644
657
|
children
|
|
645
658
|
}) {
|
|
@@ -666,7 +679,7 @@ function AppointmentRecord({
|
|
|
666
679
|
!creating && /* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "organizer", readOnly: true }),
|
|
667
680
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "requiredattendees", readOnly }),
|
|
668
681
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "optionalattendees", readOnly }),
|
|
669
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables } }),
|
|
682
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables }, ...regardingLinks }),
|
|
670
683
|
!creating && /* @__PURE__ */ jsxRuntime.jsx(reactFluent.StatusReasonEdit, { columnName: "statuscode", allowStateChange: true, readOnly }),
|
|
671
684
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "description", readOnly })
|
|
672
685
|
] });
|
|
@@ -755,7 +768,11 @@ function seriesRequests(pattern, appointment, timeZone) {
|
|
|
755
768
|
};
|
|
756
769
|
return [request];
|
|
757
770
|
}
|
|
758
|
-
function SeriesRecord({
|
|
771
|
+
function SeriesRecord({
|
|
772
|
+
editable,
|
|
773
|
+
regardingTables,
|
|
774
|
+
regardingLinks
|
|
775
|
+
}) {
|
|
759
776
|
const styles = useStyles2();
|
|
760
777
|
const t = react$1.usePrefixedT("app.components.calendar");
|
|
761
778
|
const ctx = react$1.useRecordContext();
|
|
@@ -813,7 +830,7 @@ function SeriesRecord({ editable, regardingTables }) {
|
|
|
813
830
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "organizer", readOnly: true }),
|
|
814
831
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "requiredattendees", readOnly }),
|
|
815
832
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "optionalattendees", readOnly }),
|
|
816
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables } }),
|
|
833
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "regardingobjectid", readOnly, ...regardingTables && { targetTables: regardingTables }, ...regardingLinks }),
|
|
817
834
|
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.ColumnEdit, { columnName: "description", readOnly })
|
|
818
835
|
] });
|
|
819
836
|
}
|
|
@@ -1228,8 +1245,47 @@ function newAppointment(range, regarding) {
|
|
|
1228
1245
|
}
|
|
1229
1246
|
};
|
|
1230
1247
|
}
|
|
1248
|
+
function offeredViewIds(defaultViewId2, viewIds, multiTableViewIds, customViews) {
|
|
1249
|
+
const ids = [
|
|
1250
|
+
...defaultViewId2 ? [defaultViewId2] : [],
|
|
1251
|
+
...viewIds ?? [],
|
|
1252
|
+
...multiTableViewIds ?? [],
|
|
1253
|
+
...(customViews ?? []).map((view) => view.id)
|
|
1254
|
+
].map((id) => id.toLowerCase());
|
|
1255
|
+
return ids.length === 0 ? [reactFluent.EVERY_TABLE_VIEW_ID] : [...new Set(ids)];
|
|
1256
|
+
}
|
|
1257
|
+
function findCustomView(id, customViews) {
|
|
1258
|
+
if (!id) return void 0;
|
|
1259
|
+
return customViews?.find((view) => view.id.toLowerCase() === id.toLowerCase());
|
|
1260
|
+
}
|
|
1261
|
+
function selectedViewId(offered, picked) {
|
|
1262
|
+
return picked && offered.includes(picked.toLowerCase()) ? picked.toLowerCase() : offered[0];
|
|
1263
|
+
}
|
|
1264
|
+
function offersViews(offered) {
|
|
1265
|
+
return offered.some((id) => id !== reactFluent.EVERY_TABLE_VIEW_ID);
|
|
1266
|
+
}
|
|
1267
|
+
function withSavedViews(pageViews, savedViews, settings, control, shown, offersSavedViews) {
|
|
1268
|
+
if (!offersSavedViews) return [...pageViews];
|
|
1269
|
+
let all = [...new Set([...pageViews, ...savedViews].map((id) => id.toLowerCase()))];
|
|
1270
|
+
const userDefault = core.defaultViewId(settings, all, control);
|
|
1271
|
+
if (userDefault) all = [userDefault, ...all.filter((id) => id !== userDefault)];
|
|
1272
|
+
const offered = all.filter((id) => id === shown?.toLowerCase() || !core.isViewHidden(settings, id, control));
|
|
1273
|
+
return offered.length > 0 ? offered : all;
|
|
1274
|
+
}
|
|
1275
|
+
var LAYOUTS = ["day", "workWeek", "week", "month", "agenda"];
|
|
1276
|
+
function readSavedLayout(json) {
|
|
1277
|
+
if (!json?.trim()) return void 0;
|
|
1278
|
+
try {
|
|
1279
|
+
const layout = JSON.parse(json).layout;
|
|
1280
|
+
return LAYOUTS.find((x) => x === layout);
|
|
1281
|
+
} catch {
|
|
1282
|
+
return void 0;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
function writeSavedLayout(layout) {
|
|
1286
|
+
return JSON.stringify({ version: 1, layout });
|
|
1287
|
+
}
|
|
1231
1288
|
var APPOINTMENT_TABLE = "appointment";
|
|
1232
|
-
var EVERY_TABLE_VIEW_ID = "00000000-0000-0000-0000-000000000000";
|
|
1233
1289
|
var SERIES_TABLE2 = "recurringappointmentmaster";
|
|
1234
1290
|
var DEFAULT_CALENDAR_TABLES = [APPOINTMENT_TABLE, "task"];
|
|
1235
1291
|
var CALENDAR_COLUMNS = {
|
|
@@ -1295,10 +1351,10 @@ function drawnTimes(item, dateOnly, timeZone) {
|
|
|
1295
1351
|
return { start: zonedMidnight(first, timeZone), end: zonedMidnight(after, timeZone) };
|
|
1296
1352
|
}
|
|
1297
1353
|
function fromMultiTableItem(item, info, drawn) {
|
|
1298
|
-
const
|
|
1354
|
+
const dates = info?.definition?.calendar;
|
|
1299
1355
|
const changeable = new Set((info?.changeableColumns ?? []).map((x) => x.toLowerCase()));
|
|
1300
|
-
const movable = (Number(item.permissions ?? 0) & core.TableSecurityPermission.Write) !== 0 && !isClosed(item) && !!
|
|
1301
|
-
const resizable = movable && !!
|
|
1356
|
+
const movable = (Number(item.permissions ?? 0) & core.TableSecurityPermission.Write) !== 0 && !isClosed(item) && !!dates?.start && changeable.has(dates.start.toLowerCase());
|
|
1357
|
+
const resizable = movable && !!dates?.end && changeable.has(dates.end.toLowerCase());
|
|
1302
1358
|
const isAppointment = item.table === APPOINTMENT_TABLE;
|
|
1303
1359
|
const state = stateOf(item);
|
|
1304
1360
|
const location = valueOf2(item.record, "location");
|
|
@@ -1316,7 +1372,7 @@ function fromMultiTableItem(item, info, drawn) {
|
|
|
1316
1372
|
durationEditable: resizable ? null : false,
|
|
1317
1373
|
showAs: isAppointment ? showAsOf(typeof status === "number" ? status : null, state) : AppointmentShowAs.Busy,
|
|
1318
1374
|
canceled: state === 2,
|
|
1319
|
-
color: definition?.color ?? null,
|
|
1375
|
+
color: info?.definition?.color ?? null,
|
|
1320
1376
|
record: item.record ?? null
|
|
1321
1377
|
};
|
|
1322
1378
|
}
|
|
@@ -1324,86 +1380,23 @@ function stored(moment, dateOnly, timeZone) {
|
|
|
1324
1380
|
return dateOnly ? `${localDate(moment, timeZone)}T00:00:00.000Z` : moment.toISOString();
|
|
1325
1381
|
}
|
|
1326
1382
|
function moveRecord(change, item, info, dateOnly, timeZone) {
|
|
1327
|
-
const
|
|
1328
|
-
if (!
|
|
1383
|
+
const dates = info?.definition?.calendar;
|
|
1384
|
+
if (!dates?.start) return null;
|
|
1329
1385
|
const changeable = new Set((info?.changeableColumns ?? []).map((x) => x.toLowerCase()));
|
|
1330
|
-
const allDayColumn =
|
|
1386
|
+
const allDayColumn = dates.allDay && changeable.has(dates.allDay.toLowerCase()) ? dates.allDay : null;
|
|
1331
1387
|
if (change.allDay !== (item.isAllDay ?? false) && !allDayColumn) return null;
|
|
1332
1388
|
if (dateOnly && !change.allDay) return null;
|
|
1333
1389
|
const end = change.end ?? new Date(change.start.getTime() + (change.allDay ? DAY_MS2 : 30 * MINUTE_MS2));
|
|
1334
1390
|
const drawn = drawnTimes(item, dateOnly, timeZone);
|
|
1335
1391
|
const lengthChanged = end.getTime() - change.start.getTime() !== drawn.end.getTime() - drawn.start.getTime();
|
|
1336
1392
|
const properties = {
|
|
1337
|
-
[
|
|
1393
|
+
[dates.start]: { $type: 2, value: stored(change.start, dateOnly, timeZone) }
|
|
1338
1394
|
};
|
|
1339
|
-
if (
|
|
1340
|
-
properties[
|
|
1395
|
+
if (dates.end && (!item.hasNoEnd || lengthChanged))
|
|
1396
|
+
properties[dates.end] = { $type: 2, value: stored(end, dateOnly, timeZone) };
|
|
1341
1397
|
if (allDayColumn) properties[allDayColumn] = { $type: 0, value: change.allDay };
|
|
1342
1398
|
return { tableName: item.table, id: item.id, properties };
|
|
1343
1399
|
}
|
|
1344
|
-
function tablesOf(tables, registered, allowed, stored2, isStoredView) {
|
|
1345
|
-
let named;
|
|
1346
|
-
if (tables) named = tables.map((x) => x.table ?? "");
|
|
1347
|
-
else if (isStoredView) {
|
|
1348
|
-
if (!stored2) return null;
|
|
1349
|
-
named = [...stored2];
|
|
1350
|
-
} else named = registered.map((x) => x.table ?? "");
|
|
1351
|
-
const expanded = named.flatMap(
|
|
1352
|
-
(table) => table.toLowerCase() === "activitypointer" ? registered.filter((x) => x.isActivity).map((x) => x.table ?? "") : [table.toLowerCase()]
|
|
1353
|
-
);
|
|
1354
|
-
return [...new Set(expanded)].filter(
|
|
1355
|
-
(table) => registered.some((x) => x.table === table) && (!allowed || allowed.has(table))
|
|
1356
|
-
);
|
|
1357
|
-
}
|
|
1358
|
-
function hiddenByDefault(viewId, shown, defaults) {
|
|
1359
|
-
if (viewId !== EVERY_TABLE_VIEW_ID || !shown.some((table) => defaults.has(table))) return [];
|
|
1360
|
-
return shown.filter((table) => !defaults.has(table));
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
// src/calendar-query.ts
|
|
1364
|
-
function offeredViewIds(defaultViewId2, viewIds, multiTableViewIds, customViews) {
|
|
1365
|
-
const ids = [
|
|
1366
|
-
...defaultViewId2 ? [defaultViewId2] : [],
|
|
1367
|
-
...viewIds ?? [],
|
|
1368
|
-
...multiTableViewIds ?? [],
|
|
1369
|
-
...(customViews ?? []).map((view) => view.id)
|
|
1370
|
-
].map((id) => id.toLowerCase());
|
|
1371
|
-
return ids.length === 0 ? [EVERY_TABLE_VIEW_ID] : [...new Set(ids)];
|
|
1372
|
-
}
|
|
1373
|
-
function findCustomView(id, customViews) {
|
|
1374
|
-
if (!id) return void 0;
|
|
1375
|
-
return customViews?.find((view) => view.id.toLowerCase() === id.toLowerCase());
|
|
1376
|
-
}
|
|
1377
|
-
function selectedViewId(offered, picked) {
|
|
1378
|
-
return picked && offered.includes(picked.toLowerCase()) ? picked.toLowerCase() : offered[0];
|
|
1379
|
-
}
|
|
1380
|
-
function offersViews(offered) {
|
|
1381
|
-
return offered.some((id) => id !== EVERY_TABLE_VIEW_ID);
|
|
1382
|
-
}
|
|
1383
|
-
function everyRow(table) {
|
|
1384
|
-
return `<fetch><entity name="${table}" /></fetch>`;
|
|
1385
|
-
}
|
|
1386
|
-
function withSavedViews(pageViews, savedViews, settings, control, shown, offersSavedViews) {
|
|
1387
|
-
if (!offersSavedViews) return [...pageViews];
|
|
1388
|
-
let all = [...new Set([...pageViews, ...savedViews].map((id) => id.toLowerCase()))];
|
|
1389
|
-
const userDefault = core.defaultViewId(settings, all, control);
|
|
1390
|
-
if (userDefault) all = [userDefault, ...all.filter((id) => id !== userDefault)];
|
|
1391
|
-
const offered = all.filter((id) => id === shown?.toLowerCase() || !core.isViewHidden(settings, id, control));
|
|
1392
|
-
return offered.length > 0 ? offered : all;
|
|
1393
|
-
}
|
|
1394
|
-
var LAYOUTS = ["day", "workWeek", "week", "month", "agenda"];
|
|
1395
|
-
function readSavedLayout(json) {
|
|
1396
|
-
if (!json?.trim()) return void 0;
|
|
1397
|
-
try {
|
|
1398
|
-
const layout = JSON.parse(json).layout;
|
|
1399
|
-
return LAYOUTS.find((x) => x === layout);
|
|
1400
|
-
} catch {
|
|
1401
|
-
return void 0;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
function writeSavedLayout(layout) {
|
|
1405
|
-
return JSON.stringify({ version: 1, layout });
|
|
1406
|
-
}
|
|
1407
1400
|
|
|
1408
1401
|
// ../../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
|
|
1409
1402
|
var skeleton_default = `
|
|
@@ -1930,8 +1923,6 @@ function ensureFullCalendarStyles(document2) {
|
|
|
1930
1923
|
ensureStyleSheet(document2, STYLE_ID2, `${skeleton_default}
|
|
1931
1924
|
${theme_default}`);
|
|
1932
1925
|
}
|
|
1933
|
-
|
|
1934
|
-
// src/persisted-calendar-state.ts
|
|
1935
1926
|
var DATE2 = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
1936
1927
|
var GUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1937
1928
|
function isDate(value) {
|
|
@@ -1969,21 +1960,10 @@ function encodePersistedCalendarState(state) {
|
|
|
1969
1960
|
return Object.keys(compact).length > 0 ? JSON.stringify(compact) : null;
|
|
1970
1961
|
}
|
|
1971
1962
|
function writePersistedCalendarState(queryParameterName, state) {
|
|
1972
|
-
if (!queryParameterName
|
|
1973
|
-
|
|
1974
|
-
const params = new URLSearchParams(window.location.search);
|
|
1975
|
-
if (params.get(queryParameterName) === encoded) return;
|
|
1976
|
-
if (encoded === null) params.delete(queryParameterName);
|
|
1977
|
-
else params.set(queryParameterName, encoded);
|
|
1978
|
-
const query = params.toString();
|
|
1979
|
-
window.history.replaceState(
|
|
1980
|
-
window.history.state,
|
|
1981
|
-
"",
|
|
1982
|
-
`${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`
|
|
1983
|
-
);
|
|
1963
|
+
if (!queryParameterName) return;
|
|
1964
|
+
react$1.replaceQueryParam(queryParameterName, encodePersistedCalendarState(state) ?? void 0);
|
|
1984
1965
|
}
|
|
1985
1966
|
var plugins = [formaTheme__default.default, dayGridPlugin__default.default, timeGridPlugin__default.default, listPlugin__default.default, interactionPlugin__default.default];
|
|
1986
|
-
var SEARCH_DEBOUNCE_MS = 300;
|
|
1987
1967
|
var layoutKeys = {
|
|
1988
1968
|
day: "layouts.day",
|
|
1989
1969
|
workWeek: "layouts.work-week",
|
|
@@ -1998,32 +1978,6 @@ var useStyles3 = reactComponents.makeStyles({
|
|
|
1998
1978
|
gap: reactComponents.tokens.spacingVerticalS,
|
|
1999
1979
|
minHeight: 0
|
|
2000
1980
|
},
|
|
2001
|
-
// Two groups: the views, navigation and title, then search and the rest at the end. On a narrow
|
|
2002
|
-
// screen the end group wraps below the first as a whole rather than squeezing the title.
|
|
2003
|
-
toolbar: {
|
|
2004
|
-
alignItems: "center",
|
|
2005
|
-
flexWrap: "wrap",
|
|
2006
|
-
justifyContent: "space-between",
|
|
2007
|
-
rowGap: reactComponents.tokens.spacingVerticalXS,
|
|
2008
|
-
columnGap: reactComponents.tokens.spacingHorizontalS,
|
|
2009
|
-
paddingInline: 0
|
|
2010
|
-
},
|
|
2011
|
-
toolbarStart: {
|
|
2012
|
-
display: "flex",
|
|
2013
|
-
alignItems: "center",
|
|
2014
|
-
gap: reactComponents.tokens.spacingHorizontalXS,
|
|
2015
|
-
flex: "1 1 auto",
|
|
2016
|
-
minWidth: 0
|
|
2017
|
-
},
|
|
2018
|
-
toolbarEnd: {
|
|
2019
|
-
display: "flex",
|
|
2020
|
-
flexWrap: "wrap",
|
|
2021
|
-
alignItems: "center",
|
|
2022
|
-
justifyContent: "flex-end",
|
|
2023
|
-
gap: reactComponents.tokens.spacingHorizontalXS,
|
|
2024
|
-
marginInlineStart: "auto",
|
|
2025
|
-
minWidth: 0
|
|
2026
|
-
},
|
|
2027
1981
|
// The period and the moves through it, kept together.
|
|
2028
1982
|
navigation: {
|
|
2029
1983
|
display: "flex",
|
|
@@ -2045,10 +1999,6 @@ var useStyles3 = reactComponents.makeStyles({
|
|
|
2045
1999
|
overflow: "hidden",
|
|
2046
2000
|
textOverflow: "ellipsis"
|
|
2047
2001
|
},
|
|
2048
|
-
// As wide as a grid's view picker.
|
|
2049
|
-
viewPicker: {
|
|
2050
|
-
minWidth: "220px"
|
|
2051
|
-
},
|
|
2052
2002
|
search: {
|
|
2053
2003
|
width: "220px",
|
|
2054
2004
|
maxWidth: "100%"
|
|
@@ -2118,6 +2068,8 @@ function Calendar({
|
|
|
2118
2068
|
defaultLayout = "week",
|
|
2119
2069
|
layouts,
|
|
2120
2070
|
editable = false,
|
|
2071
|
+
showRecordLinks = true,
|
|
2072
|
+
onNavigate,
|
|
2121
2073
|
regardingTables,
|
|
2122
2074
|
height = "600px",
|
|
2123
2075
|
onAppointmentClick,
|
|
@@ -2186,6 +2138,7 @@ function Calendar({
|
|
|
2186
2138
|
);
|
|
2187
2139
|
const viewId = selectedViewId(offered, shownViewId);
|
|
2188
2140
|
if (viewSettled) openedViewRef.current ??= viewId;
|
|
2141
|
+
const tableSet = reactFluent.useMultiTableTableSet({ use: core.MultiTableUses.Calendar, viewId, tables, defaultTables });
|
|
2189
2142
|
const openingLayoutRef = react.useRef(void 0);
|
|
2190
2143
|
if (openingLayoutRef.current === void 0 && viewSettled) {
|
|
2191
2144
|
const savedLayout = persisted.l ? void 0 : readSavedLayout(savedCalendarLayout(viewId));
|
|
@@ -2194,13 +2147,12 @@ function Calendar({
|
|
|
2194
2147
|
const initialLayout = openingLayoutRef.current ?? openingLayout(layoutsOffered, persisted.l, defaultLayout);
|
|
2195
2148
|
const viewOpeningLayout = (id) => openingLayout(layoutsOffered, readSavedLayout(savedCalendarLayout(id)), defaultLayout);
|
|
2196
2149
|
const showsSearch = !appointments && allowSearch;
|
|
2197
|
-
const [
|
|
2198
|
-
const [search, setSearch] = react.useState(searchText);
|
|
2150
|
+
const [search, setSearch] = react.useState(() => includeSearchInPersistedState ? persisted.q ?? "" : "");
|
|
2199
2151
|
const picksViews = !appointments && offered.length > 1;
|
|
2200
2152
|
const namesViews = picksViews || !appointments && saved.available;
|
|
2201
2153
|
const namedViewIds = saved.available ? [.../* @__PURE__ */ new Set([...offered, ...pageViews])] : offered;
|
|
2202
2154
|
const dataverseViewIds = namedViewIds.filter(
|
|
2203
|
-
(id) => id !== EVERY_TABLE_VIEW_ID && !isMultiTableView(id) && !findCustomView(id, customViewDefinitions) && !findSaved(id) && !findSavedMulti(id)
|
|
2155
|
+
(id) => id !== reactFluent.EVERY_TABLE_VIEW_ID && !isMultiTableView(id) && !findCustomView(id, customViewDefinitions) && !findSaved(id) && !findSavedMulti(id)
|
|
2204
2156
|
);
|
|
2205
2157
|
react$1.useLocalization(namesViews ? dataverseViewIds.map((id) => `views.${id}`) : []);
|
|
2206
2158
|
const [viewNames, setViewNames] = react.useState({ dataverse: /* @__PURE__ */ new Map(), multiTable: /* @__PURE__ */ new Map() });
|
|
@@ -2216,10 +2168,10 @@ function Calendar({
|
|
|
2216
2168
|
const multiTable = new Map(viewNames.multiTable);
|
|
2217
2169
|
const missing = multiTableIds.filter((x) => !multiTable.has(x));
|
|
2218
2170
|
if (missing.length > 0) {
|
|
2219
|
-
const registeredViews = (await registeredAsync().catch(() => null))?.views ?? [];
|
|
2171
|
+
const registeredViews = (await tableSet.registeredAsync().catch(() => null))?.views ?? [];
|
|
2220
2172
|
for (const id of missing) {
|
|
2221
2173
|
const known2 = registeredViews.find((view2) => view2.id?.toLowerCase() === id);
|
|
2222
|
-
multiTable.set(id, known2 ? known2.name ?? null : await storedViewName(id));
|
|
2174
|
+
multiTable.set(id, known2 ? known2.name ?? null : (await tableSet.storedViewName(id)).name);
|
|
2223
2175
|
}
|
|
2224
2176
|
}
|
|
2225
2177
|
if (current) setViewNames({ dataverse, multiTable });
|
|
@@ -2229,7 +2181,7 @@ function Calendar({
|
|
|
2229
2181
|
};
|
|
2230
2182
|
}, [namesViews, namesKey, ppp]);
|
|
2231
2183
|
const labelOf = (id) => {
|
|
2232
|
-
if (id === EVERY_TABLE_VIEW_ID) return t("every-table");
|
|
2184
|
+
if (id === reactFluent.EVERY_TABLE_VIEW_ID) return t("every-table");
|
|
2233
2185
|
const custom = findCustomView(id, customViewDefinitions);
|
|
2234
2186
|
if (custom) return custom.displayName?.trim() ? custom.displayName : id;
|
|
2235
2187
|
const ownMulti = findSavedMulti(id);
|
|
@@ -2246,12 +2198,7 @@ function Calendar({
|
|
|
2246
2198
|
}
|
|
2247
2199
|
if (!viewNames.dataverse.has(id)) return null;
|
|
2248
2200
|
const metadata = viewNames.dataverse.get(id);
|
|
2249
|
-
|
|
2250
|
-
const key = `tables.${metadata.tableName}.views.${id}.label`;
|
|
2251
|
-
const localized = tAll(key);
|
|
2252
|
-
if (localized !== key) return localized;
|
|
2253
|
-
}
|
|
2254
|
-
return metadata?.displayName ?? metadata?.name ?? id;
|
|
2201
|
+
return metadata ? reactFluent.viewLabelOf({ ...metadata, id }, tAll) : id;
|
|
2255
2202
|
};
|
|
2256
2203
|
const showsSavedViewsMenu = allowSavedViews && !appointments && (saved.available || saved.needsSignIn);
|
|
2257
2204
|
const viewOptions = react.useMemo(() => {
|
|
@@ -2261,11 +2208,8 @@ function Calendar({
|
|
|
2261
2208
|
return label === null ? null : { id, label };
|
|
2262
2209
|
});
|
|
2263
2210
|
if (labeled.some((option) => option === null)) return [];
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
if (viewSort === reactFluent.ViewSort.NameDescending) options2.sort((a, b) => b.label.localeCompare(a.label, locale));
|
|
2267
|
-
return options2;
|
|
2268
|
-
}, [offered, customViewsKey, saved.views, multiSaved.views, viewNames, viewSort, tAll, locale, showsSavedViewsMenu]);
|
|
2211
|
+
return labeled;
|
|
2212
|
+
}, [offered, customViewsKey, saved.views, multiSaved.views, viewNames, tAll, showsSavedViewsMenu]);
|
|
2269
2213
|
const showsViewPicker = !appointments && viewOptions.length > (showsSavedViewsMenu ? 0 : 1);
|
|
2270
2214
|
react.useEffect(() => {
|
|
2271
2215
|
ensureFullCalendarStyles(document);
|
|
@@ -2300,7 +2244,7 @@ function Calendar({
|
|
|
2300
2244
|
react.useEffect(() => () => void (latestStart.current = -1), []);
|
|
2301
2245
|
const user = authState.status === "authenticated" ? authState.user?.userId : null;
|
|
2302
2246
|
const tablesKey = (tables ?? []).map((table) => table.trim().toLowerCase()).join(",");
|
|
2303
|
-
const allowedTables =
|
|
2247
|
+
const allowedTables = tableSet.allowed;
|
|
2304
2248
|
const mayCreateAppointments = () => {
|
|
2305
2249
|
let asked = mayCreate.current;
|
|
2306
2250
|
if (!asked || asked.user !== user) {
|
|
@@ -2360,36 +2304,12 @@ function Calendar({
|
|
|
2360
2304
|
const [refreshes, setRefreshes] = react.useState(0);
|
|
2361
2305
|
const latestLoad = react.useRef(null);
|
|
2362
2306
|
react.useEffect(() => () => latestLoad.current?.abort(), []);
|
|
2363
|
-
const
|
|
2364
|
-
const
|
|
2365
|
-
const
|
|
2366
|
-
let asked = registeredRef.current;
|
|
2367
|
-
if (!asked || asked.user !== user) {
|
|
2368
|
-
const answer = ppp.getMultiTableTablesAsync();
|
|
2369
|
-
asked = registeredRef.current = { user, answer };
|
|
2370
|
-
answer.then(
|
|
2371
|
-
(response) => registeredRef.current?.answer === answer && setRegistered(response),
|
|
2372
|
-
() => {
|
|
2373
|
-
if (registeredRef.current?.answer === answer) registeredRef.current = null;
|
|
2374
|
-
}
|
|
2375
|
-
);
|
|
2376
|
-
}
|
|
2377
|
-
return asked.answer;
|
|
2378
|
-
};
|
|
2379
|
-
const infoOf = (table) => registered?.tables?.find((x) => x.table === table);
|
|
2380
|
-
const storedViewName = async (id) => {
|
|
2381
|
-
try {
|
|
2382
|
-
const stored2 = await ppp.retrieveRecordAsync("ppp_multitableview", id, ["ppp_name"]);
|
|
2383
|
-
const name = stored2.properties?.["ppp_name"]?.value;
|
|
2384
|
-
return typeof name === "string" ? name : null;
|
|
2385
|
-
} catch {
|
|
2386
|
-
return null;
|
|
2387
|
-
}
|
|
2388
|
-
};
|
|
2389
|
-
const storedViewTables = react.useRef(/* @__PURE__ */ new Map());
|
|
2307
|
+
const registeredAsync = tableSet.registeredAsync;
|
|
2308
|
+
const infoOf = tableSet.infoOf;
|
|
2309
|
+
const tableLabel = tableSet.tableLabel;
|
|
2390
2310
|
const isStoredView = (id, response) => isMultiTableView(id) && !(response.views ?? []).some((view2) => view2.id?.toLowerCase() === id);
|
|
2391
2311
|
const viewTablesAsync = async (id) => {
|
|
2392
|
-
if (id === EVERY_TABLE_VIEW_ID) return null;
|
|
2312
|
+
if (id === reactFluent.EVERY_TABLE_VIEW_ID) return null;
|
|
2393
2313
|
if (isMultiTableView(id))
|
|
2394
2314
|
return (await registeredAsync()).views?.find((view3) => view3.id?.toLowerCase() === id)?.tables ?? null;
|
|
2395
2315
|
const custom = findCustomView(id, customViewDefinitions);
|
|
@@ -2403,35 +2323,15 @@ function Calendar({
|
|
|
2403
2323
|
console.warn(`[Calendar] The view ${id} doesn't exist or is on a table the user may not read, so it shows nothing.`);
|
|
2404
2324
|
return [];
|
|
2405
2325
|
};
|
|
2326
|
+
const knownTablesOf = (id, viewTables, response) => tableSet.tablesOf(viewTables, isStoredView(id, response) ? id : null);
|
|
2406
2327
|
const defaultsKey = defaultTables.map((table) => table.trim().toLowerCase()).join(",");
|
|
2407
|
-
const
|
|
2408
|
-
const
|
|
2409
|
-
const [hiddenChoice, setHiddenChoice] = react.useState(null);
|
|
2410
|
-
const hiddenIn = (id, of) => hiddenChoice && hiddenChoice.viewId === id ? hiddenChoice.tables : hiddenByDefault(id, of, new Set(defaultsKey.split(",").filter(Boolean)));
|
|
2411
|
-
const hidden = hiddenIn(viewId, known);
|
|
2412
|
-
const shownIn = (id, of, byView = false) => {
|
|
2413
|
-
const off = byView ? hiddenByDefault(id, of, new Set(defaultsKey.split(",").filter(Boolean))) : hiddenIn(id, of);
|
|
2414
|
-
return of.length < 2 ? [...of] : of.filter((table) => !off.includes(table));
|
|
2415
|
-
};
|
|
2416
|
-
const shownTables = shownIn(viewId, known);
|
|
2417
|
-
const kinds = known.length > 1 ? known : [];
|
|
2418
|
-
const hiddenAtOpen = hiddenByDefault(viewId, known, new Set(defaultsKey.split(",").filter(Boolean)));
|
|
2419
|
-
const tablesChanged = kinds.some((table) => hidden.includes(table) !== hiddenAtOpen.includes(table));
|
|
2420
|
-
const showTable = (table, shown) => {
|
|
2421
|
-
const next = shown ? hidden.filter((x) => x !== table) : [.../* @__PURE__ */ new Set([...hidden, table])];
|
|
2422
|
-
setHiddenChoice({ viewId, tables: next });
|
|
2423
|
-
};
|
|
2424
|
-
react$1.useLocalization(known.map((table) => `tables.${table}`));
|
|
2425
|
-
const tableLabel = (table) => {
|
|
2426
|
-
const key = `tables.${table}.label`;
|
|
2427
|
-
const label = tAll(key);
|
|
2428
|
-
return label !== key ? label : table;
|
|
2429
|
-
};
|
|
2328
|
+
const known = tableSet.known;
|
|
2329
|
+
const shownTables = tableSet.shown;
|
|
2430
2330
|
const rows = react.useRef(/* @__PURE__ */ new Map());
|
|
2431
2331
|
const dateOnly = react.useRef(/* @__PURE__ */ new Map());
|
|
2432
2332
|
const learnDateOnly = async (tables2, response) => {
|
|
2433
2333
|
for (const table of [...new Set(tables2)].filter((x) => !dateOnly.current.has(x))) {
|
|
2434
|
-
const start = response.tables?.find((x) => x.table === table)?.definition?.start;
|
|
2334
|
+
const start = response.tables?.find((x) => x.table === table)?.definition?.calendar?.start;
|
|
2435
2335
|
try {
|
|
2436
2336
|
const metadata = await tableMetadataCache.getAsync(table);
|
|
2437
2337
|
const column = metadata?.columns?.find((x) => x.columnName === start);
|
|
@@ -2442,22 +2342,12 @@ function Calendar({
|
|
|
2442
2342
|
}
|
|
2443
2343
|
};
|
|
2444
2344
|
const [failures, setFailures] = react.useState([]);
|
|
2445
|
-
const showsFilterButton = !appointments && allowFiltering && !(registered && isStoredView(viewId, registered));
|
|
2446
|
-
const
|
|
2447
|
-
react.useEffect(() => {
|
|
2448
|
-
setUserFilter((current) => current && current.viewId !== viewId ? null : current);
|
|
2449
|
-
setHiddenChoice((current) => current && current.viewId !== viewId ? null : current);
|
|
2450
|
-
}, [viewId]);
|
|
2451
|
-
const filtered = userFilter && userFilter.viewId === viewId ? userFilter : null;
|
|
2452
|
-
const [filterDialog, setFilterDialog] = react.useState(null);
|
|
2345
|
+
const showsFilterButton = !appointments && allowFiltering && !(tableSet.registered && isStoredView(viewId, tableSet.registered));
|
|
2346
|
+
const filtered = tableSet.filter;
|
|
2453
2347
|
const filterTablesAsync = async (id) => {
|
|
2454
|
-
|
|
2455
|
-
const tablesShown = await viewTablesAsync(id) ?? (id === EVERY_TABLE_VIEW_ID ? (tablesOf(null
|
|
2456
|
-
return
|
|
2457
|
-
};
|
|
2458
|
-
const isShownTable = (table, named, shownNow, response) => {
|
|
2459
|
-
const lower = (x) => x.toLowerCase();
|
|
2460
|
-
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));
|
|
2348
|
+
await registeredAsync();
|
|
2349
|
+
const tablesShown = await viewTablesAsync(id) ?? (id === reactFluent.EVERY_TABLE_VIEW_ID ? (tableSet.tablesOf(null) ?? []).map((table) => ({ table })) : []);
|
|
2350
|
+
return tableSet.filterQueries(tablesShown);
|
|
2461
2351
|
};
|
|
2462
2352
|
const openFilter = async () => {
|
|
2463
2353
|
const id = viewId;
|
|
@@ -2465,36 +2355,14 @@ function Calendar({
|
|
|
2465
2355
|
try {
|
|
2466
2356
|
const response = await registeredAsync();
|
|
2467
2357
|
const tablesShown = await filterTablesAsync(id);
|
|
2468
|
-
const knownNow =
|
|
2469
|
-
|
|
2470
|
-
response.tables ?? [],
|
|
2471
|
-
allowedTables,
|
|
2472
|
-
storedViewTables.current.get(id),
|
|
2473
|
-
isStoredView(id, response)
|
|
2474
|
-
) ?? [];
|
|
2475
|
-
const shownNow = shownIn(id, knownNow);
|
|
2476
|
-
const named = tablesShown.map((x) => x.table.table ?? "");
|
|
2477
|
-
const tabs = reactFluent.multiTableFilterTabs(
|
|
2478
|
-
tablesShown,
|
|
2479
|
-
(table) => isShownTable(table, named, shownNow, response),
|
|
2480
|
-
tableLabel,
|
|
2481
|
-
filtered?.criteria
|
|
2482
|
-
);
|
|
2483
|
-
const shownByView = shownIn(id, knownNow, true);
|
|
2484
|
-
const viewTabs = reactFluent.multiTableFilterTabs(tablesShown, (table) => isShownTable(table, named, shownByView, response), tableLabel);
|
|
2485
|
-
if (tabs.length > 0 && id === viewId) setFilterDialog({ viewId: id, tables: tablesShown, tabs, viewTabs });
|
|
2358
|
+
const knownNow = knownTablesOf(id, await viewTablesAsync(id) ?? null, response) ?? [];
|
|
2359
|
+
tableSet.openFilter(id, tablesShown, knownNow, tableLabel);
|
|
2486
2360
|
} catch (error) {
|
|
2487
2361
|
console.warn("[Calendar] The filters of the view shown could not be read.", error);
|
|
2488
2362
|
}
|
|
2489
2363
|
};
|
|
2490
2364
|
const applyFilter = (criteria, restoreView) => {
|
|
2491
|
-
|
|
2492
|
-
setFilterDialog(null);
|
|
2493
|
-
if (!dialog2 || dialog2.viewId !== viewId) return;
|
|
2494
|
-
const filter = reactFluent.applyMultiTableFilter(dialog2.tables, restoreView ? dialog2.viewTabs : dialog2.tabs, criteria);
|
|
2495
|
-
setUserFilter(filter ? { viewId, tables: filter.tables, criteria: filter.criteria } : null);
|
|
2496
|
-
if (!restoreView) return;
|
|
2497
|
-
setHiddenChoice(null);
|
|
2365
|
+
if (!tableSet.applyFilter(criteria, restoreView) || !restoreView) return;
|
|
2498
2366
|
const layout = viewOpeningLayout(viewId);
|
|
2499
2367
|
if (layout !== currentLayout && layoutsOffered.includes(layout)) controller.changeView(toFullCalendarView(layout));
|
|
2500
2368
|
};
|
|
@@ -2507,7 +2375,7 @@ function Calendar({
|
|
|
2507
2375
|
customViewsKey,
|
|
2508
2376
|
filtered?.tables ?? null,
|
|
2509
2377
|
searched,
|
|
2510
|
-
hiddenChoice,
|
|
2378
|
+
tableSet.hiddenChoice,
|
|
2511
2379
|
tablesKey,
|
|
2512
2380
|
defaultsKey,
|
|
2513
2381
|
matchParties ?? null,
|
|
@@ -2537,14 +2405,10 @@ function Calendar({
|
|
|
2537
2405
|
openingViewRef.current = offered[0];
|
|
2538
2406
|
if (viewSettled && previous !== void 0 && previous !== offered[0]) persist();
|
|
2539
2407
|
}, [offered[0]]);
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
persist({ search: searchText });
|
|
2545
|
-
}, SEARCH_DEBOUNCE_MS);
|
|
2546
|
-
return () => clearTimeout(timer);
|
|
2547
|
-
}, [searchText]);
|
|
2408
|
+
const searchFor = (text) => {
|
|
2409
|
+
setSearch(text);
|
|
2410
|
+
persist({ search: text });
|
|
2411
|
+
};
|
|
2548
2412
|
const events = react.useMemo(() => {
|
|
2549
2413
|
if (appointments) return appointments.map(toEventInput);
|
|
2550
2414
|
return async (info) => {
|
|
@@ -2557,8 +2421,8 @@ function Calendar({
|
|
|
2557
2421
|
const response = await registeredAsync();
|
|
2558
2422
|
const viewTables = await viewTablesAsync(id);
|
|
2559
2423
|
const stored2 = isStoredView(id, response);
|
|
2560
|
-
let knownNow =
|
|
2561
|
-
if (latestLoad.current === load && knownNow)
|
|
2424
|
+
let knownNow = knownTablesOf(id, viewTables, response);
|
|
2425
|
+
if (latestLoad.current === load && knownNow) tableSet.setKnown(id, knownNow);
|
|
2562
2426
|
if (knownNow?.length === 0) {
|
|
2563
2427
|
if (latestLoad.current === load) {
|
|
2564
2428
|
setFailed(false);
|
|
@@ -2574,7 +2438,7 @@ function Calendar({
|
|
|
2574
2438
|
viewId: filtered || !isMultiTableView(id) ? null : id,
|
|
2575
2439
|
tables: filtered ? [...filtered.tables] : viewTables && viewTables.length > 0 ? [...viewTables] : null,
|
|
2576
2440
|
// A view whose tables aren't known yet is read as the calendar allows.
|
|
2577
|
-
includeTables: knownNow ? shownIn(id, knownNow) : allowedTables ? [...allowedTables] : null,
|
|
2441
|
+
includeTables: knownNow ? tableSet.shownIn(id, knownNow) : allowedTables ? [...allowedTables] : null,
|
|
2578
2442
|
regarding: regarding ? { tableName: regarding.tableName, id: regarding.id } : null,
|
|
2579
2443
|
matchParties: matchParties ?? null,
|
|
2580
2444
|
series: series ?? null,
|
|
@@ -2583,9 +2447,8 @@ function Calendar({
|
|
|
2583
2447
|
};
|
|
2584
2448
|
const range = await ppp.loadMultiTableRangeAsync(request, load.signal);
|
|
2585
2449
|
if (!knownNow && stored2) {
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
if (latestLoad.current === load) setKnownTables({ viewId: id, tables: knownNow });
|
|
2450
|
+
knownNow = tableSet.learnTables(id, range.tables ?? []);
|
|
2451
|
+
if (latestLoad.current === load) tableSet.setKnown(id, knownNow);
|
|
2589
2452
|
}
|
|
2590
2453
|
const items = range.items ?? [];
|
|
2591
2454
|
await learnDateOnly(items.map((item) => item.table ?? ""), response);
|
|
@@ -2702,13 +2565,10 @@ function Calendar({
|
|
|
2702
2565
|
const shownSaved = findSaved(viewId);
|
|
2703
2566
|
const shownSavedMulti = findSavedMulti(viewId);
|
|
2704
2567
|
const showsAppointmentsAlone = shownTables.length === 1 && shownTables[0] === APPOINTMENT_TABLE;
|
|
2705
|
-
const canSaveView = shownTables.length > 0 && !(registered && isStoredView(viewId, registered));
|
|
2706
|
-
const viewChanged = !!filtered || tablesChanged || currentLayout !== viewOpeningLayout(viewId);
|
|
2568
|
+
const canSaveView = shownTables.length > 0 && !(tableSet.registered && isStoredView(viewId, tableSet.registered));
|
|
2569
|
+
const viewChanged = !!filtered || tableSet.tablesChanged || currentLayout !== viewOpeningLayout(viewId);
|
|
2707
2570
|
const savedViewChanged = (!!shownSaved || !!shownSavedMulti) && canSaveView && viewChanged;
|
|
2708
2571
|
const isUserDefault = !!viewId && core.defaultViewId(saved.settings, offered, savedViewsControl) === viewId;
|
|
2709
|
-
const [savingView, setSavingView] = react.useState(false);
|
|
2710
|
-
const [nameDialog, setNameDialog] = react.useState(null);
|
|
2711
|
-
const [manageViewsOpen, setManageViewsOpen] = react.useState(false);
|
|
2712
2572
|
const currentQuery = async () => {
|
|
2713
2573
|
if (!showsAppointmentsAlone || !viewId) return void 0;
|
|
2714
2574
|
const own = filtered?.tables.find((x) => x.table === APPOINTMENT_TABLE);
|
|
@@ -2721,261 +2581,195 @@ function Calendar({
|
|
|
2721
2581
|
const tablesNow = filtered ? [...filtered.tables] : (await filterTablesAsync(viewId)).map((x) => x.table);
|
|
2722
2582
|
return core.shownViewTables(tablesNow, known, shownTables, (table) => !!response.tables?.find((info) => info.table === table)?.isActivity);
|
|
2723
2583
|
};
|
|
2724
|
-
const runSavedViewChange = async (change) => {
|
|
2725
|
-
if (savingView) return;
|
|
2726
|
-
setSavingView(true);
|
|
2727
|
-
try {
|
|
2728
|
-
await change();
|
|
2729
|
-
} catch (error) {
|
|
2730
|
-
console.warn("[Calendar] A change to the user\u2019s saved views failed.", error);
|
|
2731
|
-
await dialog.showErrorAsync(tAll("app.components.grid.saved-views-error"));
|
|
2732
|
-
} finally {
|
|
2733
|
-
setSavingView(false);
|
|
2734
|
-
}
|
|
2735
|
-
};
|
|
2736
|
-
const signedIn = async (action) => {
|
|
2737
|
-
if (!saved.needsSignIn) {
|
|
2738
|
-
await action();
|
|
2739
|
-
return;
|
|
2740
|
-
}
|
|
2741
|
-
const result = await dialog.showConfirmationAsync(tAll("app.components.grid.saved-views-sign-in-message"), {
|
|
2742
|
-
title: tAll("app.components.grid.saved-views-sign-in-title"),
|
|
2743
|
-
primaryText: tAll("app.buttons.login.label"),
|
|
2744
|
-
secondaryText: tAll("app.buttons.cancel.label")
|
|
2745
|
-
});
|
|
2746
|
-
if (result.canceled) return;
|
|
2747
|
-
const returnUrl = window.location.pathname + window.location.search + window.location.hash;
|
|
2748
|
-
window.location.assign(`${signInUrl}${signInUrl.includes("?") ? "&" : "?"}ReturnUrl=${encodeURIComponent(returnUrl)}`);
|
|
2749
|
-
};
|
|
2750
2584
|
const showSavedView = (id) => {
|
|
2751
|
-
|
|
2752
|
-
setHiddenChoice(null);
|
|
2585
|
+
tableSet.reset();
|
|
2753
2586
|
setPickedViewId(id);
|
|
2754
2587
|
persist({ viewId: id });
|
|
2755
2588
|
};
|
|
2756
|
-
const saveView = () => runSavedViewChange(async () => {
|
|
2757
|
-
if (shownSavedMulti) {
|
|
2758
|
-
const tables2 = await currentTables();
|
|
2759
|
-
if (tables2.length === 0) return;
|
|
2760
|
-
await multiSaved.update(shownSavedMulti.id, { tables: tables2, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2761
|
-
} else {
|
|
2762
|
-
if (!shownSaved) return;
|
|
2763
|
-
const fetchXml = await currentQuery();
|
|
2764
|
-
if (!fetchXml) return;
|
|
2765
|
-
await saved.update(shownSaved.id, { fetchXml, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2766
|
-
}
|
|
2767
|
-
setUserFilter(null);
|
|
2768
|
-
setHiddenChoice(null);
|
|
2769
|
-
});
|
|
2770
|
-
const saveViewAs = (name) => runSavedViewChange(async () => {
|
|
2771
|
-
const fetchXml = showsAppointmentsAlone ? await currentQuery() : void 0;
|
|
2772
|
-
if (fetchXml) {
|
|
2773
|
-
const view3 = await saved.create(name, fetchXml, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2774
|
-
showSavedView(view3.id.toLowerCase());
|
|
2775
|
-
return;
|
|
2776
|
-
}
|
|
2777
|
-
const tables2 = await currentTables();
|
|
2778
|
-
if (tables2.length === 0) return;
|
|
2779
|
-
const view2 = await multiSaved.create(name, tables2, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2780
|
-
showSavedView(view2.id.toLowerCase());
|
|
2781
|
-
});
|
|
2782
|
-
const cloneView = (id, name) => runSavedViewChange(async () => {
|
|
2783
|
-
const own = findSaved(id);
|
|
2784
|
-
const custom = findCustomView(id, customViewDefinitions)?.tables;
|
|
2785
|
-
const only = custom?.length === 1 && custom[0].table === APPOINTMENT_TABLE && (custom[0].viewType ?? core.MultiTableViewType.FetchXml) === core.MultiTableViewType.FetchXml ? custom[0].fetchXml ?? everyRow(APPOINTMENT_TABLE) : void 0;
|
|
2786
|
-
const ownMulti = findSavedMulti(id);
|
|
2787
|
-
const dataverse = own || only || ownMulti || custom ? void 0 : await viewMetadataCache.getAsync(id);
|
|
2788
|
-
const fetchXml = own?.definition.fetchXml ?? only ?? (dataverse?.tableName.toLowerCase() === APPOINTMENT_TABLE ? dataverse.fetchXml : void 0);
|
|
2789
|
-
if (fetchXml) {
|
|
2790
|
-
await saved.create(name, fetchXml, { gridLayout: own?.gridLayout, calendarLayout: own?.calendarLayout });
|
|
2791
|
-
return;
|
|
2792
|
-
}
|
|
2793
|
-
const tables2 = ownMulti?.tables ?? await viewTablesAsync(id) ?? (id === EVERY_TABLE_VIEW_ID ? known.map((table) => ({ table })) : null);
|
|
2794
|
-
if (!tables2 || tables2.length === 0) return;
|
|
2795
|
-
await multiSaved.create(name, tables2, { calendarLayout: ownMulti?.calendarLayout });
|
|
2796
|
-
});
|
|
2797
|
-
const renameView = (id, name) => runSavedViewChange(async () => void (findSavedMulti(id) ? await multiSaved.update(id, { name }) : await saved.update(id, { name })));
|
|
2798
|
-
const deleteView = async (id) => {
|
|
2799
|
-
const result = await dialog.showConfirmationAsync(
|
|
2800
|
-
tAll("app.components.grid.saved-views-delete-message", [findSaved(id)?.name ?? findSavedMulti(id)?.name ?? ""]),
|
|
2801
|
-
{
|
|
2802
|
-
title: tAll("app.components.grid.saved-views-delete-title"),
|
|
2803
|
-
primaryText: tAll("app.components.grid.saved-views-delete"),
|
|
2804
|
-
secondaryText: tAll("app.buttons.cancel.label")
|
|
2805
|
-
}
|
|
2806
|
-
);
|
|
2807
|
-
if (result.canceled) return;
|
|
2808
|
-
await runSavedViewChange(async () => {
|
|
2809
|
-
if (findSavedMulti(id)) {
|
|
2810
|
-
await multiSaved.remove(id);
|
|
2811
|
-
await saved.reloadSettings();
|
|
2812
|
-
} else {
|
|
2813
|
-
await saved.remove(id);
|
|
2814
|
-
}
|
|
2815
|
-
if (id.toLowerCase() === viewId) setUserFilter(null);
|
|
2816
|
-
});
|
|
2817
|
-
};
|
|
2818
|
-
const setDefault = (id, isDefault) => runSavedViewChange(() => saved.setDefault(id, isDefault, viewLabel(id)));
|
|
2819
|
-
const setHidden = (id, isHidden) => runSavedViewChange(() => saved.setHidden(id, isHidden, viewLabel(id)));
|
|
2820
2589
|
function viewLabel(id) {
|
|
2821
2590
|
return labelOf(id.toLowerCase()) ?? findSaved(id)?.name ?? findSavedMulti(id)?.name ?? id;
|
|
2822
2591
|
}
|
|
2823
|
-
const
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
id,
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
{
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
onOptionSelect: (_, data) => pickView(data.optionValue),
|
|
2854
|
-
children: viewOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Option, { value: option.id, text: option.label, children: option.label }, option.id))
|
|
2592
|
+
const session = reactFluent.useSavedViewSession({
|
|
2593
|
+
saved,
|
|
2594
|
+
signInUrl,
|
|
2595
|
+
operations: {
|
|
2596
|
+
shownViewId: viewId,
|
|
2597
|
+
savedViewName: (id) => findSaved(id)?.name ?? findSavedMulti(id)?.name,
|
|
2598
|
+
managedViewName: viewLabel,
|
|
2599
|
+
// Every view for the Manage views panel, the hidden ones among them.
|
|
2600
|
+
managedViews: () => {
|
|
2601
|
+
const all = [.../* @__PURE__ */ new Set([...pageViews, ...savedIds.map((x) => x.toLowerCase())])];
|
|
2602
|
+
const userDefault = core.defaultViewId(saved.settings, all, savedViewsControl);
|
|
2603
|
+
return all.map((id) => ({
|
|
2604
|
+
id,
|
|
2605
|
+
name: viewLabel(id),
|
|
2606
|
+
isSaved: !!findSaved(id) || !!findSavedMulti(id),
|
|
2607
|
+
isDefault: id === userDefault,
|
|
2608
|
+
isHidden: core.isViewHidden(saved.settings, id, savedViewsControl),
|
|
2609
|
+
isShown: id === viewId
|
|
2610
|
+
}));
|
|
2611
|
+
},
|
|
2612
|
+
save: async () => {
|
|
2613
|
+
if (shownSavedMulti) {
|
|
2614
|
+
const tables2 = await currentTables();
|
|
2615
|
+
if (tables2.length === 0) return;
|
|
2616
|
+
await multiSaved.update(shownSavedMulti.id, { tables: tables2, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2617
|
+
} else {
|
|
2618
|
+
if (!shownSaved) return;
|
|
2619
|
+
const fetchXml = await currentQuery();
|
|
2620
|
+
if (!fetchXml) return;
|
|
2621
|
+
await saved.update(shownSaved.id, { fetchXml, calendarLayout: writeSavedLayout(currentLayout) });
|
|
2855
2622
|
}
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2623
|
+
tableSet.reset();
|
|
2624
|
+
},
|
|
2625
|
+
saveAs: async (name) => {
|
|
2626
|
+
const fetchXml = showsAppointmentsAlone ? await currentQuery() : void 0;
|
|
2627
|
+
if (fetchXml) {
|
|
2628
|
+
const view3 = await saved.create(name, fetchXml, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2629
|
+
showSavedView(view3.id.toLowerCase());
|
|
2630
|
+
return;
|
|
2631
|
+
}
|
|
2632
|
+
const tables2 = await currentTables();
|
|
2633
|
+
if (tables2.length === 0) return;
|
|
2634
|
+
const view2 = await multiSaved.create(name, tables2, { calendarLayout: writeSavedLayout(currentLayout) });
|
|
2635
|
+
showSavedView(view2.id.toLowerCase());
|
|
2636
|
+
},
|
|
2637
|
+
clone: async (id, name) => {
|
|
2638
|
+
const own = findSaved(id);
|
|
2639
|
+
const custom = findCustomView(id, customViewDefinitions)?.tables;
|
|
2640
|
+
const only = custom?.length === 1 && custom[0].table === APPOINTMENT_TABLE && (custom[0].viewType ?? core.MultiTableViewType.FetchXml) === core.MultiTableViewType.FetchXml ? custom[0].fetchXml ?? reactFluent.everyRow(APPOINTMENT_TABLE) : void 0;
|
|
2641
|
+
const ownMulti = findSavedMulti(id);
|
|
2642
|
+
const dataverse = own || only || ownMulti || custom ? void 0 : await viewMetadataCache.getAsync(id);
|
|
2643
|
+
const fetchXml = own?.definition.fetchXml ?? only ?? (dataverse?.tableName.toLowerCase() === APPOINTMENT_TABLE ? dataverse.fetchXml : void 0);
|
|
2644
|
+
if (fetchXml) {
|
|
2645
|
+
await saved.create(name, fetchXml, { gridLayout: own?.gridLayout, calendarLayout: own?.calendarLayout });
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
const tables2 = ownMulti?.tables ?? await viewTablesAsync(id) ?? (id === reactFluent.EVERY_TABLE_VIEW_ID ? known.map((table) => ({ table })) : null);
|
|
2649
|
+
if (!tables2 || tables2.length === 0) return;
|
|
2650
|
+
await multiSaved.create(name, tables2, { calendarLayout: ownMulti?.calendarLayout });
|
|
2651
|
+
},
|
|
2652
|
+
rename: async (id, name) => void (findSavedMulti(id) ? await multiSaved.update(id, { name }) : await saved.update(id, { name })),
|
|
2653
|
+
remove: async (id) => {
|
|
2654
|
+
if (findSavedMulti(id)) {
|
|
2655
|
+
await multiSaved.remove(id);
|
|
2656
|
+
await saved.reloadSettings();
|
|
2657
|
+
} else {
|
|
2658
|
+
await saved.remove(id);
|
|
2659
|
+
}
|
|
2660
|
+
if (id.toLowerCase() === viewId) tableSet.clearFilter();
|
|
2661
|
+
},
|
|
2662
|
+
openView: (id) => pickView(id)
|
|
2663
|
+
}
|
|
2664
|
+
});
|
|
2665
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.root, style: { height }, children: [
|
|
2666
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2667
|
+
reactFluent.ViewToolbar,
|
|
2668
|
+
{
|
|
2669
|
+
className: "ppp-calendar-toolbar",
|
|
2670
|
+
ariaLabel: t("toolbar"),
|
|
2671
|
+
start: showsViewPicker && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2672
|
+
reactFluent.ViewPicker,
|
|
2673
|
+
{
|
|
2674
|
+
className: "ppp-calendar-view-picker",
|
|
2675
|
+
options: viewOptions,
|
|
2676
|
+
sort: viewSort,
|
|
2677
|
+
value: viewId,
|
|
2678
|
+
onChange: pickView,
|
|
2679
|
+
isUserView: (id) => saved.available && (!!findSaved(id) || !!findSavedMulti(id))
|
|
2680
|
+
}
|
|
2681
|
+
),
|
|
2682
|
+
children: [
|
|
2683
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: reactComponents.mergeClasses("ppp-calendar-navigation", styles.navigation), children: [
|
|
2684
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2685
|
+
reactComponents.ToolbarButton,
|
|
2686
|
+
{
|
|
2687
|
+
appearance: "subtle",
|
|
2688
|
+
disabled: buttons?.today?.isDisabled ?? false,
|
|
2689
|
+
onClick: () => controller.today(),
|
|
2690
|
+
children: t("today")
|
|
2691
|
+
}
|
|
2692
|
+
),
|
|
2693
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2694
|
+
reactComponents.ToolbarButton,
|
|
2695
|
+
{
|
|
2696
|
+
appearance: "subtle",
|
|
2697
|
+
icon: direction === "rtl" ? /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ChevronRightRegular, {}) : /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ChevronLeftRegular, {}),
|
|
2698
|
+
"aria-label": t("previous"),
|
|
2699
|
+
onClick: () => controller.prev()
|
|
2700
|
+
}
|
|
2701
|
+
),
|
|
2702
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2703
|
+
reactComponents.ToolbarButton,
|
|
2704
|
+
{
|
|
2705
|
+
appearance: "subtle",
|
|
2706
|
+
icon: direction === "rtl" ? /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ChevronLeftRegular, {}) : /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ChevronRightRegular, {}),
|
|
2707
|
+
"aria-label": t("next"),
|
|
2708
|
+
onClick: () => controller.next()
|
|
2709
|
+
}
|
|
2710
|
+
),
|
|
2711
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { className: styles.title, as: "h2", "aria-live": "polite", children: view?.title })
|
|
2712
|
+
] }),
|
|
2713
|
+
children !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(CalendarContext.Provider, { value: calendarContext, children }),
|
|
2714
|
+
layoutsOffered.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.Menu, { checkedValues: { layout: [currentLayout] }, onCheckedValueChange: onLayoutChecked, children: [
|
|
2715
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuButton, { className: "ppp-calendar-layout", appearance: "subtle", children: t(layoutKeys[currentLayout]) }) }),
|
|
2716
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuPopover, { children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuList, { children: layoutsOffered.map((layout) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "layout", value: layout, children: t(layoutKeys[layout]) }, layout)) }) })
|
|
2717
|
+
] }),
|
|
2718
|
+
showsSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2719
|
+
reactFluent.ViewSearchBox,
|
|
2861
2720
|
{
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2721
|
+
className: reactComponents.mergeClasses("ppp-calendar-search", styles.search),
|
|
2722
|
+
placeholder: t("search-placeholder"),
|
|
2723
|
+
value: search,
|
|
2724
|
+
onChange: searchFor
|
|
2866
2725
|
}
|
|
2867
2726
|
),
|
|
2868
2727
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2869
|
-
|
|
2728
|
+
reactFluent.ViewFilterMenu,
|
|
2870
2729
|
{
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2730
|
+
changed: viewChanged,
|
|
2731
|
+
onEditFilters: showsFilterButton ? () => void openFilter() : void 0,
|
|
2732
|
+
tables: appointments ? void 0 : tableSet.menuTables(tableLabel),
|
|
2733
|
+
onTableShownChange: tableSet.showTable,
|
|
2734
|
+
savedViews: session.menu({
|
|
2735
|
+
canSave: savedViewChanged,
|
|
2736
|
+
canSaveAs: canSaveView && viewChanged,
|
|
2737
|
+
canSetDefault: !!viewId && !isUserDefault
|
|
2738
|
+
})
|
|
2875
2739
|
}
|
|
2876
2740
|
),
|
|
2877
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2878
|
-
|
|
2741
|
+
!appointments && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2742
|
+
reactFluent.ViewRefreshButton,
|
|
2879
2743
|
{
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
onClick: () => controller.next()
|
|
2744
|
+
className: "ppp-calendar-refresh",
|
|
2745
|
+
disabled: loading,
|
|
2746
|
+
onClick: () => setRefreshes((count) => count + 1)
|
|
2884
2747
|
}
|
|
2885
|
-
)
|
|
2886
|
-
|
|
2887
|
-
] }),
|
|
2888
|
-
children !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(CalendarContext.Provider, { value: calendarContext, children }),
|
|
2889
|
-
layoutsOffered.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.Menu, { checkedValues: { layout: [currentLayout] }, onCheckedValueChange: onLayoutChecked, children: [
|
|
2890
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuButton, { className: "ppp-calendar-layout", appearance: "subtle", children: t(layoutKeys[currentLayout]) }) }),
|
|
2891
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuPopover, { children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuList, { children: layoutsOffered.map((layout) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "layout", value: layout, children: t(layoutKeys[layout]) }, layout)) }) })
|
|
2892
|
-
] }),
|
|
2893
|
-
showsSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2894
|
-
reactComponents.SearchBox,
|
|
2895
|
-
{
|
|
2896
|
-
className: reactComponents.mergeClasses("ppp-calendar-search", styles.search),
|
|
2897
|
-
placeholder: t("search-placeholder"),
|
|
2898
|
-
"aria-label": t("search-placeholder"),
|
|
2899
|
-
value: searchText,
|
|
2900
|
-
onChange: (_, data) => setSearchText(data.value)
|
|
2901
|
-
}
|
|
2902
|
-
),
|
|
2903
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2904
|
-
reactFluent.ViewFilterMenu,
|
|
2905
|
-
{
|
|
2906
|
-
changed: viewChanged,
|
|
2907
|
-
onEditFilters: showsFilterButton ? () => void openFilter() : void 0,
|
|
2908
|
-
tables: appointments ? void 0 : kinds.map((table) => ({ table, label: tableLabel(table), shown: !hidden.includes(table) })),
|
|
2909
|
-
onTableShownChange: showTable,
|
|
2910
|
-
savedViews: showsSavedViewsMenu ? {
|
|
2911
|
-
canSave: savedViewChanged,
|
|
2912
|
-
canSaveAs: canSaveView && viewChanged,
|
|
2913
|
-
canSetDefault: !!viewId && !isUserDefault,
|
|
2914
|
-
busy: savingView,
|
|
2915
|
-
onSave: () => void signedIn(saveView),
|
|
2916
|
-
onSaveAs: () => void signedIn(() => setNameDialog({ kind: "saveAs", viewId: viewId ?? "", name: "" })),
|
|
2917
|
-
onSetDefault: () => void signedIn(() => viewId ? setDefault(viewId, true) : void 0),
|
|
2918
|
-
onManage: () => void signedIn(() => setManageViewsOpen(true))
|
|
2919
|
-
} : void 0
|
|
2920
|
-
}
|
|
2921
|
-
),
|
|
2922
|
-
!appointments && /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Tooltip, { content: tAll("app.buttons.refresh.label"), relationship: "label", withArrow: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2923
|
-
reactComponents.ToolbarButton,
|
|
2924
|
-
{
|
|
2925
|
-
className: "ppp-calendar-refresh",
|
|
2926
|
-
appearance: "subtle",
|
|
2927
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.ArrowClockwiseRegular, {}),
|
|
2928
|
-
disabled: loading,
|
|
2929
|
-
onClick: () => setRefreshes((count) => count + 1)
|
|
2930
|
-
}
|
|
2931
|
-
) })
|
|
2932
|
-
] })
|
|
2933
|
-
] }),
|
|
2934
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2935
|
-
reactFluent.GridSaveViewDialog,
|
|
2936
|
-
{
|
|
2937
|
-
open: nameDialog !== null,
|
|
2938
|
-
title: tAll(
|
|
2939
|
-
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"
|
|
2940
|
-
),
|
|
2941
|
-
name: nameDialog?.name ?? "",
|
|
2942
|
-
onSave: onNameDialogSave,
|
|
2943
|
-
onCancel: () => setNameDialog(null)
|
|
2748
|
+
)
|
|
2749
|
+
]
|
|
2944
2750
|
}
|
|
2945
2751
|
),
|
|
2946
|
-
|
|
2947
|
-
|
|
2752
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFluent.SavedViewDialogs, { session }),
|
|
2753
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2754
|
+
reactFluent.MultiTableFilterDialog,
|
|
2948
2755
|
{
|
|
2949
|
-
open:
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
setManageViewsOpen(false);
|
|
2955
|
-
pickView(id);
|
|
2956
|
-
},
|
|
2957
|
-
onSetDefault: (id, isDefault) => void setDefault(id, isDefault),
|
|
2958
|
-
onSetHidden: (id, isHidden) => void setHidden(id, isHidden),
|
|
2959
|
-
onRename: (id) => setNameDialog({ kind: "rename", viewId: id, name: findSaved(id)?.name ?? findSavedMulti(id)?.name ?? "" }),
|
|
2960
|
-
onClone: (id) => setNameDialog({ kind: "clone", viewId: id, name: tAll("app.components.grid.saved-views-copy-of", [viewLabel(id)]) }),
|
|
2961
|
-
onDelete: (id) => void deleteView(id)
|
|
2756
|
+
open: tableSet.filterDialog !== null,
|
|
2757
|
+
tabs: tableSet.filterDialog?.tabs ?? [],
|
|
2758
|
+
viewTabs: tableSet.filterDialog?.viewTabs,
|
|
2759
|
+
onApply: applyFilter,
|
|
2760
|
+
onCancel: tableSet.closeFilter
|
|
2962
2761
|
}
|
|
2963
2762
|
),
|
|
2964
2763
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2965
|
-
reactFluent.
|
|
2764
|
+
reactFluent.ViewLoadMessages,
|
|
2966
2765
|
{
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2766
|
+
failed,
|
|
2767
|
+
errorText: t("error"),
|
|
2768
|
+
failedTables: failures.length > 0 ? t("failed-tables", [failures.map((x) => tableLabel(x.table ?? "")).join(", ")]) : null,
|
|
2769
|
+
retryText: t("retry"),
|
|
2770
|
+
onRetry: () => setRefreshes((count) => count + 1)
|
|
2972
2771
|
}
|
|
2973
2772
|
),
|
|
2974
|
-
failed ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBar, { intent: "error", children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBarBody, { children: t("error") }) }) : failures.length > 0 && // A table that couldn't be read leaves the rest of the range as it is.
|
|
2975
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactComponents.MessageBar, { intent: "warning", children: [
|
|
2976
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBarBody, { children: t("failed-tables", [failures.map((x) => tableLabel(x.table ?? "")).join(", ")]) }),
|
|
2977
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBarActions, { children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Button, { size: "small", onClick: () => setRefreshes((count) => count + 1), children: t("retry") }) })
|
|
2978
|
-
] }),
|
|
2979
2773
|
truncated && /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBar, { intent: "warning", children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MessageBarBody, { children: t("truncated") }) }),
|
|
2980
2774
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.body, children: [
|
|
2981
2775
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.surface, children: viewSettled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3037,6 +2831,8 @@ function Calendar({
|
|
|
3037
2831
|
editable,
|
|
3038
2832
|
regardingTables,
|
|
3039
2833
|
location: dialogLocation,
|
|
2834
|
+
showRecordLinks,
|
|
2835
|
+
onNavigate,
|
|
3040
2836
|
onClose: () => {
|
|
3041
2837
|
setOpenAppointment(null);
|
|
3042
2838
|
setCreating(null);
|