@headless-adminapp/fluent 1.4.23 → 1.4.24
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/App/AppHeaderContianer.js +3 -1
- package/DataGrid/useTableColumns.d.ts +2 -1
- package/DataGrid/useTableColumns.js +10 -5
- package/DialogContainer/PromptDialog.d.ts +0 -22
- package/DialogContainer/PromptDialog.js +1 -54
- package/PageCalendar/EventDialog/EventFormBody.js +2 -2
- package/PageEntityForm/QuickViewControl/index.d.ts +7 -0
- package/PageEntityForm/QuickViewControl/index.js +67 -0
- package/PageEntityForm/SectionContainer.js +2 -1
- package/PageEntityForm/StandardControl.js +1 -1
- package/form/controls/TextControl.d.ts +28 -1
- package/form/controls/TextControl.js +90 -4
- package/form/useFormForAttributes.js +2 -2
- package/package.json +5 -2
- package/PageCalendar/EventDialog/utils.d.ts +0 -23
- package/PageCalendar/EventDialog/utils.js +0 -57
|
@@ -60,6 +60,7 @@ const NavActions = () => {
|
|
|
60
60
|
const logout = (0, hooks_1.useLogout)();
|
|
61
61
|
const strings = (0, AppStringContext_1.useAppStrings)();
|
|
62
62
|
const { language } = (0, locale_1.useLocale)();
|
|
63
|
+
const [accountMenuOpen, setAccountMenuOpen] = (0, react_1.useState)(false);
|
|
63
64
|
const initials = (0, react_1.useMemo)(() => {
|
|
64
65
|
return authSession?.fullName
|
|
65
66
|
.toUpperCase()
|
|
@@ -81,7 +82,7 @@ const NavActions = () => {
|
|
|
81
82
|
return (0, jsx_runtime_1.jsx)(item.Component, {}, item.__key);
|
|
82
83
|
}
|
|
83
84
|
return ((0, jsx_runtime_1.jsx)(QuickActionItem_1.QuickActionItem, { Icon: item.icon, label: item.localizedLabel?.[language] ?? item.label, onClick: () => item.onClick?.(), link: item.link }, item.__key));
|
|
84
|
-
}) }), (!isSkipAuthCheck || !!accountMenuItems?.length) && ((0, jsx_runtime_1.jsxs)(react_components_1.Popover, { children: [(0, jsx_runtime_1.jsx)(react_components_1.PopoverTrigger, { disableButtonEnhancement: true, children: (0, jsx_runtime_1.jsx)(react_components_1.Avatar, { initials: initials, color: "neutral", style: { cursor: 'pointer' }, image: {
|
|
85
|
+
}) }), (!isSkipAuthCheck || !!accountMenuItems?.length) && ((0, jsx_runtime_1.jsxs)(react_components_1.Popover, { open: accountMenuOpen, onOpenChange: (e, data) => setAccountMenuOpen(data.open), children: [(0, jsx_runtime_1.jsx)(react_components_1.PopoverTrigger, { disableButtonEnhancement: true, children: (0, jsx_runtime_1.jsx)(react_components_1.Avatar, { initials: initials, color: "neutral", style: { cursor: 'pointer' }, image: {
|
|
85
86
|
src: authSession?.profilePicture,
|
|
86
87
|
} }) }), (0, jsx_runtime_1.jsxs)(react_components_1.PopoverSurface, { tabIndex: -1, style: { padding: 0 }, children: [!isSkipAuthCheck && ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
87
88
|
display: 'flex',
|
|
@@ -99,6 +100,7 @@ const NavActions = () => {
|
|
|
99
100
|
}, children: [(0, jsx_runtime_1.jsx)(react_components_1.Caption1Strong, { children: authSession?.fullName }), (0, jsx_runtime_1.jsx)(react_components_1.Caption1, { style: { textOverflow: 'ellipsis', overflow: 'hidden' }, children: authSession?.email })] })] })), !isSkipAuthCheck && (0, jsx_runtime_1.jsx)(react_components_1.MenuDivider, { style: { marginInline: 0 } }), (0, jsx_runtime_1.jsxs)(react_components_1.MenuList, { style: { width: 200, marginBottom: 4 }, children: [accountMenuItems?.map((item) => {
|
|
100
101
|
const Icon = item.icon;
|
|
101
102
|
return ((0, jsx_runtime_1.jsx)(react_components_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(Icon, { size: "inherit" }), onClick: async () => {
|
|
103
|
+
setAccountMenuOpen(false);
|
|
102
104
|
if (item.onClick) {
|
|
103
105
|
item.onClick();
|
|
104
106
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { InternalRouteResolver
|
|
1
|
+
import { InternalRouteResolver } from '@headless-adminapp/app/route/context';
|
|
2
2
|
import { LookupAttribute } from '@headless-adminapp/core/attributes';
|
|
3
|
+
import { RouterInstance } from '@headless-adminapp/core/navigation';
|
|
3
4
|
import { ISchemaStore } from '@headless-adminapp/core/store';
|
|
4
5
|
import { UniqueRecord } from './types';
|
|
5
6
|
export declare function useTableColumns({ disableSelection, disableContextMenu, disableColumnResize, disableColumnFilter, disableColumnSort, tableWrapperRef, }: {
|
|
@@ -134,7 +134,12 @@ function useTableColumns({ disableSelection, disableContextMenu, disableColumnRe
|
|
|
134
134
|
maxSize: 32,
|
|
135
135
|
}),
|
|
136
136
|
];
|
|
137
|
-
}, [
|
|
137
|
+
}, [
|
|
138
|
+
disableContextMenu,
|
|
139
|
+
mutableContextCommandState,
|
|
140
|
+
schema.idAttribute,
|
|
141
|
+
setValue,
|
|
142
|
+
]);
|
|
138
143
|
const selectionColumns = (0, react_1.useMemo)(() => {
|
|
139
144
|
if (disableSelection)
|
|
140
145
|
return [];
|
|
@@ -410,8 +415,8 @@ function renderLookupAttribute({ value, schemaStore, routeResolver, router, attr
|
|
|
410
415
|
type: app_1.PageType.EntityForm,
|
|
411
416
|
id: value.id,
|
|
412
417
|
});
|
|
413
|
-
return ((0, jsx_runtime_1.jsx)(TableCellLink_1.TableCellLinkContent, { href: path, onClick: () => {
|
|
414
|
-
router.push(path);
|
|
418
|
+
return ((0, jsx_runtime_1.jsx)(TableCellLink_1.TableCellLinkContent, { href: path, onClick: async () => {
|
|
419
|
+
await router.push(path);
|
|
415
420
|
}, children: (0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [!!lookupSchema.avatarAttribute && ((0, jsx_runtime_1.jsx)(react_components_1.Avatar, { style: {
|
|
416
421
|
width: 24,
|
|
417
422
|
height: 24,
|
|
@@ -435,8 +440,8 @@ function renderRegardingAttribute({ value, schemaStore, routeResolver, router, f
|
|
|
435
440
|
type: app_1.PageType.EntityForm,
|
|
436
441
|
id: value.id,
|
|
437
442
|
});
|
|
438
|
-
return ((0, jsx_runtime_1.jsx)(TableCellLink_1.TableCellLinkContent, { href: path, onClick: () => {
|
|
439
|
-
router.push(path);
|
|
443
|
+
return ((0, jsx_runtime_1.jsx)(TableCellLink_1.TableCellLinkContent, { href: path, onClick: async () => {
|
|
444
|
+
await router.push(path);
|
|
440
445
|
}, children: (0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [!!lookupSchema.avatarAttribute && ((0, jsx_runtime_1.jsx)(react_components_1.Avatar, { style: {
|
|
441
446
|
width: 24,
|
|
442
447
|
height: 24,
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { FormValidationStringSet } from '@headless-adminapp/app/form';
|
|
2
1
|
import { PromptDialogOptions } from '@headless-adminapp/core/experience/dialog';
|
|
3
2
|
import { SchemaAttributes } from '@headless-adminapp/core/schema';
|
|
4
|
-
import * as yup from 'yup';
|
|
5
3
|
interface PromptDialogProps<SA extends SchemaAttributes = SchemaAttributes> {
|
|
6
4
|
open: boolean;
|
|
7
5
|
title?: PromptDialogOptions<SA>['title'];
|
|
@@ -15,24 +13,4 @@ interface PromptDialogProps<SA extends SchemaAttributes = SchemaAttributes> {
|
|
|
15
13
|
onDismiss?: PromptDialogOptions<SA>['onDismiss'];
|
|
16
14
|
}
|
|
17
15
|
export declare function PromptDialog(props: Readonly<PromptDialogProps>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
-
export declare const formValidator: (<A extends SchemaAttributes = SchemaAttributes>({ attributes, language, strings, region, }: {
|
|
19
|
-
attributes: A;
|
|
20
|
-
language: string;
|
|
21
|
-
strings: FormValidationStringSet;
|
|
22
|
-
region: string;
|
|
23
|
-
}) => (values: Record<string, any>, context: any, options: any) => Promise<import("react-hook-form").ResolverResult<{
|
|
24
|
-
[x: string]: any;
|
|
25
|
-
[x: number]: any;
|
|
26
|
-
[x: symbol]: any;
|
|
27
|
-
}>>) & import("lodash").MemoizedFunction;
|
|
28
|
-
export declare const generateValidationSchema: (<A extends SchemaAttributes = SchemaAttributes>({ attributes, language, strings, region, }: {
|
|
29
|
-
attributes: A;
|
|
30
|
-
language: string;
|
|
31
|
-
strings: FormValidationStringSet;
|
|
32
|
-
region: string;
|
|
33
|
-
}) => yup.ObjectSchema<{
|
|
34
|
-
[x: string]: any;
|
|
35
|
-
}, yup.AnyObject, {
|
|
36
|
-
[x: string]: any;
|
|
37
|
-
}, "">) & import("lodash").MemoizedFunction;
|
|
38
16
|
export {};
|
|
@@ -1,39 +1,12 @@
|
|
|
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.generateValidationSchema = exports.formValidator = void 0;
|
|
27
3
|
exports.PromptDialog = PromptDialog;
|
|
28
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
29
5
|
const react_components_1 = require("@fluentui/react-components");
|
|
30
6
|
const utils_1 = require("@headless-adminapp/app/dataform/utils");
|
|
31
7
|
const form_1 = require("@headless-adminapp/app/form");
|
|
32
8
|
const locale_1 = require("@headless-adminapp/app/locale");
|
|
33
|
-
const yup_1 = require("@hookform/resolvers/yup");
|
|
34
|
-
const lodash_1 = require("lodash");
|
|
35
9
|
const react_hook_form_1 = require("react-hook-form");
|
|
36
|
-
const yup = __importStar(require("yup"));
|
|
37
10
|
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
38
11
|
const StandardControl_1 = require("../PageEntityForm/StandardControl");
|
|
39
12
|
function PromptDialog(props) {
|
|
@@ -43,7 +16,7 @@ function PromptDialog(props) {
|
|
|
43
16
|
mode: 'all',
|
|
44
17
|
defaultValues: props.defaultValues,
|
|
45
18
|
shouldUnregister: false,
|
|
46
|
-
resolver: (0,
|
|
19
|
+
resolver: (0, utils_1.attributesFormValidator)({
|
|
47
20
|
attributes: props.attributes,
|
|
48
21
|
language,
|
|
49
22
|
strings: formValidationStrings,
|
|
@@ -75,29 +48,3 @@ function PromptDialog(props) {
|
|
|
75
48
|
})();
|
|
76
49
|
}, children: props.confirmText ?? 'Confirm' })] })] }) }) }));
|
|
77
50
|
}
|
|
78
|
-
exports.formValidator = (0, lodash_1.memoize)(function formValidator({ attributes, language, strings, region, }) {
|
|
79
|
-
return async (values, context, options) => {
|
|
80
|
-
const validator = (0, exports.generateValidationSchema)({
|
|
81
|
-
attributes,
|
|
82
|
-
language,
|
|
83
|
-
strings,
|
|
84
|
-
region,
|
|
85
|
-
});
|
|
86
|
-
const resolver = (0, yup_1.yupResolver)(validator);
|
|
87
|
-
const result = await resolver(values, context, options);
|
|
88
|
-
return result;
|
|
89
|
-
};
|
|
90
|
-
}, (options) => JSON.stringify(options));
|
|
91
|
-
exports.generateValidationSchema = (0, lodash_1.memoize)(function generateValidationSchema({ attributes, language, strings, region, }) {
|
|
92
|
-
const columns = Object.keys(attributes);
|
|
93
|
-
return yup.object().shape({
|
|
94
|
-
...columns.reduce((acc, column) => {
|
|
95
|
-
const attribute = attributes[column];
|
|
96
|
-
const validationSchema = (0, utils_1.generateAttributeValidationSchema)(attribute, language, strings, region);
|
|
97
|
-
return {
|
|
98
|
-
...acc,
|
|
99
|
-
[column]: validationSchema,
|
|
100
|
-
};
|
|
101
|
-
}, {}),
|
|
102
|
-
});
|
|
103
|
-
}, (options) => JSON.stringify(options));
|
|
@@ -4,6 +4,7 @@ exports.EventFormBody = EventFormBody;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_components_1 = require("@fluentui/react-components");
|
|
6
6
|
const baseEventAttributes_1 = require("@headless-adminapp/app/calendar/baseEventAttributes");
|
|
7
|
+
const dataform_1 = require("@headless-adminapp/app/dataform");
|
|
7
8
|
const saveRecord_1 = require("@headless-adminapp/app/dataform/utils/saveRecord");
|
|
8
9
|
const form_1 = require("@headless-adminapp/app/form");
|
|
9
10
|
const locale_1 = require("@headless-adminapp/app/locale");
|
|
@@ -12,7 +13,6 @@ const react_1 = require("react");
|
|
|
12
13
|
const react_hook_form_1 = require("react-hook-form");
|
|
13
14
|
const BodyLoading_1 = require("../../components/BodyLoading");
|
|
14
15
|
const EventFormContent_1 = require("./EventFormContent");
|
|
15
|
-
const utils_1 = require("./utils");
|
|
16
16
|
function EventFormBody(props) {
|
|
17
17
|
const { language, region } = (0, locale_1.useLocale)();
|
|
18
18
|
const formValidationStrings = (0, form_1.useFormValidationStrings)();
|
|
@@ -29,7 +29,7 @@ function EventFormBody(props) {
|
|
|
29
29
|
mode: 'all',
|
|
30
30
|
defaultValues: props.values,
|
|
31
31
|
shouldUnregister: false,
|
|
32
|
-
resolver: (0,
|
|
32
|
+
resolver: (0, dataform_1.attributesFormValidator)({
|
|
33
33
|
attributes: baseEventAttributes_1.baseEventAttributes,
|
|
34
34
|
language,
|
|
35
35
|
strings: formValidationStrings,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SectionQuickViewControl } from '@headless-adminapp/core/experience/form/SectionControl';
|
|
2
|
+
interface QuickViewControlProps {
|
|
3
|
+
labelPosition?: 'top' | 'left';
|
|
4
|
+
control: SectionQuickViewControl;
|
|
5
|
+
}
|
|
6
|
+
export declare function QuickViewControl({ control, labelPosition, }: Readonly<QuickViewControlProps>): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QuickViewControl = QuickViewControl;
|
|
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 hooks_1 = require("@headless-adminapp/app/hooks");
|
|
8
|
+
const metadata_1 = require("@headless-adminapp/app/metadata");
|
|
9
|
+
const transport_1 = require("@headless-adminapp/app/transport");
|
|
10
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
11
|
+
const SectionControl_1 = require("../../DataForm/SectionControl");
|
|
12
|
+
const StandardControl_1 = require("../StandardControl");
|
|
13
|
+
function QuickViewControl({ control, labelPosition, }) {
|
|
14
|
+
const schema = (0, dataform_1.useDataFormSchema)();
|
|
15
|
+
const formInstance = (0, dataform_1.useFormInstance)();
|
|
16
|
+
const { schemaStore } = (0, metadata_1.useMetadata)();
|
|
17
|
+
const attribute = schema.attributes[control.attributeName];
|
|
18
|
+
if (!attribute) {
|
|
19
|
+
console.warn(`Attribute ${control.attributeName} not found in schema`);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (attribute.type !== 'lookup') {
|
|
23
|
+
console.warn(`Attribute ${control.attributeName} is not a lookup field, skipping QuickViewControl.`);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const targetSchema = schemaStore.getSchema(attribute.entity);
|
|
27
|
+
const value = formInstance.watch(control.attributeName);
|
|
28
|
+
if (!value?.id) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return ((0, jsx_runtime_1.jsx)(QuickViewControlInternal, { control: control, labelPosition: labelPosition, targetRecordId: value.id, targetSchema: targetSchema }));
|
|
32
|
+
}
|
|
33
|
+
function QuickViewControlInternal({ labelPosition, control, targetRecordId, targetSchema, }) {
|
|
34
|
+
const isMobile = (0, hooks_1.useIsMobile)();
|
|
35
|
+
const dataService = (0, transport_1.useDataService)();
|
|
36
|
+
const { data, isPending } = (0, react_query_1.useQuery)({
|
|
37
|
+
queryKey: [
|
|
38
|
+
'data',
|
|
39
|
+
'retriveRecord',
|
|
40
|
+
targetSchema.logicalName,
|
|
41
|
+
targetRecordId,
|
|
42
|
+
control.form.attributes,
|
|
43
|
+
],
|
|
44
|
+
queryFn: async () => {
|
|
45
|
+
if (!targetRecordId) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const record = await dataService.retriveRecord(targetSchema.logicalName, targetRecordId, control.form.attributes);
|
|
49
|
+
return record;
|
|
50
|
+
},
|
|
51
|
+
placeholderData: react_query_1.keepPreviousData,
|
|
52
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
53
|
+
});
|
|
54
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
55
|
+
display: 'flex',
|
|
56
|
+
flexDirection: 'column',
|
|
57
|
+
gap: react_components_1.tokens.spacingVerticalM,
|
|
58
|
+
}, children: control.form.attributes.map((attributeName) => {
|
|
59
|
+
const attribute = targetSchema.attributes[attributeName];
|
|
60
|
+
if (!attribute) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return ((0, jsx_runtime_1.jsx)(SectionControl_1.SectionControlWrapper, { label: attribute.label, labelPosition: isMobile ? 'top' : labelPosition, children: (0, jsx_runtime_1.jsx)(StandardControl_1.StandardControl, { attribute: attribute, name: attributeName, value: data?.[attributeName] ?? null, onChange: () => {
|
|
64
|
+
// do nothing
|
|
65
|
+
}, readOnly: true, label: attribute.label, placeholder: attribute.label, allowNavigation: true, allowNewRecord: false, skeleton: isPending }) }, attributeName));
|
|
66
|
+
}) }));
|
|
67
|
+
}
|
|
@@ -19,6 +19,7 @@ const componentStore_1 = require("../componentStore");
|
|
|
19
19
|
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
20
20
|
const layout_1 = require("../form/layout");
|
|
21
21
|
const EditableGridControl_1 = require("./EditableGridControl/EditableGridControl");
|
|
22
|
+
const QuickViewControl_1 = require("./QuickViewControl");
|
|
22
23
|
const StandardControl_1 = require("./StandardControl");
|
|
23
24
|
const SubgridControl_1 = require("./SubgridControl");
|
|
24
25
|
function SectionContainer({ section, skeleton, }) {
|
|
@@ -113,7 +114,7 @@ function SectionContainer({ section, skeleton, }) {
|
|
|
113
114
|
return ((0, jsx_runtime_1.jsx)(EditableGridControl_1.EditableGridControl, { readOnly: disabled, control: control }));
|
|
114
115
|
}
|
|
115
116
|
case 'quickview':
|
|
116
|
-
return
|
|
117
|
+
return ((0, jsx_runtime_1.jsx)(QuickViewControl_1.QuickViewControl, { control: control, labelPosition: section.labelPosition }));
|
|
117
118
|
case 'subgrid': {
|
|
118
119
|
let ContainerComponent = null;
|
|
119
120
|
if (control.component) {
|
|
@@ -83,7 +83,7 @@ const StandardControl = (props) => {
|
|
|
83
83
|
switch (attribute.format) {
|
|
84
84
|
case 'text': {
|
|
85
85
|
const Control = componentStore_1.componentStore.getComponent('Form.TextControl') ?? TextControl_1.TextControl;
|
|
86
|
-
return ((0, jsx_runtime_1.jsx)(Control, { ...controlProps, textTransform: attribute.textTransform }));
|
|
86
|
+
return ((0, jsx_runtime_1.jsx)(Control, { ...controlProps, textTransform: attribute.textTransform, suggestions: attribute.suggestions }));
|
|
87
87
|
}
|
|
88
88
|
case 'email': {
|
|
89
89
|
const Control = componentStore_1.componentStore.getComponent('Form.EmailControl') ?? EmailControl_1.EmailControl;
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { InputProps } from '@fluentui/react-components';
|
|
2
|
+
import { SuggestionOptions } from '@headless-adminapp/core/attributes/StringAttribute';
|
|
3
|
+
import { FC } from 'react';
|
|
2
4
|
import { ControlProps } from './types';
|
|
5
|
+
export declare function useSuggestions({ searchText, readOnly, }: {
|
|
6
|
+
searchText: string;
|
|
7
|
+
readOnly: boolean;
|
|
8
|
+
}): {
|
|
9
|
+
data: string[];
|
|
10
|
+
open: boolean;
|
|
11
|
+
setOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
12
|
+
onData: (data: string[]) => void;
|
|
13
|
+
lookupEnabled: boolean;
|
|
14
|
+
debouncedSearchText: string;
|
|
15
|
+
};
|
|
3
16
|
export interface TextControlProps extends ControlProps<string> {
|
|
4
17
|
autoComplete?: string;
|
|
5
18
|
autoCapitalize?: string;
|
|
@@ -7,5 +20,19 @@ export interface TextControlProps extends ControlProps<string> {
|
|
|
7
20
|
textTransform?: 'capitalize' | 'uppercase' | 'lowercase' | 'none';
|
|
8
21
|
appearance?: InputProps['appearance'];
|
|
9
22
|
maxLength?: number;
|
|
23
|
+
suggestions?: SuggestionOptions;
|
|
10
24
|
}
|
|
11
|
-
export declare function TextControl({ value, onChange, id, name, onBlur, onFocus, placeholder, disabled, autoComplete, autoFocus, autoCapitalize, autoCorrect, textTransform, readOnly, appearance, maxLength, skeleton, }: Readonly<TextControlProps>): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare function TextControl({ value, onChange, id, name, onBlur, onFocus, placeholder, disabled, autoComplete, autoFocus, autoCapitalize, autoCorrect, textTransform, readOnly, appearance, maxLength, skeleton, suggestions, }: Readonly<TextControlProps>): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare const DynamicSuggestionLoader: FC<{
|
|
27
|
+
entity: string;
|
|
28
|
+
field: string;
|
|
29
|
+
searchText: string;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
onData: (data: string[]) => void;
|
|
32
|
+
}>;
|
|
33
|
+
export declare const StaticSuggestionLoader: FC<{
|
|
34
|
+
values: string[];
|
|
35
|
+
searchText: string;
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
onData: (data: string[]) => void;
|
|
38
|
+
}>;
|
|
@@ -1,20 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StaticSuggestionLoader = exports.DynamicSuggestionLoader = void 0;
|
|
4
|
+
exports.useSuggestions = useSuggestions;
|
|
3
5
|
exports.TextControl = TextControl;
|
|
4
6
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
7
|
const react_components_1 = require("@fluentui/react-components");
|
|
8
|
+
const hooks_1 = require("@headless-adminapp/app/hooks");
|
|
9
|
+
const metadata_1 = require("@headless-adminapp/app/metadata");
|
|
10
|
+
const useRetriveRecords_1 = require("@headless-adminapp/app/transport/hooks/useRetriveRecords");
|
|
11
|
+
const lodash_1 = require("lodash");
|
|
12
|
+
const react_1 = require("react");
|
|
6
13
|
const SkeletonControl_1 = require("./SkeletonControl");
|
|
14
|
+
function useSuggestions({ searchText, readOnly, }) {
|
|
15
|
+
const [debouncedSearchText] = (0, hooks_1.useDebouncedValue)(searchText, 500);
|
|
16
|
+
const [data, setData] = (0, react_1.useState)([]);
|
|
17
|
+
const [open, setOpen] = (0, react_1.useState)(false);
|
|
18
|
+
const [lookupEnabled, setLookupEnabled] = (0, react_1.useState)(false);
|
|
19
|
+
const onData = (0, react_1.useCallback)((data) => {
|
|
20
|
+
setData(data);
|
|
21
|
+
}, []);
|
|
22
|
+
(0, react_1.useEffect)(() => {
|
|
23
|
+
if (open && !readOnly)
|
|
24
|
+
setLookupEnabled(true);
|
|
25
|
+
}, [open, readOnly]);
|
|
26
|
+
return { data, open, setOpen, onData, lookupEnabled, debouncedSearchText };
|
|
27
|
+
}
|
|
7
28
|
function TextControl({ value, onChange, id, name, onBlur, onFocus,
|
|
8
29
|
// error,
|
|
9
30
|
placeholder, disabled, autoComplete, autoFocus, autoCapitalize, autoCorrect, textTransform,
|
|
10
31
|
// borderOnFocusOnly,
|
|
11
|
-
readOnly, appearance = 'filled-darker', maxLength, skeleton, }) {
|
|
32
|
+
readOnly, appearance = 'filled-darker', maxLength, skeleton, suggestions, }) {
|
|
12
33
|
const readonly = disabled || readOnly;
|
|
34
|
+
const { data, open, setOpen, lookupEnabled, onData, debouncedSearchText } = useSuggestions({
|
|
35
|
+
searchText: value ?? '',
|
|
36
|
+
readOnly: !!readonly,
|
|
37
|
+
});
|
|
13
38
|
if (skeleton) {
|
|
14
39
|
return (0, jsx_runtime_1.jsx)(SkeletonControl_1.SkeletonControl, {});
|
|
15
40
|
}
|
|
16
|
-
const handleOnChange = (
|
|
17
|
-
let value = e.target.value;
|
|
41
|
+
const handleOnChange = (value) => {
|
|
18
42
|
if (textTransform === 'uppercase') {
|
|
19
43
|
value = value.toUpperCase();
|
|
20
44
|
}
|
|
@@ -23,7 +47,19 @@ readOnly, appearance = 'filled-darker', maxLength, skeleton, }) {
|
|
|
23
47
|
}
|
|
24
48
|
onChange?.(value);
|
|
25
49
|
};
|
|
26
|
-
|
|
50
|
+
if (suggestions) {
|
|
51
|
+
return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_components_1.Combobox, { autoCapitalize: "none", autoCorrect: "off", placeholder: placeholder, appearance: "filled-darker", spellCheck: false, autoComplete: "off", freeform: true, id: id, name: name, autoFocus: autoFocus, maxLength: maxLength, style: { width: '100%', minWidth: 'unset' }, input: { style: { width: '100%' } }, expandIcon: null, open: open && !!data.length && !readOnly, onOpenChange: (e, data) => {
|
|
52
|
+
if (!data.open) {
|
|
53
|
+
setOpen(data.open);
|
|
54
|
+
}
|
|
55
|
+
}, value: value ?? '', onChange: (e) => {
|
|
56
|
+
handleOnChange(e.target.value);
|
|
57
|
+
setOpen(true);
|
|
58
|
+
}, onBlur: () => onBlur?.(), onFocus: () => onFocus?.(), onOptionSelect: (e, item) => {
|
|
59
|
+
onChange?.(item.optionText ?? '');
|
|
60
|
+
}, children: data.map((item) => ((0, jsx_runtime_1.jsx)(react_components_1.Option, { value: item, checkIcon: null, children: item }, item))) }), suggestions?.type === 'static' && ((0, jsx_runtime_1.jsx)(exports.StaticSuggestionLoader, { values: suggestions.values, disabled: !lookupEnabled, onData: onData, searchText: debouncedSearchText })), suggestions?.type === 'dynamic' && ((0, jsx_runtime_1.jsx)(exports.DynamicSuggestionLoader, { entity: suggestions.entity, field: suggestions.field, disabled: !lookupEnabled, searchText: debouncedSearchText, onData: onData }))] }));
|
|
61
|
+
}
|
|
62
|
+
return ((0, jsx_runtime_1.jsx)(react_components_1.Input, { placeholder: placeholder, id: id, name: name, autoFocus: autoFocus, appearance: appearance, value: value ?? '', onChange: (e) => handleOnChange(e.target.value), onBlur: () => onBlur?.(), onFocus: () => onFocus?.(),
|
|
27
63
|
// invalid={error}
|
|
28
64
|
// readOnly={readOnly || disabled}
|
|
29
65
|
readOnly: readonly, autoComplete: autoComplete, autoCorrect: autoCorrect, autoCapitalize: autoCapitalize, className: (0, react_components_1.mergeClasses)(readonly && 'TextControl_readonly'), style: {
|
|
@@ -34,3 +70,53 @@ readOnly, appearance = 'filled-darker', maxLength, skeleton, }) {
|
|
|
34
70
|
},
|
|
35
71
|
} }));
|
|
36
72
|
}
|
|
73
|
+
const DynamicSuggestionLoader = ({ entity, field, searchText, disabled, onData }) => {
|
|
74
|
+
const { schemaStore } = (0, metadata_1.useMetadata)();
|
|
75
|
+
const schema = schemaStore.getSchema(entity);
|
|
76
|
+
const { data } = (0, useRetriveRecords_1.useRetriveRecords)({
|
|
77
|
+
schema,
|
|
78
|
+
columns: [field],
|
|
79
|
+
disabled: disabled || !searchText,
|
|
80
|
+
maxRecords: 5,
|
|
81
|
+
sorting: [{ field: field, order: 'asc' }],
|
|
82
|
+
filter: {
|
|
83
|
+
type: 'and',
|
|
84
|
+
conditions: [
|
|
85
|
+
{
|
|
86
|
+
field,
|
|
87
|
+
operator: 'like',
|
|
88
|
+
value: searchText,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const onDataRef = (0, react_1.useRef)(onData);
|
|
94
|
+
onDataRef.current = onData;
|
|
95
|
+
(0, react_1.useEffect)(() => {
|
|
96
|
+
if (!searchText) {
|
|
97
|
+
onDataRef.current([]);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (data) {
|
|
101
|
+
onDataRef.current((0, lodash_1.uniq)(data.records.map((item) => item[field])));
|
|
102
|
+
}
|
|
103
|
+
}, [searchText, data, field]);
|
|
104
|
+
return null;
|
|
105
|
+
};
|
|
106
|
+
exports.DynamicSuggestionLoader = DynamicSuggestionLoader;
|
|
107
|
+
const StaticSuggestionLoader = ({ values, searchText, disabled, onData }) => {
|
|
108
|
+
const onDataRef = (0, react_1.useRef)(onData);
|
|
109
|
+
onDataRef.current = onData;
|
|
110
|
+
(0, react_1.useEffect)(() => {
|
|
111
|
+
if (!searchText || disabled) {
|
|
112
|
+
onDataRef.current([]);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const filtered = values.filter((item) => item.toLowerCase().includes(searchText.toLowerCase()));
|
|
116
|
+
if (filtered.length) {
|
|
117
|
+
onDataRef.current((0, lodash_1.uniq)(filtered));
|
|
118
|
+
}
|
|
119
|
+
}, [searchText, disabled, values]);
|
|
120
|
+
return null;
|
|
121
|
+
};
|
|
122
|
+
exports.StaticSuggestionLoader = StaticSuggestionLoader;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useFormForAttributes = useFormForAttributes;
|
|
4
|
+
const dataform_1 = require("@headless-adminapp/app/dataform");
|
|
4
5
|
const form_1 = require("@headless-adminapp/app/form");
|
|
5
6
|
const locale_1 = require("@headless-adminapp/app/locale");
|
|
6
7
|
const react_hook_form_1 = require("react-hook-form");
|
|
7
|
-
const PromptDialog_1 = require("../DialogContainer/PromptDialog");
|
|
8
8
|
function useFormForAttributes(props) {
|
|
9
9
|
const { language, region } = (0, locale_1.useLocale)();
|
|
10
10
|
const formValidationStrings = (0, form_1.useFormValidationStrings)();
|
|
@@ -12,7 +12,7 @@ function useFormForAttributes(props) {
|
|
|
12
12
|
mode: 'all',
|
|
13
13
|
defaultValues: props.defaultValues,
|
|
14
14
|
shouldUnregister: false,
|
|
15
|
-
resolver: (0,
|
|
15
|
+
resolver: (0, dataform_1.attributesFormValidator)({
|
|
16
16
|
attributes: props.attributes,
|
|
17
17
|
language,
|
|
18
18
|
strings: formValidationStrings,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@headless-adminapp/fluent",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.24",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -51,5 +51,8 @@
|
|
|
51
51
|
"uuid": "11.0.3",
|
|
52
52
|
"yup": "^1.4.0"
|
|
53
53
|
},
|
|
54
|
-
"
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/lodash": "4.17.20"
|
|
56
|
+
},
|
|
57
|
+
"gitHead": "3a4c06f1e18f8ac7861647b82d4a4f8cd8f0141c"
|
|
55
58
|
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { FormValidationStringSet } from '@headless-adminapp/app/form';
|
|
2
|
-
import { SchemaAttributes } from '@headless-adminapp/core/schema';
|
|
3
|
-
import * as yup from 'yup';
|
|
4
|
-
export declare const formValidator: (<A extends SchemaAttributes = SchemaAttributes>({ attributes, language, strings, region, }: {
|
|
5
|
-
attributes: A;
|
|
6
|
-
language: string;
|
|
7
|
-
strings: FormValidationStringSet;
|
|
8
|
-
region: string;
|
|
9
|
-
}) => (values: Record<string, any>, context: any, options: any) => Promise<import("react-hook-form").ResolverResult<{
|
|
10
|
-
[x: string]: any;
|
|
11
|
-
[x: number]: any;
|
|
12
|
-
[x: symbol]: any;
|
|
13
|
-
}>>) & import("lodash").MemoizedFunction;
|
|
14
|
-
export declare const generateValidationSchema: (<A extends SchemaAttributes = SchemaAttributes>({ attributes, language, strings, region, }: {
|
|
15
|
-
attributes: A;
|
|
16
|
-
language: string;
|
|
17
|
-
strings: FormValidationStringSet;
|
|
18
|
-
region: string;
|
|
19
|
-
}) => yup.ObjectSchema<{
|
|
20
|
-
[x: string]: any;
|
|
21
|
-
}, yup.AnyObject, {
|
|
22
|
-
[x: string]: any;
|
|
23
|
-
}, "">) & import("lodash").MemoizedFunction;
|
|
@@ -1,57 +0,0 @@
|
|
|
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
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.generateValidationSchema = exports.formValidator = void 0;
|
|
27
|
-
const utils_1 = require("@headless-adminapp/app/dataform/utils");
|
|
28
|
-
const yup_1 = require("@hookform/resolvers/yup");
|
|
29
|
-
const lodash_1 = require("lodash");
|
|
30
|
-
const yup = __importStar(require("yup"));
|
|
31
|
-
// TODO: refactor duplicate code
|
|
32
|
-
exports.formValidator = (0, lodash_1.memoize)(function formValidator({ attributes, language, strings, region, }) {
|
|
33
|
-
return async (values, context, options) => {
|
|
34
|
-
const validator = (0, exports.generateValidationSchema)({
|
|
35
|
-
attributes,
|
|
36
|
-
language,
|
|
37
|
-
strings,
|
|
38
|
-
region,
|
|
39
|
-
});
|
|
40
|
-
const resolver = (0, yup_1.yupResolver)(validator);
|
|
41
|
-
const result = await resolver(values, context, options);
|
|
42
|
-
return result;
|
|
43
|
-
};
|
|
44
|
-
}, (options) => JSON.stringify(options));
|
|
45
|
-
exports.generateValidationSchema = (0, lodash_1.memoize)(function generateValidationSchema({ attributes, language, strings, region, }) {
|
|
46
|
-
const columns = Object.keys(attributes);
|
|
47
|
-
return yup.object().shape({
|
|
48
|
-
...columns.reduce((acc, column) => {
|
|
49
|
-
const attribute = attributes[column];
|
|
50
|
-
const validationSchema = (0, utils_1.generateAttributeValidationSchema)(attribute, language, strings, region);
|
|
51
|
-
return {
|
|
52
|
-
...acc,
|
|
53
|
-
[column]: validationSchema,
|
|
54
|
-
};
|
|
55
|
-
}, {}),
|
|
56
|
-
});
|
|
57
|
-
}, (options) => JSON.stringify(options));
|