@byline/admin 6.0.3 → 6.1.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.
Files changed (86) hide show
  1. package/dist/exports-parity.test.node.js +37 -0
  2. package/dist/fields/array/array-field.jsx +209 -0
  3. package/dist/fields/blocks/blocks-field.jsx +248 -0
  4. package/dist/fields/checkbox/checkbox-field.jsx +24 -0
  5. package/dist/fields/code/code-editor.jsx +211 -0
  6. package/dist/fields/code/code-field.jsx +109 -0
  7. package/dist/fields/column-formatter.jsx +25 -0
  8. package/dist/fields/date-time-formatter.jsx +18 -0
  9. package/dist/fields/datetime/datetime-field.jsx +22 -0
  10. package/dist/fields/draggable-context-menu.jsx +50 -0
  11. package/dist/fields/field-admin.test.node.js +40 -0
  12. package/dist/fields/field-renderer.jsx +136 -0
  13. package/dist/fields/field-services-context.jsx +17 -0
  14. package/dist/fields/file/file-field.jsx +176 -0
  15. package/dist/fields/file/file-upload-field.jsx +89 -0
  16. package/dist/fields/group/group-field.jsx +46 -0
  17. package/dist/fields/image/image-field.jsx +183 -0
  18. package/dist/fields/image/image-upload-field.jsx +157 -0
  19. package/dist/fields/local-date-time.jsx +69 -0
  20. package/dist/fields/locale-badge.jsx +19 -0
  21. package/dist/fields/numerical/numerical-field.jsx +93 -0
  22. package/dist/fields/relation/relation-column-formatter.jsx +74 -0
  23. package/dist/fields/relation/relation-display.jsx +118 -0
  24. package/dist/fields/relation/relation-field.jsx +108 -0
  25. package/dist/fields/relation/relation-many-field.jsx +142 -0
  26. package/dist/fields/relation/relation-picker.jsx +240 -0
  27. package/dist/fields/relation/relation-summary.jsx +45 -0
  28. package/dist/fields/select/select-field.jsx +27 -0
  29. package/dist/fields/sortable-item.jsx +54 -0
  30. package/dist/fields/text/text-field.jsx +79 -0
  31. package/dist/fields/text-area/text-area-field.jsx +79 -0
  32. package/dist/forms/available-locales-reconcile.test.node.js +43 -0
  33. package/dist/forms/available-locales-widget.jsx +63 -0
  34. package/dist/forms/document-actions.jsx +486 -0
  35. package/dist/forms/form-context.jsx +598 -0
  36. package/dist/forms/form-modals.jsx +128 -0
  37. package/dist/forms/form-renderer.d.ts +8 -2
  38. package/dist/forms/form-renderer.js +3 -2
  39. package/dist/forms/form-renderer.jsx +532 -0
  40. package/dist/forms/form-status-display.jsx +69 -0
  41. package/dist/forms/navigation-guard.jsx +68 -0
  42. package/dist/forms/nested-path.test.node.js +115 -0
  43. package/dist/forms/path-widget.d.ts +9 -1
  44. package/dist/forms/path-widget.js +8 -5
  45. package/dist/forms/path-widget.jsx +125 -0
  46. package/dist/forms/pending-uploads.test.node.js +19 -0
  47. package/dist/forms/repeating-items.test.node.js +29 -0
  48. package/dist/forms/scheduled-publication-control.jsx +389 -0
  49. package/dist/forms/scheduled-publication-state.test.node.js +121 -0
  50. package/dist/forms/scheduled-publication-time.test.node.js +70 -0
  51. package/dist/forms/status-transitions.test.node.js +76 -0
  52. package/dist/forms/tree-placement-widget.jsx +160 -0
  53. package/dist/forms/upload-executor.test.node.js +368 -0
  54. package/dist/forms/use-form-layout.test.node.js +69 -0
  55. package/dist/modules/admin-account/components/change-password.jsx +169 -0
  56. package/dist/modules/admin-account/components/container.jsx +164 -0
  57. package/dist/modules/admin-account/components/preferences.jsx +148 -0
  58. package/dist/modules/admin-account/components/theme-switch.jsx +52 -0
  59. package/dist/modules/admin-account/components/update.jsx +186 -0
  60. package/dist/modules/admin-permissions/components/inspector.jsx +200 -0
  61. package/dist/modules/admin-preferences/schemas.test.node.js +48 -0
  62. package/dist/modules/admin-roles/components/create.jsx +155 -0
  63. package/dist/modules/admin-roles/components/permissions.jsx +239 -0
  64. package/dist/modules/admin-roles/components/update.jsx +148 -0
  65. package/dist/modules/admin-users/components/create.jsx +206 -0
  66. package/dist/modules/admin-users/components/roles.jsx +126 -0
  67. package/dist/modules/admin-users/components/set-password.jsx +133 -0
  68. package/dist/modules/admin-users/components/update.jsx +215 -0
  69. package/dist/modules/analytics/components/dashboard.jsx +208 -0
  70. package/dist/modules/analytics/components/dashboard.test.node.js +162 -0
  71. package/dist/modules/analytics/components/timeseries.jsx +193 -0
  72. package/dist/modules/auth/components/sign-in-form.jsx +89 -0
  73. package/dist/modules/auth/safe-redirect.test.node.js +40 -0
  74. package/dist/modules/auth/sign-in-form-props.test.node.js +7 -0
  75. package/dist/presentation/group.jsx +26 -0
  76. package/dist/presentation/row.jsx +23 -0
  77. package/dist/presentation/tabs.jsx +39 -0
  78. package/dist/services/admin-services-context.jsx +17 -0
  79. package/dist/widgets/diff-viewer/diff-modal.jsx +110 -0
  80. package/dist/widgets/source-locale-badge/source-locale-badge.jsx +28 -0
  81. package/dist/widgets/status-badge/status-badge.jsx +46 -0
  82. package/package.json +7 -7
  83. package/src/forms/form-renderer-capabilities.test.tsx +72 -2
  84. package/src/forms/form-renderer.tsx +14 -2
  85. package/src/forms/path-widget.test.tsx +96 -2
  86. package/src/forms/path-widget.tsx +31 -11
