@headless-adminapp/fluent 0.0.17-alpha.56 → 0.0.17-alpha.59
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/useTableColumns.js +14 -0
- package/DialogContainer/PromptDialog.d.ts +12 -2
- package/DialogContainer/PromptDialog.js +18 -8
- package/PageEntityForm/PageEntityFormDesktopContainer.js +3 -2
- package/PageEntityForm/RecordAvatar.d.ts +2 -0
- package/PageEntityForm/RecordAvatar.js +79 -0
- package/PageEntityForm/SubgridControl.js +3 -1
- package/PageEntityForm/UploadImageDialog.d.ts +12 -0
- package/PageEntityForm/UploadImageDialog.js +111 -0
- package/PageEntityView/FormSubgridNotAvailableContainer.d.ts +2 -0
- package/PageEntityView/FormSubgridNotAvailableContainer.js +48 -0
- package/PageEntityView/PageEntityViewStringContext.d.ts +1 -0
- package/PageEntityView/PageEntityViewStringContext.js +1 -0
- package/form/controls/AttachmentControl.d.ts +10 -0
- package/form/controls/AttachmentControl.js +4 -0
- package/form/controls/LookupControl.js +6 -1
- package/form/controls/TelephoneControl.d.ts +1 -1
- package/form/controls/TelephoneControl.js +24 -2
- package/package.json +2 -2
- package/types/index.d.ts +2 -0
|
@@ -13,6 +13,7 @@ const mutable_1 = require("@headless-adminapp/app/mutable");
|
|
|
13
13
|
const hooks_4 = require("@headless-adminapp/app/recordset/hooks");
|
|
14
14
|
const hooks_5 = require("@headless-adminapp/app/route/hooks");
|
|
15
15
|
const utils_1 = require("@headless-adminapp/app/utils");
|
|
16
|
+
const phone_1 = require("@headless-adminapp/app/utils/phone");
|
|
16
17
|
const app_1 = require("@headless-adminapp/core/experience/app");
|
|
17
18
|
const react_table_1 = require("@tanstack/react-table");
|
|
18
19
|
const react_1 = require("react");
|
|
@@ -264,6 +265,7 @@ function renderCellContent({ info, column, schema, schemaStore, locale, routeRes
|
|
|
264
265
|
currencyDisplay: currency.currencyDisplay,
|
|
265
266
|
currencySign: currency.currencySign,
|
|
266
267
|
locale: locale.locale,
|
|
268
|
+
region: locale.region,
|
|
267
269
|
}) ?? '';
|
|
268
270
|
if (column.plainText) {
|
|
269
271
|
return ((0, jsx_runtime_1.jsx)(TableCell_1.TableCellText, { value: formattedValue, width: info.column.getSize() }, column.id));
|
|
@@ -311,6 +313,18 @@ function renderCellContent({ info, column, schema, schemaStore, locale, routeRes
|
|
|
311
313
|
case 'choice':
|
|
312
314
|
return ((0, jsx_runtime_1.jsx)(TableCellChoice_1.TableCellChoice, { column: column, schema: schema, record: info.row.original, value: value, attribute: attribute, formattedValue: formattedValue, width: info.column.getSize() }));
|
|
313
315
|
}
|
|
316
|
+
if (attribute.type === 'string' && attribute.format === 'phone') {
|
|
317
|
+
const parsedNumber = (0, phone_1.parsePhoneNumber)(value, locale.region);
|
|
318
|
+
if (parsedNumber.isValid && parsedNumber.uri) {
|
|
319
|
+
return ((0, jsx_runtime_1.jsx)(TableCellLink_1.TableCellLink, { value: formattedValue, width: info.column.getSize(), href: parsedNumber.uri }, column.id));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (attribute.type === 'string' &&
|
|
323
|
+
attribute.format === 'email' &&
|
|
324
|
+
value &&
|
|
325
|
+
typeof value === 'string') {
|
|
326
|
+
return ((0, jsx_runtime_1.jsx)(TableCellLink_1.TableCellLink, { value: formattedValue, width: info.column.getSize(), href: `mailto:${value}` }, column.id));
|
|
327
|
+
}
|
|
314
328
|
return ((0, jsx_runtime_1.jsx)(TableCell_1.TableCellText, { value: formattedValue, width: info.column.getSize() }, column.id));
|
|
315
329
|
}
|
|
316
330
|
function renderPrimaryAttribute({ info, column, schema, routeResolver, openRecord, value, }) {
|
|
@@ -15,12 +15,22 @@ interface PromptDialogProps<SA extends SchemaAttributes = SchemaAttributes> {
|
|
|
15
15
|
onDismiss?: PromptDialogOptions<SA>['onDismiss'];
|
|
16
16
|
}
|
|
17
17
|
export declare function PromptDialog(props: PromptDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
-
export declare const formValidator: (<A extends SchemaAttributes = SchemaAttributes>(attributes
|
|
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<{
|
|
19
24
|
[x: string]: any;
|
|
20
25
|
[x: number]: any;
|
|
21
26
|
[x: symbol]: any;
|
|
22
27
|
}>>) & import("lodash").MemoizedFunction;
|
|
23
|
-
export declare const generateValidationSchema: (<A extends SchemaAttributes = SchemaAttributes>(attributes
|
|
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<{
|
|
24
34
|
[x: string]: any;
|
|
25
35
|
}, yup.AnyObject, {
|
|
26
36
|
[x: string]: any;
|
|
@@ -37,13 +37,18 @@ const yup = __importStar(require("yup"));
|
|
|
37
37
|
const SectionControl_1 = require("../DataForm/SectionControl");
|
|
38
38
|
const StandardControl_1 = require("../PageEntityForm/StandardControl");
|
|
39
39
|
function PromptDialog(props) {
|
|
40
|
-
const { language } = (0, locale_1.useLocale)();
|
|
40
|
+
const { language, region } = (0, locale_1.useLocale)();
|
|
41
41
|
const formValidationStrings = (0, form_1.useFormValidationStrings)();
|
|
42
42
|
const form = (0, react_hook_form_1.useForm)({
|
|
43
43
|
mode: 'all',
|
|
44
44
|
defaultValues: props.defaultValues,
|
|
45
45
|
shouldUnregister: false,
|
|
46
|
-
resolver: (0, exports.formValidator)(
|
|
46
|
+
resolver: (0, exports.formValidator)({
|
|
47
|
+
attributes: props.attributes,
|
|
48
|
+
language,
|
|
49
|
+
strings: formValidationStrings,
|
|
50
|
+
region,
|
|
51
|
+
}),
|
|
47
52
|
});
|
|
48
53
|
return ((0, jsx_runtime_1.jsx)(react_components_1.Dialog, { open: props.open, onOpenChange: () => {
|
|
49
54
|
props.onDismiss?.();
|
|
@@ -70,24 +75,29 @@ function PromptDialog(props) {
|
|
|
70
75
|
})();
|
|
71
76
|
}, children: props.confirmText ?? 'Confirm' })] })] }) }) }));
|
|
72
77
|
}
|
|
73
|
-
exports.formValidator = (0, lodash_1.memoize)(function formValidator(attributes, language, strings) {
|
|
78
|
+
exports.formValidator = (0, lodash_1.memoize)(function formValidator({ attributes, language, strings, region, }) {
|
|
74
79
|
return async (values, context, options) => {
|
|
75
|
-
const validator = (0, exports.generateValidationSchema)(
|
|
80
|
+
const validator = (0, exports.generateValidationSchema)({
|
|
81
|
+
attributes,
|
|
82
|
+
language,
|
|
83
|
+
strings,
|
|
84
|
+
region,
|
|
85
|
+
});
|
|
76
86
|
const resolver = (0, yup_1.yupResolver)(validator);
|
|
77
87
|
const result = await resolver(values, context, options);
|
|
78
88
|
return result;
|
|
79
89
|
};
|
|
80
|
-
}, (
|
|
81
|
-
exports.generateValidationSchema = (0, lodash_1.memoize)(function generateValidationSchema(attributes, language, strings) {
|
|
90
|
+
}, (options) => JSON.stringify(options));
|
|
91
|
+
exports.generateValidationSchema = (0, lodash_1.memoize)(function generateValidationSchema({ attributes, language, strings, region, }) {
|
|
82
92
|
const columns = Object.keys(attributes);
|
|
83
93
|
return yup.object().shape({
|
|
84
94
|
...columns.reduce((acc, column) => {
|
|
85
95
|
const attribute = attributes[column];
|
|
86
|
-
const validationSchema = (0, utils_1.generateAttributeValidationSchema)(attribute, language, strings);
|
|
96
|
+
const validationSchema = (0, utils_1.generateAttributeValidationSchema)(attribute, language, strings, region);
|
|
87
97
|
return {
|
|
88
98
|
...acc,
|
|
89
99
|
[column]: validationSchema,
|
|
90
100
|
};
|
|
91
101
|
}, {}),
|
|
92
102
|
});
|
|
93
|
-
}, (
|
|
103
|
+
}, (options) => JSON.stringify(options));
|
|
@@ -19,6 +19,7 @@ const CommandContainer_1 = require("./CommandContainer");
|
|
|
19
19
|
const FormTabRelated_1 = require("./FormTabRelated");
|
|
20
20
|
const PageEntityFormStringContext_1 = require("./PageEntityFormStringContext");
|
|
21
21
|
const ProcessFlow_1 = require("./ProcessFlow");
|
|
22
|
+
const RecordAvatar_1 = require("./RecordAvatar");
|
|
22
23
|
const RelatedViewSelector_1 = require("./RelatedViewSelector");
|
|
23
24
|
const SectionContainer_1 = require("./SectionContainer");
|
|
24
25
|
let previousCachedActiveTabInfo = null;
|
|
@@ -53,7 +54,7 @@ const PageEntityFormDesktopContainer = () => {
|
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
}, [setActiveTab, formConfig, schema]);
|
|
56
|
-
const recordTitle = (0, hooks_1.useRecordTitle)();
|
|
57
|
+
const [recordTitle] = (0, hooks_1.useRecordTitle)();
|
|
57
58
|
// const readonly = useIsFormReadonly();
|
|
58
59
|
const formInstance = (0, hooks_1.useFormInstance)();
|
|
59
60
|
const isDirty = (0, hooks_1.useFormIsDirty)();
|
|
@@ -101,7 +102,7 @@ const PageEntityFormDesktopContainer = () => {
|
|
|
101
102
|
paddingInline: react_components_1.tokens.spacingHorizontalM,
|
|
102
103
|
paddingTop: react_components_1.tokens.spacingVerticalS,
|
|
103
104
|
marginBottom: react_components_1.tokens.spacingVerticalS,
|
|
104
|
-
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column', flex: 1 }, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
105
|
+
}, children: [(0, jsx_runtime_1.jsx)(RecordAvatar_1.RecordAvatar, {}), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column', flex: 1 }, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
105
106
|
display: 'flex',
|
|
106
107
|
gap: react_components_1.tokens.spacingHorizontalXS,
|
|
107
108
|
alignItems: 'center',
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecordAvatar = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const app_1 = require("@headless-adminapp/app/app");
|
|
7
|
+
const dataform_1 = require("@headless-adminapp/app/dataform");
|
|
8
|
+
const hooks_1 = require("@headless-adminapp/app/dataform/hooks");
|
|
9
|
+
const dialog_1 = require("@headless-adminapp/app/dialog");
|
|
10
|
+
const mutable_1 = require("@headless-adminapp/app/mutable");
|
|
11
|
+
const progress_indicator_1 = require("@headless-adminapp/app/progress-indicator");
|
|
12
|
+
const transport_1 = require("@headless-adminapp/app/transport");
|
|
13
|
+
const icons_1 = require("@headless-adminapp/icons");
|
|
14
|
+
const react_1 = require("react");
|
|
15
|
+
const avatar_1 = require("../utils/avatar");
|
|
16
|
+
const UploadImageDialog_1 = require("./UploadImageDialog");
|
|
17
|
+
const RecordAvatar = () => {
|
|
18
|
+
const [recordTitle, isPlaceholder] = (0, hooks_1.useRecordTitle)();
|
|
19
|
+
const schema = (0, hooks_1.useDataFormSchema)();
|
|
20
|
+
const record = (0, mutable_1.useContextSelector)(dataform_1.DataFormContext, (state) => state.record);
|
|
21
|
+
const recordId = (0, hooks_1.useRecordId)();
|
|
22
|
+
const { schemaMetadataDic } = (0, app_1.useAppContext)();
|
|
23
|
+
const dataService = (0, transport_1.useDataService)();
|
|
24
|
+
const refresh = (0, mutable_1.useContextSelector)(dataform_1.DataFormContext, (state) => state.refresh);
|
|
25
|
+
const [showAvatarChangeDialog, setShowAvatarChangeDialog] = (0, react_1.useState)(false);
|
|
26
|
+
const { showProgressIndicator, hideProgressIndicator } = (0, progress_indicator_1.useProgressIndicator)();
|
|
27
|
+
const openErrorDialog = (0, dialog_1.useOpenErrorDialog)();
|
|
28
|
+
if (!schema.avatarAttribute) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const avatarAttribute = schema.attributes[schema.avatarAttribute];
|
|
32
|
+
if (avatarAttribute?.type !== 'attachment') {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const value = record?.[schema.avatarAttribute];
|
|
36
|
+
const handleChange = async (value) => {
|
|
37
|
+
if (!recordId) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
console.log('onChange', value);
|
|
41
|
+
try {
|
|
42
|
+
showProgressIndicator();
|
|
43
|
+
await dataService.updateRecord(schema.logicalName, recordId, {
|
|
44
|
+
[schema.avatarAttribute]: value,
|
|
45
|
+
});
|
|
46
|
+
await refresh();
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
openErrorDialog({
|
|
50
|
+
title: 'Error',
|
|
51
|
+
text: 'Unable to update record',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
hideProgressIndicator();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
if (isPlaceholder && !value) {
|
|
59
|
+
const experienceSchema = schemaMetadataDic[schema.logicalName];
|
|
60
|
+
const Icon = experienceSchema.icon ?? icons_1.Icons.Entity ?? icons_1.IconPlaceholder;
|
|
61
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
62
|
+
display: 'flex',
|
|
63
|
+
alignItems: 'flex-start',
|
|
64
|
+
marginRight: react_components_1.tokens.spacingHorizontalM,
|
|
65
|
+
marginTop: 2,
|
|
66
|
+
}, children: (0, jsx_runtime_1.jsx)(react_components_1.Avatar, { style: { width: 36, height: 36 }, icon: (0, jsx_runtime_1.jsx)(Icon, { size: 20 }) }) }));
|
|
67
|
+
}
|
|
68
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
69
|
+
display: 'flex',
|
|
70
|
+
alignItems: 'flex-start',
|
|
71
|
+
marginRight: react_components_1.tokens.spacingHorizontalM,
|
|
72
|
+
marginTop: 2,
|
|
73
|
+
}, children: [(0, jsx_runtime_1.jsx)(react_components_1.Avatar, { style: { width: 36, height: 36 }, name: recordTitle, color: (0, avatar_1.getAvatarColor)(recordTitle), image: {
|
|
74
|
+
src: value?.url,
|
|
75
|
+
}, onClick: () => {
|
|
76
|
+
setShowAvatarChangeDialog(true);
|
|
77
|
+
} }), !!recordId && ((0, jsx_runtime_1.jsx)(UploadImageDialog_1.UploadImageDialog, { recordTitle: recordTitle, currentImage: value, onChange: handleChange, recordId: recordId, open: showAvatarChangeDialog, onOpenChange: (open) => setShowAvatarChangeDialog(open) }))] }));
|
|
78
|
+
};
|
|
79
|
+
exports.RecordAvatar = RecordAvatar;
|
|
@@ -7,6 +7,7 @@ const DataGridProvider_1 = require("@headless-adminapp/app/datagrid/DataGridProv
|
|
|
7
7
|
const hooks_1 = require("@headless-adminapp/app/metadata/hooks");
|
|
8
8
|
const react_1 = require("react");
|
|
9
9
|
const FormSubgridContainer_1 = require("../PageEntityView/FormSubgridContainer");
|
|
10
|
+
const FormSubgridNotAvailableContainer_1 = require("../PageEntityView/FormSubgridNotAvailableContainer");
|
|
10
11
|
function SubgridControl(props) {
|
|
11
12
|
const schema = (0, hooks_1.useSchema)(props.logicalName);
|
|
12
13
|
const [viewId, setViewId] = (0, react_1.useState)(props.viewId);
|
|
@@ -62,5 +63,6 @@ function SubgridControl(props) {
|
|
|
62
63
|
return brokenContent;
|
|
63
64
|
}
|
|
64
65
|
const ContainerComponent = props.ContainerComponent ?? FormSubgridContainer_1.FormSubgridContainer;
|
|
65
|
-
|
|
66
|
+
const disabled = !!props.associated && !props.associated.id;
|
|
67
|
+
return ((0, jsx_runtime_1.jsx)(DataGridProvider_1.DataGridProvider, { schema: schema, view: view, views: viewLookup, onChangeView: setViewId, commands: (props.associated ? subgridCommands : commands), isSubGrid: !!props.associated, associated: props.associated, extraFilter: extraFilter, allowViewSelection: props.allowViewSelection ?? false, disabled: disabled, children: disabled ? (0, jsx_runtime_1.jsx)(FormSubgridNotAvailableContainer_1.FormSubgridNotAvailableContainer, {}) : (0, jsx_runtime_1.jsx)(ContainerComponent, {}) }));
|
|
66
68
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FileObject } from '@headless-adminapp/core/attributes/AttachmentAttribute';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
interface UploadImageDialogProps {
|
|
4
|
+
recordId: string;
|
|
5
|
+
recordTitle: string;
|
|
6
|
+
currentImage: FileObject | null;
|
|
7
|
+
onChange?: (value: FileObject | null) => void;
|
|
8
|
+
open: boolean;
|
|
9
|
+
onOpenChange: (open: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const UploadImageDialog: FC<UploadImageDialogProps>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UploadImageDialog = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const hooks_1 = require("@headless-adminapp/app/dataform/hooks");
|
|
7
|
+
const dialog_1 = require("@headless-adminapp/app/dialog");
|
|
8
|
+
const transport_1 = require("@headless-adminapp/app/transport");
|
|
9
|
+
const utils_1 = require("@headless-adminapp/core/utils");
|
|
10
|
+
const icons_1 = require("@headless-adminapp/icons");
|
|
11
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
12
|
+
const react_1 = require("react");
|
|
13
|
+
const avatar_1 = require("../utils/avatar");
|
|
14
|
+
const UploadImageDialog = ({ currentImage, recordTitle, recordId, onChange, open, onOpenChange, }) => {
|
|
15
|
+
const schema = (0, hooks_1.useDataFormSchema)();
|
|
16
|
+
const fileService = (0, transport_1.useFileService)();
|
|
17
|
+
const [file, setFile] = (0, react_1.useState)(null); // new file (indicate if file is changed)
|
|
18
|
+
const [fileUrl, setFileUrl] = (0, react_1.useState)(null); // file url, indicate that file is either selected or changed
|
|
19
|
+
const openErrorDialog = (0, dialog_1.useOpenErrorDialog)();
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
setFileUrl(currentImage?.url ?? null);
|
|
22
|
+
}, [currentImage?.url]);
|
|
23
|
+
const handleSelectFile = () => {
|
|
24
|
+
const input = document.createElement('input');
|
|
25
|
+
input.type = 'file';
|
|
26
|
+
input.accept = 'image/*';
|
|
27
|
+
input.onchange = async (e) => {
|
|
28
|
+
const files = e.target.files;
|
|
29
|
+
if (!files?.length) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const _file = files[0];
|
|
33
|
+
setFile(_file);
|
|
34
|
+
const dataUrl = await (0, utils_1.readFileAsDataURL)(_file);
|
|
35
|
+
setFileUrl(dataUrl);
|
|
36
|
+
};
|
|
37
|
+
input.click();
|
|
38
|
+
};
|
|
39
|
+
const { isPending, mutate: handleApply } = (0, react_query_1.useMutation)({
|
|
40
|
+
mutationFn: async () => {
|
|
41
|
+
if (file) {
|
|
42
|
+
const url = await fileService.uploadFile(file, {
|
|
43
|
+
context: {
|
|
44
|
+
type: 'entity-form',
|
|
45
|
+
recordId,
|
|
46
|
+
attributeName: schema.avatarAttribute,
|
|
47
|
+
logicalName: schema.logicalName,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
onChange?.({
|
|
51
|
+
name: file.name,
|
|
52
|
+
size: file.size,
|
|
53
|
+
type: file.type,
|
|
54
|
+
url,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
onChange?.(null);
|
|
59
|
+
}
|
|
60
|
+
onOpenChange(false);
|
|
61
|
+
},
|
|
62
|
+
onError: (error) => {
|
|
63
|
+
console.error(error);
|
|
64
|
+
openErrorDialog({
|
|
65
|
+
title: 'Error',
|
|
66
|
+
text: 'Unable to upload image',
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
// No image - No image selected - Upload Image
|
|
71
|
+
// No image - Image selected - Change, Cancel
|
|
72
|
+
// Image - Not changed - Upload Image, Use Default
|
|
73
|
+
// Image - Removed - Change, Cancel
|
|
74
|
+
// Image - Changed - Change, Cancel
|
|
75
|
+
const isFileChanged = (fileUrl ?? null) !== (currentImage?.url ?? null);
|
|
76
|
+
const showUploadImage = !isFileChanged;
|
|
77
|
+
const showChangeImage = !!isFileChanged;
|
|
78
|
+
const showResetImage = !isFileChanged && !!fileUrl;
|
|
79
|
+
const showCancel = isFileChanged;
|
|
80
|
+
return ((0, jsx_runtime_1.jsx)(react_components_1.Dialog, { open: open, onOpenChange: (e, data) => onOpenChange(data.open), children: (0, jsx_runtime_1.jsx)(react_components_1.DialogSurface, { style: { maxWidth: 480 }, children: (0, jsx_runtime_1.jsxs)(react_components_1.DialogBody, { children: [(0, jsx_runtime_1.jsx)(react_components_1.DialogTitle, { action: (0, jsx_runtime_1.jsx)(react_components_1.DialogTrigger, { action: "close", children: (0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "subtle", "aria-label": "close", icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Close, {}) }) }), children: "Choose Image" }), (0, jsx_runtime_1.jsx)(react_components_1.DialogContent, { children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { children: "Upload an image from your device, or use the default image" }), (0, jsx_runtime_1.jsx)("div", { style: {
|
|
81
|
+
marginTop: react_components_1.tokens.spacingVerticalM,
|
|
82
|
+
marginBottom: react_components_1.tokens.spacingVerticalM,
|
|
83
|
+
display: 'flex',
|
|
84
|
+
alignItems: 'center',
|
|
85
|
+
justifyContent: 'center',
|
|
86
|
+
}, children: (0, jsx_runtime_1.jsx)(react_components_1.Avatar, { shape: "square", style: { width: 120, height: 120 }, name: recordTitle, color: (0, avatar_1.getAvatarColor)(recordTitle), image: {
|
|
87
|
+
src: fileUrl ?? undefined,
|
|
88
|
+
} }) })] }) }), (0, jsx_runtime_1.jsxs)(react_components_1.DialogActions, { children: [showChangeImage && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "primary", onClick: () => handleApply(), style: {
|
|
89
|
+
whiteSpace: 'nowrap',
|
|
90
|
+
fontWeight: 'normal',
|
|
91
|
+
}, disabled: isPending, children: isPending ? 'Changing...' : 'Change' })), showUploadImage && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "primary", onClick: handleSelectFile, style: {
|
|
92
|
+
whiteSpace: 'nowrap',
|
|
93
|
+
// minWidth: 0,
|
|
94
|
+
fontWeight: 'normal',
|
|
95
|
+
}, children: "Upload Image" })), showResetImage && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { style: {
|
|
96
|
+
whiteSpace: 'nowrap',
|
|
97
|
+
// minWidth: 0,
|
|
98
|
+
fontWeight: 'normal',
|
|
99
|
+
}, onClick: () => {
|
|
100
|
+
setFileUrl(null);
|
|
101
|
+
setFile(null);
|
|
102
|
+
}, children: "Reset to Default" })), showCancel && ((0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "secondary", style: {
|
|
103
|
+
whiteSpace: 'nowrap',
|
|
104
|
+
// minWidth: 0,
|
|
105
|
+
fontWeight: 'normal',
|
|
106
|
+
}, onClick: () => {
|
|
107
|
+
setFileUrl(currentImage?.url ?? null);
|
|
108
|
+
setFile(null);
|
|
109
|
+
}, children: "Cancel" }))] })] }) }) }));
|
|
110
|
+
};
|
|
111
|
+
exports.UploadImageDialog = UploadImageDialog;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FormSubgridNotAvailableContainer = 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 FormSubgridViewSelector_1 = require("../DataGrid/FormSubgridViewSelector");
|
|
8
|
+
const PageEntityViewStringContext_1 = require("./PageEntityViewStringContext");
|
|
9
|
+
const FormSubgridNotAvailableContainer = () => {
|
|
10
|
+
const strings = (0, PageEntityViewStringContext_1.usePageEntityViewStrings)();
|
|
11
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
12
|
+
display: 'flex',
|
|
13
|
+
flex: 1,
|
|
14
|
+
flexDirection: 'column',
|
|
15
|
+
gap: 8,
|
|
16
|
+
overflow: 'hidden',
|
|
17
|
+
}, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
18
|
+
// gap: 12,
|
|
19
|
+
flex: 1,
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: 'column',
|
|
22
|
+
// overflow: 'hidden',
|
|
23
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
24
|
+
display: 'flex',
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
height: 40,
|
|
28
|
+
}, children: (0, jsx_runtime_1.jsx)(FormSubgridViewSelector_1.FormSubgridViewSelector, {}) }), (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: {
|
|
29
|
+
flex: 1,
|
|
30
|
+
display: 'flex',
|
|
31
|
+
flexDirection: 'column',
|
|
32
|
+
}, children: (0, jsx_runtime_1.jsx)("div", { style: {
|
|
33
|
+
gap: 16,
|
|
34
|
+
display: 'flex',
|
|
35
|
+
flexDirection: 'column',
|
|
36
|
+
flex: 1,
|
|
37
|
+
}, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
38
|
+
flex: 1,
|
|
39
|
+
display: 'flex',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
justifyContent: 'center',
|
|
42
|
+
flexDirection: 'column',
|
|
43
|
+
gap: react_components_1.tokens.spacingVerticalM,
|
|
44
|
+
minHeight: 300,
|
|
45
|
+
color: react_components_1.tokens.colorNeutralForeground3,
|
|
46
|
+
}, children: [(0, jsx_runtime_1.jsx)(icons_1.Icons.Grid, { size: 48 }), (0, jsx_runtime_1.jsx)(react_components_1.Body1, { children: strings.subgridNotAvailable })] }) }) })] }) }));
|
|
47
|
+
};
|
|
48
|
+
exports.FormSubgridNotAvailableContainer = FormSubgridNotAvailableContainer;
|
|
@@ -18,6 +18,7 @@ export interface PageEntityViewStringSet {
|
|
|
18
18
|
clearFilter: string;
|
|
19
19
|
filterBy: string;
|
|
20
20
|
noRecordsFound: string;
|
|
21
|
+
subgridNotAvailable: string;
|
|
21
22
|
}
|
|
22
23
|
export declare const defaultPageEntityViewStrings: PageEntityViewStringSet;
|
|
23
24
|
export declare const PageEntityViewStringContext: import("react").Context<PageEntityViewStringSet>;
|
|
@@ -23,6 +23,7 @@ exports.defaultPageEntityViewStrings = {
|
|
|
23
23
|
sortByDescending: 'Sort by descending',
|
|
24
24
|
filterBy: 'Filter by',
|
|
25
25
|
noRecordsFound: "We didn't find anything to show here",
|
|
26
|
+
subgridNotAvailable: 'Save the record to view associated records.',
|
|
26
27
|
};
|
|
27
28
|
exports.PageEntityViewStringContext = (0, react_1.createContext)(exports.defaultPageEntityViewStrings);
|
|
28
29
|
function usePageEntityViewStrings() {
|
|
@@ -2,6 +2,16 @@ import { AttachmentAttribute, FileObject } from '@headless-adminapp/core/attribu
|
|
|
2
2
|
import { IFileService } from '@headless-adminapp/core/transport';
|
|
3
3
|
import { FC } from 'react';
|
|
4
4
|
import { ControlProps } from './types';
|
|
5
|
+
interface UseAttachmentSelectorOptions {
|
|
6
|
+
fileService: IFileService | null;
|
|
7
|
+
fileServiceContext?: Record<string, unknown>;
|
|
8
|
+
location: AttachmentAttribute['location'];
|
|
9
|
+
onChange?: (fileObject: FileObject) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function useAttachmentSelector({ fileService, fileServiceContext, location, onChange, }: UseAttachmentSelectorOptions): {
|
|
12
|
+
isProcessing: boolean;
|
|
13
|
+
selectFile: (accept: string) => void;
|
|
14
|
+
};
|
|
5
15
|
export interface AttachmentImageControlProps extends ControlProps<FileObject> {
|
|
6
16
|
fileService: IFileService;
|
|
7
17
|
fileServiceContext?: Record<string, unknown>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AttachmentControl = void 0;
|
|
4
|
+
exports.useAttachmentSelector = useAttachmentSelector;
|
|
4
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
6
|
const react_components_1 = require("@fluentui/react-components");
|
|
6
7
|
const hooks_1 = require("@headless-adminapp/app/dialog/hooks");
|
|
@@ -16,6 +17,9 @@ function useAttachmentSelector({ fileService, fileServiceContext, location, onCh
|
|
|
16
17
|
return (0, utils_1.fileToObject)(file);
|
|
17
18
|
}
|
|
18
19
|
else {
|
|
20
|
+
if (!fileService) {
|
|
21
|
+
throw new Error('File service is not provided');
|
|
22
|
+
}
|
|
19
23
|
const url = await fileService.uploadFile(file, {
|
|
20
24
|
context: fileServiceContext,
|
|
21
25
|
});
|
|
@@ -123,7 +123,12 @@ const LookupControlMd = ({ value, onChange, id, name, onBlur, onFocus, placehold
|
|
|
123
123
|
}, disableAutoFocus: true, onBlur: onBlur, onFocus: onFocus, id: id, autoFocus: autoFocus, children: [data?.records.map((item) => ((0, jsx_runtime_1.jsx)(react_components_1.Option, { value: item[schema.idAttribute], className: (0, react_components_1.mergeClasses)(styles.option), text: item[schema.primaryAttribute], children: (0, jsx_runtime_1.jsx)(RecordCard_1.RecordCard, { cardView: view?.experience.card, record: item, schema: schema }) }, item[schema.idAttribute]))), !isLoading && !data?.records.length && ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
124
124
|
paddingInline: react_components_1.tokens.spacingHorizontalL,
|
|
125
125
|
paddingBlock: react_components_1.tokens.spacingVerticalS,
|
|
126
|
-
}, children: (0, jsx_runtime_1.jsx)(react_components_1.Body1, { children: loockupStrings.noRecordsFound }) })), allowNewRecord && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_components_1.Divider, {}), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: react_components_1.tokens.spacingVerticalXXS }, children: (0, jsx_runtime_1.jsx)(react_components_1.ToolbarButton, { style: { fontWeight: 'normal' }, icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Add, {}),
|
|
126
|
+
}, children: (0, jsx_runtime_1.jsx)(react_components_1.Body1, { children: loockupStrings.noRecordsFound }) })), allowNewRecord && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_components_1.Divider, {}), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: react_components_1.tokens.spacingVerticalXXS }, children: (0, jsx_runtime_1.jsx)(react_components_1.ToolbarButton, { style: { fontWeight: 'normal' }, icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Add, {}), onClick: () => {
|
|
127
|
+
router.push(routeResolver({
|
|
128
|
+
logicalName: schema.logicalName,
|
|
129
|
+
type: app_2.PageType.EntityForm,
|
|
130
|
+
}));
|
|
131
|
+
}, children: loockupStrings.newRecord }) })] }))] }), !!value && ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
127
132
|
position: 'absolute',
|
|
128
133
|
inset: 0,
|
|
129
134
|
alignItems: 'center',
|
|
@@ -2,4 +2,4 @@ import { ControlProps } from './types';
|
|
|
2
2
|
export interface TelephoneControlProps extends ControlProps<string> {
|
|
3
3
|
autoComplete?: string;
|
|
4
4
|
}
|
|
5
|
-
export declare function TelephoneControl({ value, onChange, id, name, onBlur, onFocus, placeholder, disabled, readOnly, autoComplete, }: TelephoneControlProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function TelephoneControl({ value, onChange, id, name, onBlur, onFocus, placeholder, disabled, readOnly, autoComplete, }: Readonly<TelephoneControlProps>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,14 +3,36 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TelephoneControl = TelephoneControl;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_components_1 = require("@fluentui/react-components");
|
|
6
|
+
const locale_1 = require("@headless-adminapp/app/locale");
|
|
7
|
+
const phone_1 = require("@headless-adminapp/app/utils/phone");
|
|
6
8
|
const icons_1 = require("@headless-adminapp/icons");
|
|
9
|
+
const react_1 = require("react");
|
|
7
10
|
function TelephoneControl({ value, onChange, id, name, onBlur, onFocus, placeholder, disabled, readOnly, autoComplete, }) {
|
|
8
|
-
|
|
11
|
+
const [internalValue, setInternalValue] = (0, react_1.useState)('');
|
|
12
|
+
const { region } = (0, locale_1.useLocale)();
|
|
13
|
+
const number = (0, react_1.useMemo)(() => {
|
|
14
|
+
if (!value) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return (0, phone_1.parsePhoneNumber)(value, region);
|
|
18
|
+
}, [value, region]);
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
setInternalValue(number?.formattedInternationalValue ?? '');
|
|
21
|
+
}, [number]);
|
|
22
|
+
const handleChange = () => {
|
|
23
|
+
const parsedPhoneNumber = (0, phone_1.parsePhoneNumber)(internalValue, region);
|
|
24
|
+
setInternalValue(parsedPhoneNumber.formattedInternationalValue);
|
|
25
|
+
onChange?.(parsedPhoneNumber.rawValue);
|
|
26
|
+
};
|
|
27
|
+
return ((0, jsx_runtime_1.jsx)(react_components_1.Input, { type: "tel", placeholder: placeholder, id: id, appearance: "filled-darker", name: name, value: internalValue, onChange: (e) => setInternalValue?.(e.target.value), onBlur: () => {
|
|
28
|
+
handleChange();
|
|
29
|
+
onBlur?.();
|
|
30
|
+
}, onFocus: () => onFocus?.(),
|
|
9
31
|
// invalid={error}
|
|
10
32
|
readOnly: disabled || readOnly, autoComplete: autoComplete, style: {
|
|
11
33
|
width: '100%',
|
|
12
34
|
paddingRight: react_components_1.tokens.spacingHorizontalXS,
|
|
13
35
|
},
|
|
14
36
|
// size="sm"
|
|
15
|
-
contentAfter: !!
|
|
37
|
+
contentAfter: !!number?.uri ? ((0, jsx_runtime_1.jsx)(react_components_1.Button, { appearance: "transparent", size: "small", onClick: () => window.open(number.uri, '_blank'), title: number.uri, icon: (0, jsx_runtime_1.jsx)(icons_1.Icons.Phone, {}) })) : undefined }));
|
|
16
38
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@headless-adminapp/fluent",
|
|
3
|
-
"version": "0.0.17-alpha.
|
|
3
|
+
"version": "0.0.17-alpha.59",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"uuid": "11.0.3",
|
|
43
43
|
"yup": "^1.4.0"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "813d07729a10a5613b46f012ba4b24bcaab384dc"
|
|
46
46
|
}
|