@headless-adminapp/fluent 1.1.11 → 1.2.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/DataGrid/GridHeaderDesktop.js +15 -10
- package/DataGrid/GridQuickFilterDesktop.d.ts +2 -0
- package/DataGrid/GridQuickFilterDesktop.js +22 -0
- package/DataGrid/useTableColumns.js +12 -1
- package/Insights/charts/PieChart.js +1 -1
- package/PageBoard/Header.js +12 -7
- package/PageBoard/HeaderQuickFilter.d.ts +2 -0
- package/PageBoard/HeaderQuickFilter.js +21 -0
- package/PageBoard/PageBoard.js +2 -0
- package/PageCalendar/CalendarSection.d.ts +2 -3
- package/PageCalendar/CalendarSection.js +2 -2
- package/PageCalendar/EventDialog/EventDialog.d.ts +0 -3
- package/PageCalendar/EventDialog/EventDialog.js +1 -1
- package/PageCalendar/EventDialog/EventFormBody.d.ts +0 -3
- package/PageCalendar/EventDialog/EventFormBody.js +3 -14
- package/PageCalendar/Header.js +2 -1
- package/PageCalendar/PageCalendar.js +3 -219
- package/PageCalendar/PageCalendarUI.d.ts +2 -0
- package/PageCalendar/PageCalendarUI.js +169 -0
- package/PageCalendar/renderEventContent.js +91 -15
- package/PageEntityForm/EditableGridControl/EditableGridControl.d.ts +7 -0
- package/PageEntityForm/EditableGridControl/EditableGridControl.js +133 -0
- package/PageEntityForm/EditableGridControl/TableUi.d.ts +15 -0
- package/PageEntityForm/EditableGridControl/TableUi.js +64 -0
- package/PageEntityForm/EditableGridControl/index.d.ts +1 -0
- package/PageEntityForm/EditableGridControl/index.js +5 -0
- package/PageEntityForm/RecordCard.js +2 -15
- package/PageEntityForm/RecordSetNavigatorContainer.js +4 -0
- package/PageEntityForm/SectionContainer.js +8 -1
- package/components/ChoiceBadge.d.ts +3 -2
- package/components/ChoiceBadge.js +15 -2
- package/form/AttributeController.d.ts +2 -1
- package/form/AttributeController.js +2 -2
- package/package.json +2 -2
|
@@ -10,6 +10,7 @@ const react_1 = require("react");
|
|
|
10
10
|
const AppStringContext_1 = require("../App/AppStringContext");
|
|
11
11
|
const PageEntityViewStringContext_1 = require("../PageEntityView/PageEntityViewStringContext");
|
|
12
12
|
const CustomizeColumns_1 = require("./CustomizeColumns");
|
|
13
|
+
const GridQuickFilterDesktop_1 = require("./GridQuickFilterDesktop");
|
|
13
14
|
const GridHeaderDesktop = (props) => {
|
|
14
15
|
const viewLookup = (0, hooks_1.useGridViewLookupData)();
|
|
15
16
|
const selectedView = (0, hooks_1.useSelectedView)();
|
|
@@ -20,19 +21,23 @@ const GridHeaderDesktop = (props) => {
|
|
|
20
21
|
const strings = (0, PageEntityViewStringContext_1.usePageEntityViewStrings)();
|
|
21
22
|
const appStrings = (0, AppStringContext_1.useAppStrings)();
|
|
22
23
|
return ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
paddingInline: 8,
|
|
25
|
-
gap: 16,
|
|
26
24
|
display: 'flex',
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
flexDirection: 'column',
|
|
26
|
+
gap: 8,
|
|
27
|
+
paddingInline: 8,
|
|
28
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
29
29
|
alignItems: 'center',
|
|
30
30
|
gap: 16,
|
|
31
|
-
justifyContent: 'space-between',
|
|
32
31
|
display: 'flex',
|
|
33
|
-
}, children: (0, jsx_runtime_1.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
}, children: [(0, jsx_runtime_1.jsx)(CustomizeColumns_1.CustomizeColumns, { opened: isColumnCustomizationOpen, onClose: () => setIsColumnCustomizationOpen(false) }), (0, jsx_runtime_1.jsx)("div", { style: {
|
|
33
|
+
flex: 1,
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
gap: 16,
|
|
36
|
+
justifyContent: 'space-between',
|
|
37
|
+
display: 'flex',
|
|
38
|
+
}, children: (0, jsx_runtime_1.jsxs)(react_components_1.Menu, { children: [(0, jsx_runtime_1.jsx)(react_components_1.MenuTrigger, { children: (0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "subtle", icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.ChevronDown, {}), iconPosition: "after", style: {
|
|
39
|
+
fontSize: react_components_1.tokens.fontSizeBase400,
|
|
40
|
+
fontWeight: react_components_1.tokens.fontWeightMedium,
|
|
41
|
+
}, children: selectedView.localizedNames?.[language] ?? selectedView.name }) }), (0, jsx_runtime_1.jsx)(react_components_1.MenuPopover, { children: (0, jsx_runtime_1.jsx)(react_components_1.MenuList, { children: viewLookup.map((view) => ((0, jsx_runtime_1.jsx)(react_components_1.MenuItem, { onClick: () => changeView(view.id), children: view.localizedNames?.[language] ?? view.name }, view.id))) }) })] }) }), (0, jsx_runtime_1.jsxs)("div", { style: { alignItems: 'center', display: 'flex', gap: 16 }, children: [props.headingRight, (0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "subtle", icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.EditColumns, { size: 24 }), onClick: () => setIsColumnCustomizationOpen(true), children: strings.editColumns }), (0, jsx_runtime_1.jsx)(react_components_1.Input, { contentBefore: (0, jsx_runtime_1.jsx)(icons_1.Icons.Search, { size: 16 }), placeholder: appStrings.searchPlaceholder, value: searchText, onChange: (e) => setSearchText(e.target.value), appearance: "filled-darker" })] })] }), (0, jsx_runtime_1.jsx)(GridQuickFilterDesktop_1.GridQuickFilterDesktop, {})] }));
|
|
37
42
|
};
|
|
38
43
|
exports.GridHeaderDesktop = GridHeaderDesktop;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GridQuickFilterDesktop = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const useQuickFilter_1 = require("@headless-adminapp/app/datagrid/hooks/useQuickFilter");
|
|
7
|
+
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
8
|
+
const StandardControl_1 = require("../PageEntityForm/StandardControl");
|
|
9
|
+
const GridQuickFilterDesktop = () => {
|
|
10
|
+
const [quickFilter, values, setValue] = (0, useQuickFilter_1.useQuickFilter)();
|
|
11
|
+
if (!quickFilter) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
15
|
+
display: 'flex',
|
|
16
|
+
gap: react_components_1.tokens.spacingHorizontalS,
|
|
17
|
+
paddingInline: react_components_1.tokens.spacingHorizontalM,
|
|
18
|
+
}, children: Object.entries(quickFilter.attributes).map(([key, attribute]) => {
|
|
19
|
+
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(SectionControl_1.SectionControlWrapper, { label: attribute.label, labelHidden: true, labelPosition: "top", children: (0, jsx_runtime_1.jsx)(StandardControl_1.StandardControl, { attribute: attribute, name: key, value: values[key] ?? null, onChange: (value) => setValue(key, value) }) }) }, key));
|
|
20
|
+
}) }));
|
|
21
|
+
};
|
|
22
|
+
exports.GridQuickFilterDesktop = GridQuickFilterDesktop;
|
|
@@ -287,7 +287,18 @@ function renderCellContent({ info, column, schema, schemaStore, locale, routeRes
|
|
|
287
287
|
return ((0, jsx_runtime_1.jsx)(TableCell_1.TableCellText, { value: formattedValue, width: info.column.getSize() }, column.id));
|
|
288
288
|
}
|
|
289
289
|
if (column.component) {
|
|
290
|
-
|
|
290
|
+
let Component;
|
|
291
|
+
if (column.component) {
|
|
292
|
+
if (typeof column.component === 'function') {
|
|
293
|
+
Component = column.component;
|
|
294
|
+
}
|
|
295
|
+
else if (typeof column.component === 'string') {
|
|
296
|
+
const OverrideControl = componentStore_1.componentStore.getComponent(column.component);
|
|
297
|
+
if (OverrideControl) {
|
|
298
|
+
Component = OverrideControl;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
291
302
|
if (!Component) {
|
|
292
303
|
throw new Error(`Component with name ${column.component} not found`);
|
|
293
304
|
}
|
|
@@ -29,7 +29,7 @@ function PieChart({ dataset, chartInfo, }) {
|
|
|
29
29
|
overflow: 'auto',
|
|
30
30
|
top: 5,
|
|
31
31
|
bottom: 5,
|
|
32
|
-
} })), (0, jsx_runtime_1.jsx)(recharts_1.Tooltip, { cursor: {
|
|
32
|
+
}, formatter: nameFormatter })), (0, jsx_runtime_1.jsx)(recharts_1.Tooltip, { cursor: {
|
|
33
33
|
stroke: react_components_1.tokens.colorNeutralBackground6,
|
|
34
34
|
opacity: 0.5,
|
|
35
35
|
}, content: ({ payload }) => renderTooltipContent({
|
package/PageBoard/Header.js
CHANGED
|
@@ -8,6 +8,7 @@ const hooks_2 = require("@headless-adminapp/app/hooks");
|
|
|
8
8
|
const icons_1 = require("@headless-adminapp/icons");
|
|
9
9
|
const react_query_1 = require("@tanstack/react-query");
|
|
10
10
|
const AppStringContext_1 = require("../App/AppStringContext");
|
|
11
|
+
const HeaderQuickFilter_1 = require("./HeaderQuickFilter");
|
|
11
12
|
const Header = ({ title, subtitle }) => {
|
|
12
13
|
const client = (0, react_query_1.useQueryClient)();
|
|
13
14
|
const schema = (0, hooks_1.useBoardSchema)();
|
|
@@ -21,13 +22,17 @@ const Header = ({ title, subtitle }) => {
|
|
|
21
22
|
};
|
|
22
23
|
return ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
23
24
|
display: 'flex',
|
|
24
|
-
flexDirection:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}, children: [(0, jsx_runtime_1.jsx)("div", { style: { flex: 1 }, children: (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column' }, children: [(0, jsx_runtime_1.jsx)(react_components_1.Subtitle2, { style: { color: react_components_1.tokens.colorNeutralForeground1 }, children: title }), (0, jsx_runtime_1.jsx)(react_components_1.Caption1, { style: { color: react_components_1.tokens.colorNeutralForeground2 }, children: subtitle })] }) }) }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
25
|
+
flexDirection: 'column',
|
|
26
|
+
gap: 16,
|
|
27
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
28
28
|
display: 'flex',
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
flexDirection: isMobile ? 'column' : 'row',
|
|
30
|
+
alignItems: isMobile ? 'flex-start' : 'center',
|
|
31
|
+
gap: react_components_1.tokens.spacingHorizontalM,
|
|
32
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: { flex: 1 }, children: (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column' }, children: [(0, jsx_runtime_1.jsx)(react_components_1.Subtitle2, { style: { color: react_components_1.tokens.colorNeutralForeground1 }, children: title }), (0, jsx_runtime_1.jsx)(react_components_1.Caption1, { style: { color: react_components_1.tokens.colorNeutralForeground2 }, children: subtitle })] }) }) }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
33
|
+
display: 'flex',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
gap: react_components_1.tokens.spacingHorizontalS,
|
|
36
|
+
}, children: [(0, jsx_runtime_1.jsx)(react_components_1.SearchBox, { appearance: "filled-darker", placeholder: appStrings.searchPlaceholder, value: searchText, onChange: (e, data) => setSearchText(data.value) }), (0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "subtle", icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Refresh, { size: 20 }), onClick: refresh })] })] }), (0, jsx_runtime_1.jsx)(HeaderQuickFilter_1.HeaderQuickFilter, {})] }));
|
|
32
37
|
};
|
|
33
38
|
exports.Header = Header;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HeaderQuickFilter = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const useQuickFilter_1 = require("@headless-adminapp/app/board/hooks/useQuickFilter");
|
|
7
|
+
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
8
|
+
const StandardControl_1 = require("../PageEntityForm/StandardControl");
|
|
9
|
+
const HeaderQuickFilter = () => {
|
|
10
|
+
const [quickFilter, values, setValue] = (0, useQuickFilter_1.useQuickFilter)();
|
|
11
|
+
if (!quickFilter) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
15
|
+
display: 'flex',
|
|
16
|
+
gap: react_components_1.tokens.spacingHorizontalS,
|
|
17
|
+
}, children: Object.entries(quickFilter.attributes).map(([key, attribute]) => {
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(SectionControl_1.SectionControlWrapper, { label: attribute.label, labelHidden: true, labelPosition: "top", children: (0, jsx_runtime_1.jsx)(StandardControl_1.StandardControl, { attribute: attribute, name: key, value: values[key] ?? null, onChange: (value) => setValue(key, value) }) }) }, key));
|
|
19
|
+
}) }));
|
|
20
|
+
};
|
|
21
|
+
exports.HeaderQuickFilter = HeaderQuickFilter;
|
package/PageBoard/PageBoard.js
CHANGED
|
@@ -14,11 +14,13 @@ function PageBoard(props) {
|
|
|
14
14
|
const contextValue = (0, context_2.useCreateContextStore)({
|
|
15
15
|
config: props.config,
|
|
16
16
|
searchText: '',
|
|
17
|
+
quickFilterValues: props.config.quickFilter?.defaultValues ?? {},
|
|
17
18
|
});
|
|
18
19
|
(0, react_1.useEffect)(() => {
|
|
19
20
|
contextValue.setValue({
|
|
20
21
|
config: props.config,
|
|
21
22
|
searchText: '',
|
|
23
|
+
quickFilterValues: props.config.quickFilter?.defaultValues ?? {},
|
|
22
24
|
});
|
|
23
25
|
}, [contextValue, props.config]);
|
|
24
26
|
return ((0, jsx_runtime_1.jsx)(context_1.BoardContext.Provider, { value: contextValue, children: (0, jsx_runtime_1.jsx)(DndProvider_1.DndProvider, { children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DateSelectArg,
|
|
1
|
+
import { DateSelectArg, EventInput } from '@fullcalendar/core';
|
|
2
2
|
import { ViewType } from './types';
|
|
3
3
|
interface CalendarSectionProps {
|
|
4
4
|
startDate: Date | null;
|
|
@@ -12,9 +12,8 @@ interface CalendarSectionProps {
|
|
|
12
12
|
viewType: ViewType;
|
|
13
13
|
}) => void;
|
|
14
14
|
events: EventInput[];
|
|
15
|
-
onEventClick?: (event: EventClickArg) => void;
|
|
16
15
|
onDateSelect?: (event: DateSelectArg) => void;
|
|
17
16
|
loading?: boolean;
|
|
18
17
|
}
|
|
19
|
-
export declare const CalendarSection: ({ startDate, endDate, viewType, onRangeChange, events, onDateSelect,
|
|
18
|
+
export declare const CalendarSection: ({ startDate, endDate, viewType, onRangeChange, events, onDateSelect, loading, }: Readonly<CalendarSectionProps>) => import("react/jsx-runtime").JSX.Element;
|
|
20
19
|
export {};
|
|
@@ -26,7 +26,7 @@ const ViewSelector_1 = require("./ViewSelector");
|
|
|
26
26
|
dayjs_1.default.extend(utc_1.default);
|
|
27
27
|
dayjs_1.default.extend(timezone_1.default);
|
|
28
28
|
dayjs_1.default.extend(isoWeek_1.default);
|
|
29
|
-
const CalendarSection = ({ startDate, endDate, viewType, onRangeChange, events, onDateSelect,
|
|
29
|
+
const CalendarSection = ({ startDate, endDate, viewType, onRangeChange, events, onDateSelect, loading, }) => {
|
|
30
30
|
const calendarRef = (0, react_2.useRef)(null);
|
|
31
31
|
const { timezone } = (0, locale_1.useLocale)();
|
|
32
32
|
const isMobile = (0, hooks_1.useIsMobile)();
|
|
@@ -130,7 +130,7 @@ const CalendarSection = ({ startDate, endDate, viewType, onRangeChange, events,
|
|
|
130
130
|
}, children: (0, jsx_runtime_1.jsx)(ViewSelector_1.ViewSelector, { viewType: viewType, onChange: (viewType) => {
|
|
131
131
|
calendarRef.current?.getApi().changeView(viewType);
|
|
132
132
|
calendarRef.current?.getApi().scrollToTime(initialScrollTime);
|
|
133
|
-
} }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { flex: 1, position: 'relative' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', inset: 0 }, children: (0, jsx_runtime_1.jsx)(react_1.default, { ref: calendarRef, plugins: [daygrid_1.default, timegrid_1.default, interaction_1.default], initialView: types_1.ViewType.Month, weekends: true, firstDay: 1, events: events, datesSet: handleDateRangeChange, select: onDateSelect,
|
|
133
|
+
} }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { flex: 1, position: 'relative' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', inset: 0 }, children: (0, jsx_runtime_1.jsx)(react_1.default, { ref: calendarRef, plugins: [daygrid_1.default, timegrid_1.default, interaction_1.default], initialView: types_1.ViewType.Month, weekends: true, firstDay: 1, events: events, datesSet: handleDateRangeChange, select: onDateSelect, eventContent: renderEventContent_1.renderEventContent, timeZone: timezone, height: "100%", nowIndicator: true, scrollTime: initialScrollTime, scrollTimeReset: false, editable: false, selectable: true, selectMirror: true, dayMaxEvents: true, eventMinHeight: 24, eventTimeFormat: (props) => {
|
|
134
134
|
return (0, dayjs_1.default)(props.start.marker).tz(timezone).format('hh:mm A');
|
|
135
135
|
}, headerToolbar: false }) }), (0, jsx_runtime_1.jsx)(BodyLoading_1.BodyLoading, { loading: loading })] })] }));
|
|
136
136
|
};
|
|
@@ -15,9 +15,6 @@ interface EventDialogProps<SA1 extends SchemaAttributes = SchemaAttributes, SA2
|
|
|
15
15
|
}) => Promise<void>;
|
|
16
16
|
onCancel?: () => void;
|
|
17
17
|
onDismiss?: () => void;
|
|
18
|
-
allowOpenRecord?: boolean;
|
|
19
|
-
onOpenRecord?: (id: string) => void;
|
|
20
|
-
onDelete?: (id: string) => void;
|
|
21
18
|
eventResolver?: CalendarEventResolverFn;
|
|
22
19
|
config: CalendarConfig;
|
|
23
20
|
}
|
|
@@ -17,5 +17,5 @@ function defineEventAttributes(beforeDescriptionAttributes, afterDescriptionAttr
|
|
|
17
17
|
function EventDialog(props) {
|
|
18
18
|
return ((0, jsx_runtime_1.jsx)(react_components_1.Dialog, { open: props.isOpen, onOpenChange: () => {
|
|
19
19
|
props.onDismiss?.();
|
|
20
|
-
}, children: (0, jsx_runtime_1.jsx)(react_components_1.DialogSurface, { style: { maxWidth: 480 }, children: (0, jsx_runtime_1.jsx)(EventFormBody_1.EventFormBody, { values: props.values, config: props.config, onCancel: props.onCancel, onSubmit: props.onSubmit
|
|
20
|
+
}, children: (0, jsx_runtime_1.jsx)(react_components_1.DialogSurface, { style: { maxWidth: 480 }, children: (0, jsx_runtime_1.jsx)(EventFormBody_1.EventFormBody, { values: props.values, config: props.config, onCancel: props.onCancel, onSubmit: props.onSubmit }) }) }));
|
|
21
21
|
}
|
|
@@ -9,9 +9,6 @@ interface EventFormBodyProps<SA1 extends SchemaAttributes = SchemaAttributes, SA
|
|
|
9
9
|
values: Nullable<InferredSchemaType<BaseEventAttributes>>;
|
|
10
10
|
}) => Promise<void>;
|
|
11
11
|
onCancel?: () => void;
|
|
12
|
-
allowOpenRecord?: boolean;
|
|
13
|
-
onOpenRecord?: (id: string) => void;
|
|
14
|
-
onDelete?: (id: string) => void;
|
|
15
12
|
config: CalendarConfig;
|
|
16
13
|
}
|
|
17
14
|
export declare function EventFormBody(props: Readonly<EventFormBodyProps>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,7 +7,6 @@ const baseEventAttributes_1 = require("@headless-adminapp/app/calendar/baseEvent
|
|
|
7
7
|
const saveRecord_1 = require("@headless-adminapp/app/dataform/utils/saveRecord");
|
|
8
8
|
const form_1 = require("@headless-adminapp/app/form");
|
|
9
9
|
const locale_1 = require("@headless-adminapp/app/locale");
|
|
10
|
-
const icons_fluent_1 = require("@headless-adminapp/icons-fluent");
|
|
11
10
|
const react_query_1 = require("@tanstack/react-query");
|
|
12
11
|
const react_1 = require("react");
|
|
13
12
|
const react_hook_form_1 = require("react-hook-form");
|
|
@@ -54,22 +53,12 @@ function EventFormBody(props) {
|
|
|
54
53
|
(0, react_1.useEffect)(() => {
|
|
55
54
|
formRef.current.reset(defaultValues);
|
|
56
55
|
}, [defaultValues]);
|
|
57
|
-
const menuItems = [];
|
|
58
|
-
if (props.allowOpenRecord) {
|
|
59
|
-
menuItems.push((0, jsx_runtime_1.jsx)(react_components_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(icons_fluent_1.iconSet.OpenInNew, { size: 20 }), onClick: () => props.onOpenRecord?.(props.values.id), children: "Open" }, "open"));
|
|
60
|
-
}
|
|
61
|
-
if (!props.config.disableEdit) {
|
|
62
|
-
menuItems.push((0, jsx_runtime_1.jsx)(react_components_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(icons_fluent_1.iconSet.Delete, { size: 20 }), onClick: () => props.onDelete?.(props.values.id), children: "Delete" }, "delete"));
|
|
63
|
-
}
|
|
64
56
|
let title = (props.values.id ? 'Edit' : 'New') +
|
|
65
57
|
` ${props.config.eventLabel.toLowerCase()}`;
|
|
66
|
-
if (props.values.id
|
|
58
|
+
if (props.values.id) {
|
|
67
59
|
title = props.config.eventLabel;
|
|
68
60
|
}
|
|
69
|
-
|
|
70
|
-
? props.config.disableEdit
|
|
71
|
-
: props.config.disableCreate;
|
|
72
|
-
return ((0, jsx_runtime_1.jsxs)(react_components_1.DialogBody, { children: [(0, jsx_runtime_1.jsx)(react_components_1.DialogTitle, { action: props.values.id && menuItems.length > 0 ? ((0, jsx_runtime_1.jsxs)(react_components_1.Menu, { positioning: "below-end", children: [(0, jsx_runtime_1.jsx)(react_components_1.MenuTrigger, { children: (0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "subtle", "aria-label": "close", icon: (0, jsx_runtime_1.jsx)(icons_fluent_1.iconSet.MoreVertical, {}) }) }), (0, jsx_runtime_1.jsx)(react_components_1.MenuPopover, { children: (0, jsx_runtime_1.jsx)(react_components_1.MenuList, { children: menuItems }) })] })) : null, children: title }), (0, jsx_runtime_1.jsx)(EventFormContent_1.EventFormContent, { form: form, afterDescriptionAttributes: props.config.afterDescriptionAttributes, beforeDescriptionAttributes: props.config.beforeDescriptionAttributes, readOnly: readOnly, config: props.config }), (0, jsx_runtime_1.jsxs)(react_components_1.DialogActions, { children: [!readOnly && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "primary", disabled: form.formState.submitCount > 0 && !form.formState.isValid, onClick: async () => {
|
|
61
|
+
return ((0, jsx_runtime_1.jsxs)(react_components_1.DialogBody, { children: [(0, jsx_runtime_1.jsx)(react_components_1.DialogTitle, { children: title }), (0, jsx_runtime_1.jsx)(EventFormContent_1.EventFormContent, { form: form, afterDescriptionAttributes: props.config.afterDescriptionAttributes, beforeDescriptionAttributes: props.config.beforeDescriptionAttributes, config: props.config }), (0, jsx_runtime_1.jsxs)(react_components_1.DialogActions, { children: [(0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "primary", disabled: form.formState.submitCount > 0 && !form.formState.isValid, onClick: async () => {
|
|
73
62
|
await form.handleSubmit(async (values) => {
|
|
74
63
|
await props.onSubmit?.({
|
|
75
64
|
modifiedValues: values.id
|
|
@@ -78,7 +67,7 @@ function EventFormBody(props) {
|
|
|
78
67
|
values,
|
|
79
68
|
});
|
|
80
69
|
})();
|
|
81
|
-
}, children: props.values.id ? 'Save' : 'Create' })
|
|
70
|
+
}, children: props.values.id ? 'Save' : 'Create' }), (0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "secondary", type: "button", onClick: () => {
|
|
82
71
|
props.onCancel?.();
|
|
83
72
|
}, children: props.values.id ? 'Close' : 'Cancel' })] }), (0, jsx_runtime_1.jsx)(BodyLoading_1.BodyLoading, { loading: isPending })] }));
|
|
84
73
|
}
|
package/PageCalendar/Header.js
CHANGED
|
@@ -27,7 +27,8 @@ function Header({ filterForm, onCreateButtonClick, }) {
|
|
|
27
27
|
display: 'flex',
|
|
28
28
|
alignItems: 'center',
|
|
29
29
|
gap: react_components_1.tokens.spacingHorizontalS,
|
|
30
|
-
}, children:
|
|
30
|
+
}, children: !!config.createOptions && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { style: { fontWeight: react_components_1.tokens.fontWeightMedium }, icon: (0, jsx_runtime_1.jsx)(icons_fluent_1.iconSet.Add, {}), appearance: "primary", onClick: onCreateButtonClick, children: "Create" })) })] }), !!config.filterAttributes &&
|
|
31
|
+
Object.keys(config.filterAttributes).length > 0 && ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_components_1.Divider, { style: { opacity: 0.2 } }), (0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', gap: react_components_1.tokens.spacingHorizontalS }, children: Object.entries(config.filterAttributes).map(([attributeName, attribute]) => {
|
|
31
32
|
return ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: filterForm.control, name: attributeName, render: ({ field }) => {
|
|
32
33
|
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(StandardControl_1.StandardControl, { attribute: attribute, name: attributeName, value: field.value, onChange: field.onChange, onBlur: field.onBlur }) }));
|
|
33
34
|
} }, attributeName));
|
|
@@ -1,56 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
3
|
exports.PageCalendar = PageCalendar;
|
|
30
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
31
|
-
const
|
|
32
|
-
const auth_1 = require("@headless-adminapp/app/auth");
|
|
33
|
-
const context_1 = require("@headless-adminapp/app/calendar/context");
|
|
34
|
-
const dialog_1 = require("@headless-adminapp/app/dialog");
|
|
35
|
-
const hooks_1 = require("@headless-adminapp/app/hooks");
|
|
5
|
+
const CalendarProvider_1 = require("@headless-adminapp/app/calendar/CalendarProvider");
|
|
36
6
|
const mutable_1 = require("@headless-adminapp/app/mutable");
|
|
37
|
-
const progress_indicator_1 = require("@headless-adminapp/app/progress-indicator");
|
|
38
|
-
const toast_notification_1 = require("@headless-adminapp/app/toast-notification");
|
|
39
|
-
const react_query_1 = require("@tanstack/react-query");
|
|
40
|
-
const dayjs_1 = __importDefault(require("dayjs"));
|
|
41
|
-
const isoWeek_1 = __importDefault(require("dayjs/plugin/isoWeek"));
|
|
42
|
-
const timezone_1 = __importDefault(require("dayjs/plugin/timezone"));
|
|
43
|
-
const utc_1 = __importDefault(require("dayjs/plugin/utc"));
|
|
44
7
|
const react_1 = require("react");
|
|
45
|
-
const
|
|
46
|
-
const EventDialog_1 = require("./EventDialog/EventDialog");
|
|
47
|
-
const Header_1 = require("./Header");
|
|
48
|
-
const types_1 = require("./types");
|
|
49
|
-
const utils_1 = require("./utils");
|
|
50
|
-
const CalendarSection = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./CalendarSection'))).then((mod) => ({ default: mod.CalendarSection })));
|
|
51
|
-
dayjs_1.default.extend(utc_1.default);
|
|
52
|
-
dayjs_1.default.extend(timezone_1.default);
|
|
53
|
-
dayjs_1.default.extend(isoWeek_1.default);
|
|
8
|
+
const PageCalendarUI_1 = require("./PageCalendarUI");
|
|
54
9
|
function PageCalendar(props) {
|
|
55
10
|
const contextValue = (0, mutable_1.useCreateContextStore)({
|
|
56
11
|
config: props.config,
|
|
@@ -61,176 +16,5 @@ function PageCalendar(props) {
|
|
|
61
16
|
});
|
|
62
17
|
}, [contextValue, props.config]);
|
|
63
18
|
const config = props.config;
|
|
64
|
-
|
|
65
|
-
const openConfirmDialog = (0, dialog_1.useOpenConfirmDialog)();
|
|
66
|
-
const openToastNotification = (0, toast_notification_1.useOpenToastNotification)();
|
|
67
|
-
const { hideProgressIndicator, showProgressIndicator } = (0, progress_indicator_1.useProgressIndicator)();
|
|
68
|
-
const isMobile = (0, hooks_1.useIsMobile)();
|
|
69
|
-
const [activeStartDate, setActiveStartDate] = (0, react_1.useState)(null);
|
|
70
|
-
const [activeEndDate, setActiveEndDate] = (0, react_1.useState)(null);
|
|
71
|
-
const [currentStartDate, setCurrentStartDate] = (0, react_1.useState)(null);
|
|
72
|
-
const [currentEndDate, setCurrentEndDate] = (0, react_1.useState)(null);
|
|
73
|
-
const [viewType, setViewType] = (0, react_1.useState)(isMobile ? types_1.ViewType.Day : types_1.ViewType.Month);
|
|
74
|
-
const queryClient = (0, react_query_1.useQueryClient)();
|
|
75
|
-
const filterForm = (0, react_hook_form_1.useForm)({
|
|
76
|
-
mode: 'all',
|
|
77
|
-
defaultValues: config.defaultFilter,
|
|
78
|
-
shouldUnregister: false,
|
|
79
|
-
});
|
|
80
|
-
const filterValues = filterForm.watch();
|
|
81
|
-
const auth = (0, auth_1.useAuthSession)();
|
|
82
|
-
const { data: events, isPending: loading } = (0, react_query_1.useQuery)({
|
|
83
|
-
queryKey: [
|
|
84
|
-
'calendar-events',
|
|
85
|
-
'list',
|
|
86
|
-
activeStartDate,
|
|
87
|
-
activeEndDate,
|
|
88
|
-
filterValues,
|
|
89
|
-
auth,
|
|
90
|
-
],
|
|
91
|
-
queryFn: async () => {
|
|
92
|
-
if (!activeStartDate || !activeEndDate) {
|
|
93
|
-
return [];
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const result = await config.eventsResolver({
|
|
97
|
-
start: activeStartDate,
|
|
98
|
-
end: activeEndDate,
|
|
99
|
-
filter: filterValues,
|
|
100
|
-
auth,
|
|
101
|
-
});
|
|
102
|
-
return result.map(utils_1.transformEvent);
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
openToastNotification({
|
|
106
|
-
title: 'Error',
|
|
107
|
-
text: error.message,
|
|
108
|
-
type: 'error',
|
|
109
|
-
});
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
114
|
-
});
|
|
115
|
-
function openEventDetailModel(values) {
|
|
116
|
-
const { close } = openDialog({
|
|
117
|
-
type: 'custom',
|
|
118
|
-
Component: EventDialog_1.EventDialog,
|
|
119
|
-
props: {
|
|
120
|
-
onDismiss: () => {
|
|
121
|
-
close();
|
|
122
|
-
},
|
|
123
|
-
config,
|
|
124
|
-
values,
|
|
125
|
-
onSubmit: async (data) => {
|
|
126
|
-
try {
|
|
127
|
-
const { id, end, start, title, allDay, description, ...rest } = data.values;
|
|
128
|
-
await config.saveEvent({
|
|
129
|
-
event: {
|
|
130
|
-
id,
|
|
131
|
-
title,
|
|
132
|
-
start: start ? new Date(start) : null,
|
|
133
|
-
end: end ? new Date(end) : null,
|
|
134
|
-
allDay: allDay ?? false,
|
|
135
|
-
description,
|
|
136
|
-
...rest,
|
|
137
|
-
},
|
|
138
|
-
modifiedValues: data.modifiedValues,
|
|
139
|
-
});
|
|
140
|
-
await queryClient.invalidateQueries({
|
|
141
|
-
queryKey: ['calendar-events'],
|
|
142
|
-
});
|
|
143
|
-
close();
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
openToastNotification({
|
|
147
|
-
title: 'Error',
|
|
148
|
-
text: error.message,
|
|
149
|
-
type: 'error',
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
onDelete: async (id) => {
|
|
154
|
-
try {
|
|
155
|
-
const confirmResult = await openConfirmDialog({
|
|
156
|
-
title: 'Delete Event',
|
|
157
|
-
text: 'Are you sure you want to delete this event?',
|
|
158
|
-
});
|
|
159
|
-
if (!confirmResult?.confirmed) {
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
showProgressIndicator('Deleting event...');
|
|
163
|
-
await config.deleteEvent(id);
|
|
164
|
-
await queryClient.invalidateQueries({
|
|
165
|
-
queryKey: ['calendar-events'],
|
|
166
|
-
});
|
|
167
|
-
close();
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
openToastNotification({
|
|
171
|
-
title: 'Error',
|
|
172
|
-
text: error.message,
|
|
173
|
-
type: 'error',
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
finally {
|
|
177
|
-
hideProgressIndicator();
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
allowOpenRecord: !!config.openRecord,
|
|
181
|
-
onOpenRecord: config.openRecord,
|
|
182
|
-
onCancel: () => {
|
|
183
|
-
close();
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
function handleDateSelect(selectInfo) {
|
|
189
|
-
if (config.disableCreate) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
openEventDetailModel({
|
|
193
|
-
title: '',
|
|
194
|
-
start: selectInfo.start.toISOString(),
|
|
195
|
-
end: selectInfo.end.toISOString(),
|
|
196
|
-
allDay: selectInfo.allDay,
|
|
197
|
-
customer: null,
|
|
198
|
-
description: '',
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
function handleEventClick(clickInfo) {
|
|
202
|
-
openEventDetailModel({
|
|
203
|
-
id: clickInfo.event.id,
|
|
204
|
-
title: clickInfo.event.title,
|
|
205
|
-
start: clickInfo.event.start?.toISOString(),
|
|
206
|
-
end: clickInfo.event.end?.toISOString(),
|
|
207
|
-
allDay: clickInfo.event.allDay,
|
|
208
|
-
description: '',
|
|
209
|
-
...clickInfo.event.extendedProps,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
function handleCreateButtonClick() {
|
|
213
|
-
openEventDetailModel({
|
|
214
|
-
title: '',
|
|
215
|
-
start: null,
|
|
216
|
-
end: null,
|
|
217
|
-
allDay: false,
|
|
218
|
-
description: '',
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
const onRangeChange = ({ currentStart, currentEnd, activeStart, activeEnd, viewType, }) => {
|
|
222
|
-
setCurrentStartDate(currentStart);
|
|
223
|
-
setCurrentEndDate(currentEnd);
|
|
224
|
-
setActiveStartDate(activeStart);
|
|
225
|
-
setActiveEndDate(activeEnd);
|
|
226
|
-
setViewType(viewType);
|
|
227
|
-
};
|
|
228
|
-
return ((0, jsx_runtime_1.jsx)(context_1.CalendarContext.Provider, { value: contextValue, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
229
|
-
display: 'flex',
|
|
230
|
-
flexDirection: 'column',
|
|
231
|
-
flex: 1,
|
|
232
|
-
gap: react_components_1.tokens.spacingVerticalM,
|
|
233
|
-
padding: react_components_1.tokens.spacingHorizontalM,
|
|
234
|
-
background: react_components_1.tokens.colorNeutralBackground2,
|
|
235
|
-
}, children: [(0, jsx_runtime_1.jsx)(Header_1.Header, { filterForm: filterForm, onCreateButtonClick: handleCreateButtonClick }), (0, jsx_runtime_1.jsx)(react_1.Suspense, { children: (0, jsx_runtime_1.jsx)(CalendarSection, { startDate: currentStartDate, endDate: currentEndDate, viewType: viewType, onRangeChange: onRangeChange, events: events ?? [], onEventClick: handleEventClick, onDateSelect: handleDateSelect, loading: loading }) })] }) }));
|
|
19
|
+
return ((0, jsx_runtime_1.jsx)(CalendarProvider_1.CalendarProvider, { config: config, children: (0, jsx_runtime_1.jsx)(PageCalendarUI_1.PageCalendarUI, {}) }));
|
|
236
20
|
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.PageCalendarUI = PageCalendarUI;
|
|
30
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
31
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
32
|
+
const auth_1 = require("@headless-adminapp/app/auth");
|
|
33
|
+
const hooks_1 = require("@headless-adminapp/app/calendar/hooks");
|
|
34
|
+
const useOpenDetailDialog_1 = require("@headless-adminapp/app/calendar/hooks/useOpenDetailDialog");
|
|
35
|
+
const hooks_2 = require("@headless-adminapp/app/hooks");
|
|
36
|
+
const navigation_1 = require("@headless-adminapp/app/navigation");
|
|
37
|
+
const route_1 = require("@headless-adminapp/app/route");
|
|
38
|
+
const toast_notification_1 = require("@headless-adminapp/app/toast-notification");
|
|
39
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
40
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
41
|
+
const isoWeek_1 = __importDefault(require("dayjs/plugin/isoWeek"));
|
|
42
|
+
const timezone_1 = __importDefault(require("dayjs/plugin/timezone"));
|
|
43
|
+
const utc_1 = __importDefault(require("dayjs/plugin/utc"));
|
|
44
|
+
const react_1 = require("react");
|
|
45
|
+
const react_hook_form_1 = require("react-hook-form");
|
|
46
|
+
const EventDialog_1 = require("./EventDialog/EventDialog");
|
|
47
|
+
const Header_1 = require("./Header");
|
|
48
|
+
const types_1 = require("./types");
|
|
49
|
+
const utils_1 = require("./utils");
|
|
50
|
+
const CalendarSection = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./CalendarSection'))).then((mod) => ({ default: mod.CalendarSection })));
|
|
51
|
+
dayjs_1.default.extend(utc_1.default);
|
|
52
|
+
dayjs_1.default.extend(timezone_1.default);
|
|
53
|
+
dayjs_1.default.extend(isoWeek_1.default);
|
|
54
|
+
function PageCalendarUI() {
|
|
55
|
+
const config = (0, hooks_1.useConfig)();
|
|
56
|
+
const openToastNotification = (0, toast_notification_1.useOpenToastNotification)();
|
|
57
|
+
const isMobile = (0, hooks_2.useIsMobile)();
|
|
58
|
+
const [activeStartDate, setActiveStartDate] = (0, react_1.useState)(null);
|
|
59
|
+
const [activeEndDate, setActiveEndDate] = (0, react_1.useState)(null);
|
|
60
|
+
const [currentStartDate, setCurrentStartDate] = (0, react_1.useState)(null);
|
|
61
|
+
const [currentEndDate, setCurrentEndDate] = (0, react_1.useState)(null);
|
|
62
|
+
const [viewType, setViewType] = (0, react_1.useState)(isMobile ? types_1.ViewType.Day : types_1.ViewType.Month);
|
|
63
|
+
const filterForm = (0, react_hook_form_1.useForm)({
|
|
64
|
+
mode: 'all',
|
|
65
|
+
defaultValues: config.defaultFilter,
|
|
66
|
+
shouldUnregister: false,
|
|
67
|
+
});
|
|
68
|
+
const filterValues = filterForm.watch();
|
|
69
|
+
const auth = (0, auth_1.useAuthSession)();
|
|
70
|
+
const { data: events, isPending: loading } = (0, react_query_1.useQuery)({
|
|
71
|
+
queryKey: [
|
|
72
|
+
'calendar-events',
|
|
73
|
+
'list',
|
|
74
|
+
activeStartDate,
|
|
75
|
+
activeEndDate,
|
|
76
|
+
filterValues,
|
|
77
|
+
auth,
|
|
78
|
+
],
|
|
79
|
+
queryFn: async () => {
|
|
80
|
+
if (!activeStartDate || !activeEndDate) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const result = await config.eventsResolver({
|
|
85
|
+
start: activeStartDate,
|
|
86
|
+
end: activeEndDate,
|
|
87
|
+
filter: filterValues,
|
|
88
|
+
auth,
|
|
89
|
+
});
|
|
90
|
+
return result.map(utils_1.transformEvent);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
openToastNotification({
|
|
94
|
+
title: 'Error',
|
|
95
|
+
text: error.message,
|
|
96
|
+
type: 'error',
|
|
97
|
+
});
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
102
|
+
});
|
|
103
|
+
const openEventDetailModel = (0, useOpenDetailDialog_1.useOpenDetailDialog)(EventDialog_1.EventDialog);
|
|
104
|
+
const router = (0, route_1.useRouter)();
|
|
105
|
+
const routeResolver = (0, route_1.useRouteResolver)();
|
|
106
|
+
const openForm = (0, navigation_1.useOpenForm)();
|
|
107
|
+
const handleNewRecord = (values) => {
|
|
108
|
+
if (!config.createOptions) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (config.createOptions.mode === 'dialog') {
|
|
112
|
+
if (!config.saveEvent) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
openEventDetailModel(values);
|
|
116
|
+
}
|
|
117
|
+
else if (config.createOptions.mode === 'custom') {
|
|
118
|
+
config.createOptions.onClick(values, {
|
|
119
|
+
openForm,
|
|
120
|
+
router,
|
|
121
|
+
routeResolver,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
function handleDateSelect(selectInfo) {
|
|
126
|
+
if (!config.createOptions) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (config.createOptions.mode === 'custom' &&
|
|
130
|
+
!config.createOptions.allowQuickCreate) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (config.disableAllDay && selectInfo.allDay) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
handleNewRecord({
|
|
137
|
+
title: '',
|
|
138
|
+
start: selectInfo.start.toISOString(),
|
|
139
|
+
end: selectInfo.end.toISOString(),
|
|
140
|
+
allDay: selectInfo.allDay,
|
|
141
|
+
customer: null,
|
|
142
|
+
description: '',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function handleCreateButtonClick() {
|
|
146
|
+
handleNewRecord({
|
|
147
|
+
title: '',
|
|
148
|
+
start: null,
|
|
149
|
+
end: null,
|
|
150
|
+
allDay: false,
|
|
151
|
+
description: '',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const onRangeChange = ({ currentStart, currentEnd, activeStart, activeEnd, viewType, }) => {
|
|
155
|
+
setCurrentStartDate(currentStart);
|
|
156
|
+
setCurrentEndDate(currentEnd);
|
|
157
|
+
setActiveStartDate(activeStart);
|
|
158
|
+
setActiveEndDate(activeEnd);
|
|
159
|
+
setViewType(viewType);
|
|
160
|
+
};
|
|
161
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
162
|
+
display: 'flex',
|
|
163
|
+
flexDirection: 'column',
|
|
164
|
+
flex: 1,
|
|
165
|
+
gap: react_components_1.tokens.spacingVerticalM,
|
|
166
|
+
padding: react_components_1.tokens.spacingHorizontalM,
|
|
167
|
+
background: react_components_1.tokens.colorNeutralBackground2,
|
|
168
|
+
}, children: [(0, jsx_runtime_1.jsx)(Header_1.Header, { filterForm: filterForm, onCreateButtonClick: handleCreateButtonClick }), (0, jsx_runtime_1.jsx)(react_1.Suspense, { children: (0, jsx_runtime_1.jsx)(CalendarSection, { startDate: currentStartDate, endDate: currentEndDate, viewType: viewType, onRangeChange: onRangeChange, events: events ?? [], onDateSelect: handleDateSelect, loading: loading }) })] }));
|
|
169
|
+
}
|
|
@@ -1,22 +1,98 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.renderEventContent = renderEventContent;
|
|
4
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
8
|
const react_components_1 = require("@fluentui/react-components");
|
|
9
|
+
const useConfig_1 = require("@headless-adminapp/app/calendar/hooks/useConfig");
|
|
10
|
+
const useDeleteEvent_1 = require("@headless-adminapp/app/calendar/hooks/useDeleteEvent");
|
|
11
|
+
const useOpenDetailDialog_1 = require("@headless-adminapp/app/calendar/hooks/useOpenDetailDialog");
|
|
12
|
+
const locale_1 = require("@headless-adminapp/app/locale");
|
|
13
|
+
const navigation_1 = require("@headless-adminapp/app/navigation");
|
|
14
|
+
const route_1 = require("@headless-adminapp/app/route");
|
|
15
|
+
const icons_1 = require("@headless-adminapp/icons");
|
|
16
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
17
|
+
const react_1 = require("react");
|
|
18
|
+
const EventDialog_1 = require("./EventDialog/EventDialog");
|
|
6
19
|
function renderEventContent(eventInfo) {
|
|
7
|
-
return (
|
|
8
|
-
display: 'flex',
|
|
9
|
-
backgroundColor: react_components_1.tokens.colorBrandBackground2,
|
|
10
|
-
color: react_components_1.tokens.colorNeutralForeground1,
|
|
11
|
-
borderRadius: react_components_1.tokens.borderRadiusMedium,
|
|
12
|
-
paddingBlock: react_components_1.tokens.spacingVerticalXXS,
|
|
13
|
-
paddingInline: react_components_1.tokens.spacingHorizontalS,
|
|
14
|
-
border: `1px solid ${react_components_1.tokens.colorBrandStroke2}`,
|
|
15
|
-
gap: react_components_1.tokens.spacingHorizontalS,
|
|
16
|
-
width: '100%',
|
|
17
|
-
overflow: 'hidden',
|
|
18
|
-
textOverflow: 'ellipsis',
|
|
19
|
-
height: '100%',
|
|
20
|
-
cursor: 'pointer',
|
|
21
|
-
}, children: [eventInfo.timeText && (0, jsx_runtime_1.jsx)("span", { children: eventInfo.timeText }), (0, jsx_runtime_1.jsx)("span", { style: { fontWeight: react_components_1.tokens.fontWeightSemibold }, children: eventInfo.event.title })] }));
|
|
20
|
+
return (0, jsx_runtime_1.jsx)(EventContent, { eventInfo: eventInfo });
|
|
22
21
|
}
|
|
22
|
+
const EventContent = ({ eventInfo }) => {
|
|
23
|
+
const [open, setOpen] = (0, react_1.useState)(false);
|
|
24
|
+
return ((0, jsx_runtime_1.jsxs)(react_components_1.Popover, { positioning: "after", withArrow: true, open: open, onOpenChange: (e, data) => setOpen(data.open), children: [(0, jsx_runtime_1.jsx)(react_components_1.PopoverTrigger, { children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
backgroundColor: react_components_1.tokens.colorBrandBackground2,
|
|
27
|
+
color: react_components_1.tokens.colorNeutralForeground1,
|
|
28
|
+
borderRadius: react_components_1.tokens.borderRadiusMedium,
|
|
29
|
+
paddingBlock: react_components_1.tokens.spacingVerticalXXS,
|
|
30
|
+
paddingInline: react_components_1.tokens.spacingHorizontalS,
|
|
31
|
+
border: `1px solid ${react_components_1.tokens.colorBrandStroke2}`,
|
|
32
|
+
gap: react_components_1.tokens.spacingHorizontalS,
|
|
33
|
+
width: '100%',
|
|
34
|
+
overflow: 'hidden',
|
|
35
|
+
textOverflow: 'ellipsis',
|
|
36
|
+
height: '100%',
|
|
37
|
+
cursor: 'pointer',
|
|
38
|
+
}, children: [eventInfo.timeText && (0, jsx_runtime_1.jsx)("span", { children: eventInfo.timeText }), (0, jsx_runtime_1.jsx)("span", { style: { fontWeight: react_components_1.tokens.fontWeightSemibold }, children: eventInfo.event.title })] }) }), (0, jsx_runtime_1.jsx)(react_components_1.PopoverSurface, { style: { maxWidth: 600 }, children: (0, jsx_runtime_1.jsx)(PopoverContent, { eventInfo: eventInfo, onClose: () => setOpen(false) }) })] }));
|
|
39
|
+
};
|
|
40
|
+
const PopoverContent = ({ eventInfo, onClose }) => {
|
|
41
|
+
const config = (0, useConfig_1.useConfig)();
|
|
42
|
+
const { dateFormats, timeFormats } = (0, locale_1.useLocale)();
|
|
43
|
+
const deleteEvent = (0, useDeleteEvent_1.useDeleteEvent)();
|
|
44
|
+
const openEventDetailModel = (0, useOpenDetailDialog_1.useOpenDetailDialog)(EventDialog_1.EventDialog);
|
|
45
|
+
const router = (0, route_1.useRouter)();
|
|
46
|
+
const routeResolver = (0, route_1.useRouteResolver)();
|
|
47
|
+
const openForm = (0, navigation_1.useOpenForm)();
|
|
48
|
+
const handleEdit = () => {
|
|
49
|
+
if (!config.editOptions) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
onClose();
|
|
53
|
+
if (config.editOptions.mode === 'dialog') {
|
|
54
|
+
openEventDetailModel({
|
|
55
|
+
id: eventInfo.event.id,
|
|
56
|
+
title: eventInfo.event.title,
|
|
57
|
+
start: eventInfo.event.start?.toISOString(),
|
|
58
|
+
end: eventInfo.event.end?.toISOString(),
|
|
59
|
+
allDay: eventInfo.event.allDay,
|
|
60
|
+
description: '',
|
|
61
|
+
...eventInfo.event.extendedProps,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else if (config.editOptions.mode === 'custom') {
|
|
65
|
+
config.editOptions.onClick(eventInfo.event, {
|
|
66
|
+
openForm,
|
|
67
|
+
router,
|
|
68
|
+
routeResolver,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column' }, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
73
|
+
display: 'flex',
|
|
74
|
+
alignItems: 'flex-start',
|
|
75
|
+
gap: react_components_1.tokens.spacingHorizontalM,
|
|
76
|
+
paddingBottom: react_components_1.tokens.spacingVerticalM,
|
|
77
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
78
|
+
fontWeight: react_components_1.tokens.fontWeightBold,
|
|
79
|
+
fontSize: react_components_1.tokens.fontSizeBase400,
|
|
80
|
+
flex: 1,
|
|
81
|
+
alignSelf: 'center',
|
|
82
|
+
}, children: eventInfo.event.title }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
83
|
+
display: 'flex',
|
|
84
|
+
flexDirection: 'row',
|
|
85
|
+
alignItems: 'center',
|
|
86
|
+
gap: react_components_1.tokens.spacingHorizontalS,
|
|
87
|
+
}, children: [!!config.deleteEvent && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Delete, { size: 16 }), appearance: "subtle", onClick: async () => {
|
|
88
|
+
onClose();
|
|
89
|
+
await deleteEvent(eventInfo.event.id);
|
|
90
|
+
} })), !!config.editOptions && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Edit, { size: 16 }), appearance: "subtle", onClick: handleEdit })), (0, jsx_runtime_1.jsx)(react_components_1.Button, { icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Close, { size: 16 }), appearance: "subtle", onClick: onClose })] })] }), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(react_components_1.Divider, { style: { opacity: 0.5 } }) }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
91
|
+
paddingTop: react_components_1.tokens.spacingVerticalM,
|
|
92
|
+
display: 'flex',
|
|
93
|
+
flexDirection: 'column',
|
|
94
|
+
gap: react_components_1.tokens.spacingVerticalM,
|
|
95
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, dayjs_1.default)(eventInfo.event.start).format(dateFormats.long), ' ', (0, dayjs_1.default)(eventInfo.event.start).format(timeFormats.short), ' ', eventInfo.event.allDay
|
|
96
|
+
? 'All Day'
|
|
97
|
+
: '- ' + (0, dayjs_1.default)(eventInfo.event.end).format(timeFormats.short)] }), (0, jsx_runtime_1.jsx)("div", { children: eventInfo.event.extendedProps.description })] })] }));
|
|
98
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SectionEditableGridControl } from '@headless-adminapp/core/experience/form';
|
|
2
|
+
interface EditableGridControlProps {
|
|
3
|
+
readOnly?: boolean;
|
|
4
|
+
control: SectionEditableGridControl;
|
|
5
|
+
}
|
|
6
|
+
export declare function EditableGridControl({ readOnly, control, }: Readonly<EditableGridControlProps>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EditableGridControl = EditableGridControl;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const dataform_1 = require("@headless-adminapp/app/dataform");
|
|
7
|
+
const getRecord_1 = require("@headless-adminapp/app/dataform/DataFormProvider/getRecord");
|
|
8
|
+
const saveRecord_1 = require("@headless-adminapp/app/dataform/utils/saveRecord");
|
|
9
|
+
const form_1 = require("@headless-adminapp/app/form");
|
|
10
|
+
const locale_1 = require("@headless-adminapp/app/locale");
|
|
11
|
+
const metadata_1 = require("@headless-adminapp/app/metadata");
|
|
12
|
+
const transport_1 = require("@headless-adminapp/app/transport");
|
|
13
|
+
const icons_1 = require("@headless-adminapp/icons");
|
|
14
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
15
|
+
const react_1 = require("react");
|
|
16
|
+
const react_hook_form_1 = require("react-hook-form");
|
|
17
|
+
const BodyLoading_1 = require("../../components/BodyLoading");
|
|
18
|
+
const TableUi_1 = require("./TableUi");
|
|
19
|
+
function EditableGridControl({ readOnly, control, }) {
|
|
20
|
+
const recordId = (0, dataform_1.useRecordId)();
|
|
21
|
+
const dataService = (0, transport_1.useDataService)();
|
|
22
|
+
const { schemaStore } = (0, metadata_1.useMetadata)();
|
|
23
|
+
const { language, region } = (0, locale_1.useLocale)();
|
|
24
|
+
const formValidationStrings = (0, form_1.useFormValidationStrings)();
|
|
25
|
+
const schema = schemaStore.getSchema(control.logicalName);
|
|
26
|
+
const alias = control.alias ? control.alias : 'items';
|
|
27
|
+
const parentFormInstance = (0, dataform_1.useFormInstance)();
|
|
28
|
+
const localFormInstance = (0, react_hook_form_1.useForm)({
|
|
29
|
+
mode: 'all',
|
|
30
|
+
defaultValues: {
|
|
31
|
+
items: [],
|
|
32
|
+
},
|
|
33
|
+
resolver: (0, dataform_1.editableSubgridFormValidator)({
|
|
34
|
+
alias,
|
|
35
|
+
control,
|
|
36
|
+
schema: schemaStore.getSchema(control.logicalName),
|
|
37
|
+
language,
|
|
38
|
+
region,
|
|
39
|
+
schemaStore,
|
|
40
|
+
strings: formValidationStrings,
|
|
41
|
+
formReadOnly: readOnly,
|
|
42
|
+
}),
|
|
43
|
+
shouldUnregister: false,
|
|
44
|
+
});
|
|
45
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
46
|
+
const { data, isFetching } = (0, react_query_1.useQuery)({
|
|
47
|
+
queryKey: ['editable-grid', recordId, control],
|
|
48
|
+
queryFn: async () => {
|
|
49
|
+
return (0, getRecord_1.getEditableSubgridRecords)({
|
|
50
|
+
control,
|
|
51
|
+
schemaStore,
|
|
52
|
+
dataService,
|
|
53
|
+
recordId,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
enabled: !!recordId && !control.alias,
|
|
57
|
+
});
|
|
58
|
+
const formInstanceRef = (0, react_1.useRef)(localFormInstance);
|
|
59
|
+
formInstanceRef.current = localFormInstance;
|
|
60
|
+
(0, react_1.useEffect)(() => {
|
|
61
|
+
if (!data) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
formInstanceRef.current.reset({
|
|
65
|
+
items: data,
|
|
66
|
+
});
|
|
67
|
+
}, [data]);
|
|
68
|
+
const formControl = control.alias
|
|
69
|
+
? parentFormInstance.control
|
|
70
|
+
: localFormInstance.control;
|
|
71
|
+
const fieldArray = (0, react_hook_form_1.useFieldArray)({
|
|
72
|
+
control: formControl,
|
|
73
|
+
name: alias,
|
|
74
|
+
keyName: '__key',
|
|
75
|
+
shouldUnregister: false,
|
|
76
|
+
});
|
|
77
|
+
const handleAddRow = () => {
|
|
78
|
+
const newItem = {
|
|
79
|
+
$entity: schema.logicalName,
|
|
80
|
+
[schema.idAttribute]: null,
|
|
81
|
+
[control.associatedAttribute]: {
|
|
82
|
+
id: recordId,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
control.controls.forEach((control) => {
|
|
86
|
+
if (typeof control === 'string') {
|
|
87
|
+
newItem[control] = null;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
newItem[control.attributeName] = null;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
fieldArray.append(newItem);
|
|
94
|
+
};
|
|
95
|
+
const handleSave = async () => {
|
|
96
|
+
await localFormInstance.handleSubmit(async (values) => {
|
|
97
|
+
try {
|
|
98
|
+
await (0, saveRecord_1.saveEditableGridControl)({
|
|
99
|
+
recordId,
|
|
100
|
+
values,
|
|
101
|
+
initialValues: localFormInstance.formState.defaultValues,
|
|
102
|
+
control,
|
|
103
|
+
dataService,
|
|
104
|
+
schemaStore,
|
|
105
|
+
alias,
|
|
106
|
+
});
|
|
107
|
+
await queryClient.invalidateQueries({
|
|
108
|
+
queryKey: ['editable-grid', recordId, control],
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error(error);
|
|
113
|
+
}
|
|
114
|
+
}, (errors) => {
|
|
115
|
+
console.error(errors);
|
|
116
|
+
})();
|
|
117
|
+
};
|
|
118
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
119
|
+
display: 'flex',
|
|
120
|
+
flexDirection: 'column',
|
|
121
|
+
position: 'relative',
|
|
122
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
123
|
+
display: 'flex',
|
|
124
|
+
paddingInline: 16,
|
|
125
|
+
paddingBlock: 8,
|
|
126
|
+
height: 40,
|
|
127
|
+
alignItems: 'center',
|
|
128
|
+
}, children: (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', width: '100%' }, children: [(0, jsx_runtime_1.jsx)(react_components_1.Body1Strong, { children: control.label }), (0, jsx_runtime_1.jsx)("div", { style: { flex: 1 } }), (0, jsx_runtime_1.jsx)("div", { style: { marginRight: -12 }, children: !control.alias && !readOnly && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Save, {}), appearance: "subtle", style: { minWidth: 0 }, disabled: localFormInstance.formState.isSubmitting ||
|
|
129
|
+
!localFormInstance.formState.isValid ||
|
|
130
|
+
!localFormInstance.formState.isDirty, onClick: handleSave, children: "Save" })) })] }) }), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(react_components_1.Divider, { style: { opacity: 0.2 } }) }), (0, jsx_runtime_1.jsx)("div", { style: { padding: 16, position: 'relative' }, children: (0, jsx_runtime_1.jsx)(TableUi_1.TableUi, { schema: schema, control: control, formControl: formControl, alias: alias, onAddRow: handleAddRow, onRemoveRow: (index) => {
|
|
131
|
+
fieldArray.remove(index);
|
|
132
|
+
}, rows: fieldArray.fields }) }), (0, jsx_runtime_1.jsx)(BodyLoading_1.BodyLoading, { loading: isFetching || localFormInstance.formState.isSubmitting })] }));
|
|
133
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SectionEditableGridControl } from '@headless-adminapp/core/experience/form';
|
|
2
|
+
import { Schema } from '@headless-adminapp/core/schema';
|
|
3
|
+
import { FC } from 'react';
|
|
4
|
+
import { Control } from 'react-hook-form';
|
|
5
|
+
interface TableUiProps {
|
|
6
|
+
schema: Schema;
|
|
7
|
+
control: SectionEditableGridControl;
|
|
8
|
+
formControl: Control;
|
|
9
|
+
onAddRow?: () => void;
|
|
10
|
+
onRemoveRow?: (index: number) => void;
|
|
11
|
+
rows: Record<'__key', string>[];
|
|
12
|
+
alias: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const TableUi: FC<TableUiProps>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TableUi = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const icons_1 = require("@headless-adminapp/icons");
|
|
7
|
+
const react_hook_form_1 = require("react-hook-form");
|
|
8
|
+
const SectionControl_1 = require("../../DataForm/SectionControl");
|
|
9
|
+
const StandardControl_1 = require("../StandardControl");
|
|
10
|
+
const useStyles = (0, react_components_1.makeStyles)({
|
|
11
|
+
table: {
|
|
12
|
+
'& tbody tr:hover': {
|
|
13
|
+
backgroundColor: 'transparent',
|
|
14
|
+
},
|
|
15
|
+
'& tr': {
|
|
16
|
+
borderBottom: `${react_components_1.tokens.strokeWidthThin} solid transparent`,
|
|
17
|
+
},
|
|
18
|
+
'& th': {
|
|
19
|
+
fontWeight: react_components_1.tokens.fontWeightMedium,
|
|
20
|
+
paddingInline: react_components_1.tokens.spacingHorizontalXS,
|
|
21
|
+
},
|
|
22
|
+
'& td': {
|
|
23
|
+
paddingInline: react_components_1.tokens.spacingHorizontalXS,
|
|
24
|
+
},
|
|
25
|
+
'& tbody tr:last-child': {
|
|
26
|
+
borderBottom: 'none',
|
|
27
|
+
},
|
|
28
|
+
'& td:first-child': {
|
|
29
|
+
paddingLeft: 0,
|
|
30
|
+
},
|
|
31
|
+
'& th:first-child': {
|
|
32
|
+
paddingLeft: 0,
|
|
33
|
+
},
|
|
34
|
+
'& td:last-child': {
|
|
35
|
+
paddingRight: 0,
|
|
36
|
+
},
|
|
37
|
+
'& th:last-child': {
|
|
38
|
+
paddingRight: 0,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
const TableUi = ({ schema, control, formControl, onAddRow, onRemoveRow, rows, alias, }) => {
|
|
43
|
+
const styles = useStyles();
|
|
44
|
+
return ((0, jsx_runtime_1.jsxs)(react_components_1.Table, { className: styles.table, children: [(0, jsx_runtime_1.jsxs)("colgroup", { children: [control.controls.map((_, index) => ((0, jsx_runtime_1.jsx)("col", {}, index))), (0, jsx_runtime_1.jsx)("col", { style: { width: 36 } })] }), (0, jsx_runtime_1.jsx)(react_components_1.TableHeader, { children: (0, jsx_runtime_1.jsxs)(react_components_1.TableRow, { children: [control.controls.map((control) => {
|
|
45
|
+
const attributeName = typeof control === 'string' ? control : control.attributeName;
|
|
46
|
+
const attribute = schema.attributes[attributeName];
|
|
47
|
+
if (!attribute) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return ((0, jsx_runtime_1.jsx)(react_components_1.TableHeaderCell, { children: attribute.label ?? attribute.label }, attributeName));
|
|
51
|
+
}), (0, jsx_runtime_1.jsx)(react_components_1.TableHeaderCell, { children: (0, jsx_runtime_1.jsx)(react_components_1.Button, { icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Add, { size: 16 }), appearance: "subtle", onClick: onAddRow }) })] }) }), (0, jsx_runtime_1.jsx)(react_components_1.TableBody, { children: rows.map((item, index) => ((0, jsx_runtime_1.jsxs)(react_components_1.TableRow, { children: [control.controls.map((control) => {
|
|
52
|
+
const attributeName = typeof control === 'string' ? control : control.attributeName;
|
|
53
|
+
const attribute = schema.attributes[attributeName];
|
|
54
|
+
if (!attribute) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return ((0, jsx_runtime_1.jsx)(react_components_1.TableCell, { children: (0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { name: `${alias}.${index}.${attributeName}`, control: formControl, render: ({ field, fieldState, formState }) => {
|
|
58
|
+
const isError = (fieldState.isTouched || formState.isSubmitted) &&
|
|
59
|
+
!!fieldState.error?.message;
|
|
60
|
+
return ((0, jsx_runtime_1.jsx)(SectionControl_1.SectionControlWrapper, { label: attribute.label, labelHidden: true, labelPosition: "top", isError: isError, children: (0, jsx_runtime_1.jsx)(StandardControl_1.StandardControl, { attribute: attribute, name: attributeName, value: field.value ?? null, onChange: field.onChange, onBlur: field.onBlur, placeholder: "" }) }));
|
|
61
|
+
} }) }, attributeName));
|
|
62
|
+
}), (0, jsx_runtime_1.jsx)(react_components_1.TableCell, { children: (0, jsx_runtime_1.jsx)(react_components_1.Button, { icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Delete, { size: 16 }), appearance: "subtle", onClick: () => onRemoveRow?.(index) }) })] }, item.__key))) })] }));
|
|
63
|
+
};
|
|
64
|
+
exports.TableUi = TableUi;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EditableGridControl } from './EditableGridControl';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EditableGridControl = void 0;
|
|
4
|
+
var EditableGridControl_1 = require("./EditableGridControl");
|
|
5
|
+
Object.defineProperty(exports, "EditableGridControl", { enumerable: true, get: function () { return EditableGridControl_1.EditableGridControl; } });
|
|
@@ -4,7 +4,7 @@ exports.RecordCard = RecordCard;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_components_1 = require("@fluentui/react-components");
|
|
6
6
|
const utils_1 = require("@headless-adminapp/app/utils");
|
|
7
|
-
const
|
|
7
|
+
const ChoiceBadge_1 = require("../components/ChoiceBadge");
|
|
8
8
|
const useStyles = (0, react_components_1.makeStyles)({
|
|
9
9
|
root: {
|
|
10
10
|
width: '100%',
|
|
@@ -113,18 +113,5 @@ function SecondaryColumnContent({ record: _record, column, schema, }) {
|
|
|
113
113
|
return ((0, jsx_runtime_1.jsxs)(react_components_1.Caption1, { style: { color: react_components_1.tokens.colorNeutralForeground4 }, children: [!!label && `${label}: `, (0, utils_1.getAttributeFormattedValue)(attribute, value)] }, column.name));
|
|
114
114
|
}
|
|
115
115
|
const ChoiceTag = ({ attribute, value, }) => {
|
|
116
|
-
|
|
117
|
-
if (!choice) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
const bgColor = choice.color;
|
|
121
|
-
let color;
|
|
122
|
-
if (bgColor) {
|
|
123
|
-
color = (0, color_1.isColorDark)(bgColor) ? '#FFFFFF' : '#000000';
|
|
124
|
-
}
|
|
125
|
-
return ((0, jsx_runtime_1.jsx)(react_components_1.Badge, { size: "small", appearance: "filled", style: {
|
|
126
|
-
background: bgColor,
|
|
127
|
-
color: color,
|
|
128
|
-
fontWeight: react_components_1.tokens.fontWeightRegular,
|
|
129
|
-
}, children: choice.label }));
|
|
116
|
+
return (0, jsx_runtime_1.jsx)(ChoiceBadge_1.ChoiceBadge, { attribute: attribute, value: value, size: "small" });
|
|
130
117
|
};
|
|
@@ -28,6 +28,7 @@ const RecordSetNavigatorContainer = () => {
|
|
|
28
28
|
const { data, cardView, schema } = (0, hooks_2.useRecordSetResult)();
|
|
29
29
|
const [visible] = (0, hooks_2.useRecordSetVisibility)();
|
|
30
30
|
const recordId = (0, hooks_1.useRecordId)();
|
|
31
|
+
const formSchema = (0, hooks_1.useDataFormSchema)();
|
|
31
32
|
const styles = useStyles();
|
|
32
33
|
const openForm = (0, navigation_1.useOpenForm)();
|
|
33
34
|
const { language, direction } = (0, locale_1.useLocale)();
|
|
@@ -37,6 +38,9 @@ const RecordSetNavigatorContainer = () => {
|
|
|
37
38
|
if (!visible) {
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
41
|
+
if (schema.logicalName !== formSchema?.logicalName) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
40
44
|
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
41
45
|
[direction === 'rtl' ? 'paddingRight' : 'paddingLeft']: react_components_1.tokens.spacingVerticalM,
|
|
42
46
|
paddingBlock: react_components_1.tokens.spacingVerticalM,
|
|
@@ -16,6 +16,7 @@ const react_hook_form_1 = require("react-hook-form");
|
|
|
16
16
|
const componentStore_1 = require("../componentStore");
|
|
17
17
|
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
18
18
|
const layout_1 = require("../form/layout");
|
|
19
|
+
const EditableGridControl_1 = require("./EditableGridControl/EditableGridControl");
|
|
19
20
|
const StandardControl_1 = require("./StandardControl");
|
|
20
21
|
const SubgridControl_1 = require("./SubgridControl");
|
|
21
22
|
function SectionContainer({ section }) {
|
|
@@ -98,7 +99,13 @@ function SectionContainer({ section }) {
|
|
|
98
99
|
} }, control.attributeName) }, control.attributeName));
|
|
99
100
|
}
|
|
100
101
|
case 'editablegrid': {
|
|
101
|
-
|
|
102
|
+
const disabled = (0, utils_1.getIsFieldDisabled)({
|
|
103
|
+
isFormReadonly,
|
|
104
|
+
disabledFields: disabledControls,
|
|
105
|
+
attribute: null,
|
|
106
|
+
control,
|
|
107
|
+
});
|
|
108
|
+
return ((0, jsx_runtime_1.jsx)(EditableGridControl_1.EditableGridControl, { readOnly: disabled, control: control }));
|
|
102
109
|
}
|
|
103
110
|
case 'quickview':
|
|
104
111
|
return null;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ChoiceAttribute } from '@headless-adminapp/core/attributes';
|
|
2
|
+
import { ChoicesAttribute } from '@headless-adminapp/core/attributes/ChoiceAttribute';
|
|
2
3
|
interface ChoiceBadgeProps {
|
|
3
4
|
value: unknown;
|
|
4
|
-
attribute: ChoiceAttribute<string | number>;
|
|
5
|
-
formattedValue
|
|
5
|
+
attribute: ChoiceAttribute<string | number> | ChoicesAttribute<string | number>;
|
|
6
|
+
formattedValue?: string | null;
|
|
6
7
|
size?: 'small' | 'medium';
|
|
7
8
|
}
|
|
8
9
|
export declare function ChoiceBadge(props: Readonly<ChoiceBadgeProps>): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -18,12 +18,25 @@ function ChoiceBadge(props) {
|
|
|
18
18
|
}
|
|
19
19
|
return (0, color_1.isColorDark)(bgColor) ? '#FFFFFF' : '#000000';
|
|
20
20
|
}, [bgColor]);
|
|
21
|
-
|
|
21
|
+
const formattedValue = (0, react_1.useMemo)(() => {
|
|
22
|
+
if (props.formattedValue) {
|
|
23
|
+
return props.formattedValue;
|
|
24
|
+
}
|
|
25
|
+
if (!props.value) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const choice = props.attribute.options.find((option) => option.value === props.value);
|
|
29
|
+
if (!choice) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return choice.label;
|
|
33
|
+
}, [props.attribute.options, props.formattedValue, props.value]);
|
|
34
|
+
if (!formattedValue) {
|
|
22
35
|
return null;
|
|
23
36
|
}
|
|
24
37
|
return ((0, jsx_runtime_1.jsx)(react_components_1.Badge, { style: {
|
|
25
38
|
backgroundColor: bgColor ?? react_components_1.tokens.colorNeutralBackground3,
|
|
26
39
|
color: color ?? react_components_1.tokens.colorNeutralForeground2,
|
|
27
40
|
fontWeight: react_components_1.tokens.fontWeightRegular,
|
|
28
|
-
}, size: props.size, children:
|
|
41
|
+
}, size: props.size, children: formattedValue }));
|
|
29
42
|
}
|
|
@@ -5,6 +5,7 @@ interface AttributeControllerProps<TFieldValues extends FieldValues = FieldValue
|
|
|
5
5
|
attributeName: FieldPath<TFieldValues>;
|
|
6
6
|
control: Control<TFieldValues>;
|
|
7
7
|
readOnly?: boolean;
|
|
8
|
+
labelPosition?: 'left' | 'top';
|
|
8
9
|
}
|
|
9
|
-
export declare function AttributeController<TFieldValues extends FieldValues = FieldValues>({ attribute, attributeName, control, readOnly, }: Readonly<AttributeControllerProps<TFieldValues>>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function AttributeController<TFieldValues extends FieldValues = FieldValues>({ attribute, attributeName, control, readOnly, labelPosition, }: Readonly<AttributeControllerProps<TFieldValues>>): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -5,13 +5,13 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
5
5
|
const react_hook_form_1 = require("react-hook-form");
|
|
6
6
|
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
7
7
|
const StandardControl_1 = require("../PageEntityForm/StandardControl");
|
|
8
|
-
function AttributeController({ attribute, attributeName, control, readOnly, }) {
|
|
8
|
+
function AttributeController({ attribute, attributeName, control, readOnly, labelPosition = 'left', }) {
|
|
9
9
|
return ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: attributeName, render: ({ field, fieldState, formState }) => {
|
|
10
10
|
const isError = (fieldState.isTouched || formState.isSubmitted) &&
|
|
11
11
|
!!fieldState.error?.message;
|
|
12
12
|
const errorMessage = fieldState.isTouched || formState.isSubmitted
|
|
13
13
|
? fieldState.error?.message
|
|
14
14
|
: '';
|
|
15
|
-
return ((0, jsx_runtime_1.jsx)(SectionControl_1.SectionControlWrapper, { label: attribute.label, labelPosition:
|
|
15
|
+
return ((0, jsx_runtime_1.jsx)(SectionControl_1.SectionControlWrapper, { label: attribute.label, labelPosition: labelPosition, required: attribute.required, isError: isError, errorMessage: errorMessage, children: (0, jsx_runtime_1.jsx)(StandardControl_1.StandardControl, { attribute: attribute, name: attributeName, value: field.value, onChange: field.onChange, onBlur: field.onBlur, errorMessage: errorMessage, isError: isError, readOnly: readOnly || attribute.readonly }) }));
|
|
16
16
|
} }));
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@headless-adminapp/fluent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"uuid": "11.0.3",
|
|
51
51
|
"yup": "^1.4.0"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "3c59cbbf000e71e39b81c9440a71363b729e6e3c"
|
|
54
54
|
}
|