@@ -0,0 +1,128 @@
1
+ 'use client';
2
+ /**
3
+ * This Source Code is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
+ *
7
+ * Copyright (c) Infonomic Company Limited
8
+ */
9
+ import { useTranslation } from '@byline/i18n/react';
10
+ import { Button, CloseIcon, IconButton, Modal } from '@byline/ui/react';
11
+ import cx from 'clsx';
12
+ import styles from './form-renderer.module.css';
13
+ /**
14
+ * Shown when the editor triggers a guarded action (status change, duplicate,
15
+ * copy-to-locale) while the form is dirty. Those actions operate on the saved
16
+ * version, so the editor must save first.
17
+ */
18
+ export const UnsavedChangesModal = ({ onClose }) => {
19
+ const { t } = useTranslation('byline-admin');
20
+ return (<Modal isOpen={true} closeOnOverlayClick={true} onDismiss={onClose}>
21
+ <Modal.Container style={{ maxWidth: '460px' }}>
22
+ <Modal.Header className={cx('byline-form-guard-modal-head', styles['guard-modal-head'])}>
23
+ <h3 className={cx('byline-form-guard-modal-title', styles['guard-modal-title'])}>
24
+ {t('forms.unsavedChanges.title')}
25
+ </h3>
26
+ </Modal.Header>
27
+ <Modal.Content>
28
+ <p className={cx('byline-form-guard-modal-text', styles['guard-modal-text'])}>
29
+ {t('forms.unsavedChanges.message')}
30
+ </p>
31
+ </Modal.Content>
32
+ <Modal.Actions>
33
+ <Button size="sm" style={{ minWidth: '60px' }} intent="primary" type="button" onClick={onClose}>
34
+ {t('forms.unsavedChanges.okButton')}
35
+ </Button>
36
+ </Modal.Actions>
37
+ </Modal.Container>
38
+ </Modal>);
39
+ };
40
+ /**
41
+ * Confirms an immediate, non-versioned write of the document-grain system
42
+ * fields (path / advertised locales) — which does NOT reset workflow status.
43
+ * When content is also dirty, the copy reassures that content edits still
44
+ * follow the normal revision + publish workflow. See docs/08-internationalization/index.md.
45
+ */
46
+ export const SystemFieldsConfirmModal = ({ contentDirty, pathDirty, availableLocalesDirty, onCancel, onConfirm, }) => {
47
+ const { t } = useTranslation('byline-admin');
48
+ return (<Modal isOpen={true} closeOnOverlayClick={true} onDismiss={onCancel}>
49
+ <Modal.Container style={{ maxWidth: '520px' }}>
50
+ <Modal.Header className={cx('byline-form-guard-modal-head', styles['guard-modal-head'])}>
51
+ <h3 className={cx('byline-form-guard-modal-title', styles['guard-modal-title'])}>
52
+ {contentDirty
53
+ ? t('forms.systemFieldsConfirm.bothTitle')
54
+ : t('forms.systemFieldsConfirm.title')}
55
+ </h3>
56
+ <IconButton aria-label={t('common.actions.close')} size="xs" onClick={onCancel}>
57
+ <CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
58
+ </IconButton>
59
+ </Modal.Header>
60
+ <Modal.Content className="prose">
61
+ {/* Lead with reassurance: content edits follow the normal
62
+ revision + publish workflow. The immediate, document-level
63
+ system-field write is explained below the divider. */}
64
+ {contentDirty && (<p className={cx('byline-form-system-fields-content-note', 'm-0 mt-2')}>
65
+ {t('forms.systemFieldsConfirm.contentNote')}
66
+ </p>)}
67
+ <p className="m-0 mt-2" style={contentDirty
68
+ ? {
69
+ marginTop: 'var(--spacing-8)',
70
+ paddingTop: 'var(--spacing-12)',
71
+ borderTop: '1px solid var(--border-color)',
72
+ }
73
+ : undefined}>
74
+ {t('forms.systemFieldsConfirm.intro')}
75
+ </p>
76
+ <ul className={cx('byline-form-system-fields-list', styles['guard-modal-text'], 'm-0')}>
77
+ {pathDirty && <li>{t('forms.systemFieldsConfirm.bulletPath')}</li>}
78
+ {availableLocalesDirty && <li>{t('forms.systemFieldsConfirm.bulletLocales')}</li>}
79
+ </ul>
80
+ <p className={cx('byline-form-system-fields-effect', styles['guard-modal-text'])} style={{
81
+ marginTop: 'var(--spacing-4)',
82
+ marginBottom: 0,
83
+ color: 'var(--text-subtle)',
84
+ }}>
85
+ {t('forms.systemFieldsConfirm.effectLine')}
86
+ </p>
87
+ </Modal.Content>
88
+ <Modal.Actions>
89
+ <Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" type="button" onClick={onCancel}>
90
+ {t('common.actions.cancel')}
91
+ </Button>
92
+ <Button size="sm" style={{ minWidth: '80px' }} intent="primary" type="button" onClick={onConfirm}>
93
+ {t('forms.systemFieldsConfirm.confirmButton')}
94
+ </Button>
95
+ </Modal.Actions>
96
+ </Modal.Container>
97
+ </Modal>);
98
+ };
99
+ /**
100
+ * Blocks router navigation / browser unload while the form is dirty. Driven by
101
+ * the navigation-guard adapter's `isBlocked` state; `onStay` keeps the editor
102
+ * on the page, `onProceed` discards and continues.
103
+ */
104
+ export const NavigationGuardModal = ({ onStay, onProceed, }) => {
105
+ const { t } = useTranslation('byline-admin');
106
+ return (<Modal isOpen={true} closeOnOverlayClick={false} onDismiss={onStay}>
107
+ <Modal.Container style={{ maxWidth: '460px' }}>
108
+ <Modal.Header className={cx('byline-form-guard-modal-head', styles['guard-modal-head'])}>
109
+ <h3 className={cx('byline-form-guard-modal-title', styles['guard-modal-title'])}>
110
+ {t('forms.navigationGuard.title')}
111
+ </h3>
112
+ </Modal.Header>
113
+ <Modal.Content>
114
+ <p className={cx('byline-form-guard-modal-text', styles['guard-modal-text'])}>
115
+ {t('forms.navigationGuard.message')}
116
+ </p>
117
+ </Modal.Content>
118
+ <Modal.Actions>
119
+ <Button size="sm" intent="noeffect" type="button" onClick={onStay}>
120
+ {t('forms.navigationGuard.stayButton')}
121
+ </Button>
122
+ <Button size="sm" intent="danger" type="button" onClick={onProceed}>
123
+ {t('forms.navigationGuard.leaveButton')}
124
+ </Button>
125
+ </Modal.Actions>
126
+ </Modal.Container>
127
+ </Modal>);
128
+ };
@@ -6,7 +6,7 @@
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
8
  import { type ReactNode } from 'react';
9
- import type { Field, FormAdminConfig, WorkflowStatus } from '@byline/core';
9
+ import type { AdminResourceConfig, Field, WorkflowStatus } from '@byline/core';
10
10
  import type { DocumentPatch } from '@byline/core/patches';
11
11
  import { type DocumentActionsLocaleOption } from './document-actions.js';
12
12
  import { type ScheduledPublicationInfo, type SchedulePublicationInput } from './scheduled-publication-control.js';
@@ -95,7 +95,13 @@ export interface FormRendererProps {
95
95
  workflowStatuses?: WorkflowStatus[];
96
96
  publishedVersion?: PublishedVersionInfo | null;
97
97
  initialData?: Record<string, any>;
98
- adminConfig?: FormAdminConfig;
98
+ /**
99
+ * Presentation configuration for the resource being edited — a collection
100
+ * or a singleton. Typed as the union rather than the shared
101
+ * `FormAdminConfig` base so the renderer can read collection-only members
102
+ * such as `lockPath`.
103
+ */
104
+ adminConfig?: AdminResourceConfig;
99
105
  /**
100
106
  * Name of the schema field to render as the live form heading.
101
107
  * Sourced from `CollectionDefinition.useAsTitle` by the caller.
@@ -533,7 +533,7 @@ const FormContent = ({ mode, mutationIssue, mutationsBlocked = false, observedRe
533
533
  /*#__PURE__*/ jsxs("div", {
534
534
  className: clsx('byline-form-sidebar', form_renderer_module.sidebar),
535
535
  children: [
536
- showPath && (useAsPath || 'string' == typeof initialData?.path && initialData.path.length > 0) && /*#__PURE__*/ jsx(PathWidget, {
536
+ showPath && (useAsPath || adminConfig?.lockPath === true || 'string' == typeof initialData?.path && initialData.path.length > 0) && /*#__PURE__*/ jsx(PathWidget, {
537
537
  disabled: mutationsBlocked || discarding,
538
538
  useAsPath: useAsPath,
539
539
  collectionPath: collectionPath ?? '',
@@ -541,7 +541,8 @@ const FormContent = ({ mode, mutationIssue, mutationsBlocked = false, observedRe
541
541
  activeLocale: contentLocale,
542
542
  mode: mode,
543
543
  slugifier: pathSlugifier,
544
- sourceLocked: pathSourceLocked
544
+ sourceLocked: pathSourceLocked,
545
+ lockPath: adminConfig?.lockPath
545
546
  }),
546
547
  tree && 'edit' === mode && 'string' == typeof initialData?.id && /*#__PURE__*/ jsx(TreePlacementWidget, {
547
548
  disabled: mutationsBlocked || discarding,