@byline/admin 5.1.3 → 5.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/dist/modules/analytics/components/dashboard.d.ts +13 -3
- package/dist/modules/analytics/components/dashboard.js +86 -68
- package/dist/modules/analytics/components/dashboard.module.js +10 -1
- package/dist/modules/analytics/components/dashboard_module.css +57 -0
- package/dist/modules/analytics/components/ranked-list-modal.d.ts +32 -0
- package/dist/modules/analytics/components/ranked-list-modal.js +145 -0
- package/dist/modules/analytics/components/ranking.d.ts +45 -0
- package/dist/modules/analytics/components/ranking.js +71 -0
- package/dist/modules/analytics/components/ranking.test.node.d.ts +8 -0
- package/package.json +14 -14
- package/src/modules/analytics/components/dashboard.module.css +69 -0
- package/src/modules/analytics/components/dashboard.tsx +105 -83
- package/src/modules/analytics/components/ranked-list-modal.test.tsx +154 -0
- package/src/modules/analytics/components/ranked-list-modal.tsx +159 -0
- package/src/modules/analytics/components/ranking.test.node.ts +43 -0
- package/src/modules/analytics/components/ranking.tsx +122 -0
- package/dist/exports-parity.test.node.js +0 -37
- package/dist/fields/array/array-field.jsx +0 -209
- package/dist/fields/blocks/blocks-field.jsx +0 -248
- package/dist/fields/checkbox/checkbox-field.jsx +0 -24
- package/dist/fields/code/code-editor.jsx +0 -211
- package/dist/fields/code/code-field.jsx +0 -109
- package/dist/fields/column-formatter.jsx +0 -25
- package/dist/fields/date-time-formatter.jsx +0 -18
- package/dist/fields/datetime/datetime-field.jsx +0 -22
- package/dist/fields/draggable-context-menu.jsx +0 -50
- package/dist/fields/field-admin.test.node.js +0 -40
- package/dist/fields/field-renderer.jsx +0 -136
- package/dist/fields/field-services-context.jsx +0 -17
- package/dist/fields/file/file-field.jsx +0 -176
- package/dist/fields/file/file-upload-field.jsx +0 -89
- package/dist/fields/group/group-field.jsx +0 -46
- package/dist/fields/image/image-field.jsx +0 -183
- package/dist/fields/image/image-upload-field.jsx +0 -157
- package/dist/fields/local-date-time.jsx +0 -69
- package/dist/fields/locale-badge.jsx +0 -19
- package/dist/fields/numerical/numerical-field.jsx +0 -93
- package/dist/fields/relation/relation-column-formatter.jsx +0 -74
- package/dist/fields/relation/relation-display.jsx +0 -118
- package/dist/fields/relation/relation-field.jsx +0 -108
- package/dist/fields/relation/relation-many-field.jsx +0 -142
- package/dist/fields/relation/relation-picker.jsx +0 -240
- package/dist/fields/relation/relation-summary.jsx +0 -45
- package/dist/fields/select/select-field.jsx +0 -27
- package/dist/fields/sortable-item.jsx +0 -54
- package/dist/fields/text/text-field.jsx +0 -79
- package/dist/fields/text-area/text-area-field.jsx +0 -79
- package/dist/forms/available-locales-reconcile.test.node.js +0 -43
- package/dist/forms/available-locales-widget.jsx +0 -63
- package/dist/forms/document-actions.jsx +0 -486
- package/dist/forms/form-context.jsx +0 -598
- package/dist/forms/form-modals.jsx +0 -128
- package/dist/forms/form-renderer.jsx +0 -532
- package/dist/forms/form-status-display.jsx +0 -69
- package/dist/forms/navigation-guard.jsx +0 -68
- package/dist/forms/nested-path.test.node.js +0 -115
- package/dist/forms/path-widget.jsx +0 -125
- package/dist/forms/pending-uploads.test.node.js +0 -19
- package/dist/forms/repeating-items.test.node.js +0 -29
- package/dist/forms/scheduled-publication-control.jsx +0 -389
- package/dist/forms/scheduled-publication-state.test.node.js +0 -121
- package/dist/forms/scheduled-publication-time.test.node.js +0 -70
- package/dist/forms/status-transitions.test.node.js +0 -76
- package/dist/forms/tree-placement-widget.jsx +0 -160
- package/dist/forms/upload-executor.test.node.js +0 -368
- package/dist/forms/use-form-layout.test.node.js +0 -69
- package/dist/modules/admin-account/components/change-password.jsx +0 -169
- package/dist/modules/admin-account/components/container.jsx +0 -164
- package/dist/modules/admin-account/components/preferences.jsx +0 -148
- package/dist/modules/admin-account/components/theme-switch.jsx +0 -52
- package/dist/modules/admin-account/components/update.jsx +0 -186
- package/dist/modules/admin-permissions/components/inspector.jsx +0 -200
- package/dist/modules/admin-preferences/schemas.test.node.js +0 -48
- package/dist/modules/admin-roles/components/create.jsx +0 -155
- package/dist/modules/admin-roles/components/permissions.jsx +0 -239
- package/dist/modules/admin-roles/components/update.jsx +0 -148
- package/dist/modules/admin-users/components/create.jsx +0 -206
- package/dist/modules/admin-users/components/roles.jsx +0 -126
- package/dist/modules/admin-users/components/set-password.jsx +0 -133
- package/dist/modules/admin-users/components/update.jsx +0 -215
- package/dist/modules/analytics/components/dashboard.jsx +0 -208
- package/dist/modules/analytics/components/dashboard.test.node.js +0 -162
- package/dist/modules/analytics/components/timeseries.jsx +0 -193
- package/dist/modules/auth/components/sign-in-form.jsx +0 -89
- package/dist/modules/auth/safe-redirect.test.node.js +0 -40
- package/dist/modules/auth/sign-in-form-props.test.node.js +0 -7
- package/dist/presentation/group.jsx +0 -26
- package/dist/presentation/row.jsx +0 -23
- package/dist/presentation/tabs.jsx +0 -39
- package/dist/services/admin-services-context.jsx +0 -17
- package/dist/widgets/diff-viewer/diff-modal.jsx +0 -110
- package/dist/widgets/source-locale-badge/source-locale-badge.jsx +0 -28
- package/dist/widgets/status-badge/status-badge.jsx +0 -46
|
@@ -1,486 +0,0 @@
|
|
|
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 { useState } from 'react';
|
|
10
|
-
import { useTranslation } from '@byline/i18n/react';
|
|
11
|
-
import { Button, Checkbox, CloseIcon, DeleteIcon, Dropdown as DropdownComponent, EllipsisIcon, IconButton, Modal, Select, } from '@byline/ui/react';
|
|
12
|
-
import cx from 'clsx';
|
|
13
|
-
import styles from './document-actions.module.css';
|
|
14
|
-
const DUPLICATE_TITLE_SUFFIX = ' (copy)';
|
|
15
|
-
export function DocumentActions({ disabled = false, publishedVersion, onUnpublish, onDelete, onDuplicate, sourceTitle, onCopyToLocale, sourceLocale, contentLocales, hasUnsavedChanges, onUnsavedChanges, onDeleteLocale, defaultLocale, availableLocales, scheduledPublicationState, onSchedulePublication, onConfirmScheduledPublication, onCancelScheduledPublication, }) {
|
|
16
|
-
const { t } = useTranslation('byline-admin');
|
|
17
|
-
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
|
18
|
-
const [showDuplicateConfirm, setShowDuplicateConfirm] = useState(false);
|
|
19
|
-
const [duplicateBusy, setDuplicateBusy] = useState(false);
|
|
20
|
-
// Copy-to-Locale modal state. The menu item is hidden entirely unless
|
|
21
|
-
// the host has supplied a handler AND there is at least one *other*
|
|
22
|
-
// locale to copy into.
|
|
23
|
-
const availableTargetLocales = (contentLocales ?? []).filter((loc) => loc.code !== sourceLocale);
|
|
24
|
-
const copyToLocaleAvailable = onCopyToLocale != null && availableTargetLocales.length > 0;
|
|
25
|
-
const [showCopyToLocaleConfirm, setShowCopyToLocaleConfirm] = useState(false);
|
|
26
|
-
const [copyToLocaleBusy, setCopyToLocaleBusy] = useState(false);
|
|
27
|
-
const [copyTargetLocale, setCopyTargetLocale] = useState(availableTargetLocales[0]?.code ?? '');
|
|
28
|
-
const [copyOverwrite, setCopyOverwrite] = useState(false);
|
|
29
|
-
// Delete-Locale modal state. The menu item is hidden unless the host
|
|
30
|
-
// supplied a handler AND the document has at least one non-default locale
|
|
31
|
-
// with content. The default locale is the document's anchor and is never
|
|
32
|
-
// listed (it cannot be removed).
|
|
33
|
-
const deletableLocales = (availableLocales ?? [])
|
|
34
|
-
.filter((code) => code !== defaultLocale && code !== 'all')
|
|
35
|
-
.map((code) => ({
|
|
36
|
-
code,
|
|
37
|
-
label: contentLocales?.find((loc) => loc.code === code)?.label ?? code,
|
|
38
|
-
}));
|
|
39
|
-
const deleteLocaleAvailable = onDeleteLocale != null && deletableLocales.length > 0;
|
|
40
|
-
const [showDeleteLocaleConfirm, setShowDeleteLocaleConfirm] = useState(false);
|
|
41
|
-
const [deleteLocaleBusy, setDeleteLocaleBusy] = useState(false);
|
|
42
|
-
const [deleteTargetLocale, setDeleteTargetLocale] = useState('');
|
|
43
|
-
// Scheduled-publication menu items. The derived state already accounts for
|
|
44
|
-
// eligibility and for the abilities the actor holds, so the only thing left
|
|
45
|
-
// here is to map the permitted operations onto entries. The group renders
|
|
46
|
-
// above the locale and duplicate items because scheduling acts on the
|
|
47
|
-
// document's lifecycle rather than on its copies.
|
|
48
|
-
const scheduling = scheduledPublicationState;
|
|
49
|
-
const schedulingActions = [];
|
|
50
|
-
if (scheduling != null) {
|
|
51
|
-
if (scheduling.actions.schedule && onSchedulePublication != null) {
|
|
52
|
-
schedulingActions.push({
|
|
53
|
-
key: 'schedule',
|
|
54
|
-
// Short form: the menu supplies the "this document" context that the
|
|
55
|
-
// modal's title and submit button have to spell out for themselves.
|
|
56
|
-
label: t('scheduledPublication.actions.scheduleMenuItem'),
|
|
57
|
-
onSelect: onSchedulePublication,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
if (scheduling.actions.confirm && onConfirmScheduledPublication != null) {
|
|
61
|
-
schedulingActions.push({
|
|
62
|
-
key: 'confirm',
|
|
63
|
-
label: t('scheduledPublication.actions.confirm'),
|
|
64
|
-
onSelect: () => void onConfirmScheduledPublication(),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
if (scheduling.actions.reschedule && onSchedulePublication != null) {
|
|
68
|
-
schedulingActions.push({
|
|
69
|
-
key: 'reschedule',
|
|
70
|
-
label: t('scheduledPublication.actions.reschedule'),
|
|
71
|
-
onSelect: onSchedulePublication,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
if (scheduling.actions.cancel && onCancelScheduledPublication != null) {
|
|
75
|
-
schedulingActions.push({
|
|
76
|
-
key: 'cancel',
|
|
77
|
-
label: t('scheduledPublication.actions.cancel'),
|
|
78
|
-
onSelect: () => void onCancelScheduledPublication(),
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// Whether the ellipsis menu has anything to show. Every entry below is
|
|
83
|
-
// conditional, so with no available action the trigger would open an empty
|
|
84
|
-
// menu.
|
|
85
|
-
const hasAnyAction = schedulingActions.length > 0 ||
|
|
86
|
-
copyToLocaleAvailable ||
|
|
87
|
-
deleteLocaleAvailable ||
|
|
88
|
-
onDuplicate != null ||
|
|
89
|
-
onDelete != null;
|
|
90
|
-
const handleOnDelete = () => {
|
|
91
|
-
if (disabled)
|
|
92
|
-
return;
|
|
93
|
-
setShowDeleteConfirm(false);
|
|
94
|
-
if (onDelete) {
|
|
95
|
-
void onDelete().catch(() => { });
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
const handleOnDuplicate = async () => {
|
|
99
|
-
if (disabled)
|
|
100
|
-
return;
|
|
101
|
-
if (!onDuplicate)
|
|
102
|
-
return;
|
|
103
|
-
setDuplicateBusy(true);
|
|
104
|
-
try {
|
|
105
|
-
await onDuplicate();
|
|
106
|
-
setShowDuplicateConfirm(false);
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// The host reports the failure and retains the editor observation.
|
|
110
|
-
}
|
|
111
|
-
finally {
|
|
112
|
-
setDuplicateBusy(false);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
const handleOpenDuplicate = () => {
|
|
116
|
-
if (disabled)
|
|
117
|
-
return;
|
|
118
|
-
// Duplicate copies the saved version — block when the form is dirty so
|
|
119
|
-
// unsaved edits are not silently dropped from the copy.
|
|
120
|
-
if (hasUnsavedChanges) {
|
|
121
|
-
onUnsavedChanges?.();
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
setShowDuplicateConfirm(true);
|
|
125
|
-
};
|
|
126
|
-
const handleOpenCopyToLocale = () => {
|
|
127
|
-
if (disabled)
|
|
128
|
-
return;
|
|
129
|
-
// Copy-to-Locale reads the saved version — block when the form is dirty.
|
|
130
|
-
if (hasUnsavedChanges) {
|
|
131
|
-
onUnsavedChanges?.();
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
// Reset on open: pick the first available target and clear the
|
|
135
|
-
// overwrite checkbox so a previous-session "overwrite=true" choice
|
|
136
|
-
// is not silently sticky.
|
|
137
|
-
setCopyTargetLocale(availableTargetLocales[0]?.code ?? '');
|
|
138
|
-
setCopyOverwrite(false);
|
|
139
|
-
setShowCopyToLocaleConfirm(true);
|
|
140
|
-
};
|
|
141
|
-
const handleOnCopyToLocale = async () => {
|
|
142
|
-
if (disabled)
|
|
143
|
-
return;
|
|
144
|
-
if (!onCopyToLocale || !copyTargetLocale)
|
|
145
|
-
return;
|
|
146
|
-
setCopyToLocaleBusy(true);
|
|
147
|
-
try {
|
|
148
|
-
await onCopyToLocale({ targetLocale: copyTargetLocale, overwrite: copyOverwrite });
|
|
149
|
-
setShowCopyToLocaleConfirm(false);
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// The host reports the failure and retains the editor observation.
|
|
153
|
-
}
|
|
154
|
-
finally {
|
|
155
|
-
setCopyToLocaleBusy(false);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
const handleOpenDeleteLocale = () => {
|
|
159
|
-
if (disabled)
|
|
160
|
-
return;
|
|
161
|
-
// Delete-Locale removes the saved version's locale content — block when
|
|
162
|
-
// the form is dirty so the editor saves (or discards) first.
|
|
163
|
-
if (hasUnsavedChanges) {
|
|
164
|
-
onUnsavedChanges?.();
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
// Default to the currently-viewed locale when it is deletable, otherwise
|
|
168
|
-
// the first available target.
|
|
169
|
-
const preferred = deletableLocales.find((loc) => loc.code === sourceLocale)?.code;
|
|
170
|
-
setDeleteTargetLocale(preferred ?? deletableLocales[0]?.code ?? '');
|
|
171
|
-
setShowDeleteLocaleConfirm(true);
|
|
172
|
-
};
|
|
173
|
-
const handleOnDeleteLocale = async () => {
|
|
174
|
-
if (disabled)
|
|
175
|
-
return;
|
|
176
|
-
if (!onDeleteLocale || !deleteTargetLocale)
|
|
177
|
-
return;
|
|
178
|
-
setDeleteLocaleBusy(true);
|
|
179
|
-
try {
|
|
180
|
-
await onDeleteLocale({ targetLocale: deleteTargetLocale });
|
|
181
|
-
setShowDeleteLocaleConfirm(false);
|
|
182
|
-
}
|
|
183
|
-
catch {
|
|
184
|
-
// The host reports the failure and retains the editor observation.
|
|
185
|
-
}
|
|
186
|
-
finally {
|
|
187
|
-
setDeleteLocaleBusy(false);
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
// Preview text shown inside the modal. Falls back to the literal suffix
|
|
191
|
-
// when no source title is supplied (collections without `useAsTitle`).
|
|
192
|
-
const duplicatePreviewBefore = sourceTitle ?? '';
|
|
193
|
-
const duplicatePreviewAfter = (sourceTitle ?? '') + DUPLICATE_TITLE_SUFFIX;
|
|
194
|
-
const sourceLocaleLabel = contentLocales?.find((loc) => loc.code === sourceLocale)?.label ?? sourceLocale ?? '';
|
|
195
|
-
return (<>
|
|
196
|
-
{hasAnyAction && (<DropdownComponent.Root>
|
|
197
|
-
<DropdownComponent.Trigger disabled={disabled} render={<IconButton variant="text" intent="noeffect" size="sm"/>}>
|
|
198
|
-
<EllipsisIcon className={cx('byline-form-actions-icon', styles.icon)} width="15px" height="15px"/>
|
|
199
|
-
</DropdownComponent.Trigger>
|
|
200
|
-
|
|
201
|
-
<DropdownComponent.Portal>
|
|
202
|
-
<DropdownComponent.Content className={cx('byline-form-actions-menu', styles.menu)} align="end" data-side="top" sideOffset={10}>
|
|
203
|
-
{/*{publishedVersion && (
|
|
204
|
-
<>
|
|
205
|
-
<DropdownComponent.Item disabled={disabled} onClick={onUnpublish}>
|
|
206
|
-
<div className={cx('byline-form-actions-item', styles.item)}>
|
|
207
|
-
<span className={cx('byline-form-actions-item-icon', styles['item-icon'])} />
|
|
208
|
-
<span className={cx('byline-form-actions-item-text', styles['item-text'])}>
|
|
209
|
-
Unpublish
|
|
210
|
-
</span>
|
|
211
|
-
</div>
|
|
212
|
-
</DropdownComponent.Item>
|
|
213
|
-
<DropdownComponent.Separator />
|
|
214
|
-
</>
|
|
215
|
-
)}*/}
|
|
216
|
-
{schedulingActions.length > 0 && (<>
|
|
217
|
-
{schedulingActions.map((action) => (<DropdownComponent.Item disabled={disabled} key={action.key} onClick={action.onSelect}>
|
|
218
|
-
<div className={cx('byline-form-actions-item', styles.item)}>
|
|
219
|
-
<span className={cx('byline-form-actions-item-text', styles['item-text'])}>
|
|
220
|
-
<button type="button" disabled={disabled}>
|
|
221
|
-
{action.label}
|
|
222
|
-
</button>
|
|
223
|
-
</span>
|
|
224
|
-
</div>
|
|
225
|
-
</DropdownComponent.Item>))}
|
|
226
|
-
<DropdownComponent.Separator />
|
|
227
|
-
</>)}
|
|
228
|
-
{copyToLocaleAvailable && (<DropdownComponent.Item disabled={disabled} onClick={handleOpenCopyToLocale}>
|
|
229
|
-
<div className={cx('byline-form-actions-item', styles.item)}>
|
|
230
|
-
<span className={cx('byline-form-actions-item-text', styles['item-text'])}>
|
|
231
|
-
<button type="button" disabled={disabled}>
|
|
232
|
-
{t('documentActions.copyToLocaleMenuItem')}
|
|
233
|
-
</button>
|
|
234
|
-
</span>
|
|
235
|
-
</div>
|
|
236
|
-
</DropdownComponent.Item>)}
|
|
237
|
-
{deleteLocaleAvailable && (<DropdownComponent.Item disabled={disabled} onClick={handleOpenDeleteLocale}>
|
|
238
|
-
<div className={cx('byline-form-actions-item', styles.item)}>
|
|
239
|
-
<span className={cx('byline-form-actions-item-text', styles['item-text'])}>
|
|
240
|
-
<button type="button" disabled={disabled}>
|
|
241
|
-
{t('documentActions.deleteLocale.menuItem')}
|
|
242
|
-
</button>
|
|
243
|
-
</span>
|
|
244
|
-
</div>
|
|
245
|
-
</DropdownComponent.Item>)}
|
|
246
|
-
{onDuplicate && (<DropdownComponent.Item disabled={disabled} onClick={handleOpenDuplicate}>
|
|
247
|
-
<div className={cx('byline-form-actions-item', styles.item)}>
|
|
248
|
-
<span className={cx('byline-form-actions-item-text', styles['item-text'])}>
|
|
249
|
-
<button type="button" disabled={disabled}>
|
|
250
|
-
{t('common.actions.duplicate')}
|
|
251
|
-
</button>
|
|
252
|
-
</span>
|
|
253
|
-
</div>
|
|
254
|
-
</DropdownComponent.Item>)}
|
|
255
|
-
{onDelete && (<>
|
|
256
|
-
<DropdownComponent.Separator />
|
|
257
|
-
<DropdownComponent.Item disabled={disabled} onClick={() => {
|
|
258
|
-
setShowDeleteConfirm(true);
|
|
259
|
-
}}>
|
|
260
|
-
<div className={cx('byline-form-actions-item', styles.item)}>
|
|
261
|
-
<span className={cx('byline-form-actions-item-icon', styles['item-icon'])}>
|
|
262
|
-
<DeleteIcon width="16px" height="16px"/>
|
|
263
|
-
</span>
|
|
264
|
-
<span className={cx('byline-form-actions-item-text', styles['item-text'])}>
|
|
265
|
-
<button type="button" className={cx('byline-form-actions-delete', styles.delete)}>
|
|
266
|
-
{t('common.actions.delete')}
|
|
267
|
-
</button>
|
|
268
|
-
</span>
|
|
269
|
-
</div>
|
|
270
|
-
</DropdownComponent.Item>
|
|
271
|
-
</>)}
|
|
272
|
-
</DropdownComponent.Content>
|
|
273
|
-
</DropdownComponent.Portal>
|
|
274
|
-
</DropdownComponent.Root>)}
|
|
275
|
-
|
|
276
|
-
<Modal isOpen={showDeleteConfirm} closeOnOverlayClick={true} onDismiss={() => {
|
|
277
|
-
setShowDeleteConfirm(false);
|
|
278
|
-
}}>
|
|
279
|
-
<Modal.Container style={{ maxWidth: '500px' }}>
|
|
280
|
-
<Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
|
|
281
|
-
<h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
|
|
282
|
-
{t('documentActions.delete.title')}
|
|
283
|
-
</h3>
|
|
284
|
-
<IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
|
|
285
|
-
setShowDeleteConfirm(false);
|
|
286
|
-
}}>
|
|
287
|
-
<CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
|
|
288
|
-
</IconButton>
|
|
289
|
-
</Modal.Header>
|
|
290
|
-
<Modal.Content>
|
|
291
|
-
<p>{t('documentActions.delete.warning')}</p>
|
|
292
|
-
</Modal.Content>
|
|
293
|
-
<Modal.Actions>
|
|
294
|
-
<button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
|
|
295
|
-
no action
|
|
296
|
-
</button>
|
|
297
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
|
|
298
|
-
setShowDeleteConfirm(false);
|
|
299
|
-
}}>
|
|
300
|
-
{t('common.actions.cancel')}
|
|
301
|
-
</Button>
|
|
302
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="danger" disabled={disabled} onClick={handleOnDelete}>
|
|
303
|
-
{t('common.actions.delete')}
|
|
304
|
-
</Button>
|
|
305
|
-
</Modal.Actions>
|
|
306
|
-
</Modal.Container>
|
|
307
|
-
</Modal>
|
|
308
|
-
|
|
309
|
-
<Modal isOpen={showDuplicateConfirm} closeOnOverlayClick={!duplicateBusy} onDismiss={() => {
|
|
310
|
-
if (!duplicateBusy)
|
|
311
|
-
setShowDuplicateConfirm(false);
|
|
312
|
-
}}>
|
|
313
|
-
<Modal.Container style={{ maxWidth: '560px' }}>
|
|
314
|
-
<Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
|
|
315
|
-
<h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
|
|
316
|
-
{t('documentActions.duplicate.title')}
|
|
317
|
-
</h3>
|
|
318
|
-
<IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
|
|
319
|
-
if (!duplicateBusy)
|
|
320
|
-
setShowDuplicateConfirm(false);
|
|
321
|
-
}}>
|
|
322
|
-
<CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
|
|
323
|
-
</IconButton>
|
|
324
|
-
</Modal.Header>
|
|
325
|
-
<Modal.Content className="prose">
|
|
326
|
-
<p className="m-0">{t('documentActions.duplicate.intro')}</p>
|
|
327
|
-
<ul className={cx('byline-form-actions-list', styles.list)}>
|
|
328
|
-
<li>
|
|
329
|
-
{t('documentActions.duplicate.bulletTitle')}{' '}
|
|
330
|
-
<code>{DUPLICATE_TITLE_SUFFIX.trim()}</code>.
|
|
331
|
-
</li>
|
|
332
|
-
<li>{t('documentActions.duplicate.bulletPath')}</li>
|
|
333
|
-
</ul>
|
|
334
|
-
{sourceTitle != null && sourceTitle.length > 0 && (<div className={cx('byline-form-actions-preview', styles.preview)}>
|
|
335
|
-
<div className={cx('byline-form-actions-preview-label', styles['preview-label'])}>
|
|
336
|
-
{t('documentActions.duplicate.previewLabel')}
|
|
337
|
-
</div>
|
|
338
|
-
<div className={cx('byline-form-actions-preview-row', styles['preview-row'])}>
|
|
339
|
-
<span className={cx('byline-form-actions-preview-before', styles['preview-before'])}>
|
|
340
|
-
{duplicatePreviewBefore}
|
|
341
|
-
</span>
|
|
342
|
-
<span className={cx('byline-form-actions-preview-arrow', styles['preview-arrow'])}>
|
|
343
|
-
→
|
|
344
|
-
</span>
|
|
345
|
-
<span className={cx('byline-form-actions-preview-after', styles['preview-after'])}>
|
|
346
|
-
{duplicatePreviewAfter}
|
|
347
|
-
</span>
|
|
348
|
-
</div>
|
|
349
|
-
</div>)}
|
|
350
|
-
</Modal.Content>
|
|
351
|
-
<Modal.Actions>
|
|
352
|
-
<button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
|
|
353
|
-
no action
|
|
354
|
-
</button>
|
|
355
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
|
|
356
|
-
if (!duplicateBusy)
|
|
357
|
-
setShowDuplicateConfirm(false);
|
|
358
|
-
}} disabled={disabled || duplicateBusy}>
|
|
359
|
-
{t('common.actions.cancel')}
|
|
360
|
-
</Button>
|
|
361
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="primary" onClick={handleOnDuplicate} disabled={disabled || duplicateBusy}>
|
|
362
|
-
{duplicateBusy
|
|
363
|
-
? t('documentActions.duplicate.busyButton')
|
|
364
|
-
: t('common.actions.duplicate')}
|
|
365
|
-
</Button>
|
|
366
|
-
</Modal.Actions>
|
|
367
|
-
</Modal.Container>
|
|
368
|
-
</Modal>
|
|
369
|
-
|
|
370
|
-
<Modal isOpen={showCopyToLocaleConfirm} closeOnOverlayClick={!copyToLocaleBusy} onDismiss={() => {
|
|
371
|
-
if (!copyToLocaleBusy)
|
|
372
|
-
setShowCopyToLocaleConfirm(false);
|
|
373
|
-
}}>
|
|
374
|
-
<Modal.Container style={{ maxWidth: '560px' }}>
|
|
375
|
-
<Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
|
|
376
|
-
<h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
|
|
377
|
-
{t('documentActions.copyToLocale.title')}
|
|
378
|
-
</h3>
|
|
379
|
-
<IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
|
|
380
|
-
if (!copyToLocaleBusy)
|
|
381
|
-
setShowCopyToLocaleConfirm(false);
|
|
382
|
-
}}>
|
|
383
|
-
<CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
|
|
384
|
-
</IconButton>
|
|
385
|
-
</Modal.Header>
|
|
386
|
-
<Modal.Content>
|
|
387
|
-
<p>{t('documentActions.copyToLocale.intro')}</p>
|
|
388
|
-
<div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-12)' }}>
|
|
389
|
-
<span className={cx('byline-form-actions-copy-label', styles['copy-label'])} style={{ fontWeight: 500 }}>
|
|
390
|
-
{t('documentActions.copyToLocale.fromLabel')}
|
|
391
|
-
</span>
|
|
392
|
-
<span className={cx('byline-form-actions-copy-source', styles['copy-source'])}>
|
|
393
|
-
{sourceLocaleLabel}
|
|
394
|
-
</span>
|
|
395
|
-
</div>
|
|
396
|
-
<div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-12)' }}>
|
|
397
|
-
<span className={cx('byline-form-actions-copy-label', styles['copy-label'])} style={{ fontWeight: 500, marginRight: 'var(--spacing-8)' }}>
|
|
398
|
-
{t('documentActions.copyToLocale.toLabel')}
|
|
399
|
-
</span>
|
|
400
|
-
<Select size="sm" ariaLabel={t('documentActions.copyToLocale.targetAriaLabel')} value={copyTargetLocale} items={availableTargetLocales.map((loc) => ({
|
|
401
|
-
value: loc.code,
|
|
402
|
-
label: loc.label,
|
|
403
|
-
}))} onValueChange={(value) => {
|
|
404
|
-
if (value != null)
|
|
405
|
-
setCopyTargetLocale(value);
|
|
406
|
-
}} disabled={disabled || copyToLocaleBusy}/>
|
|
407
|
-
</div>
|
|
408
|
-
<div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-16)' }}>
|
|
409
|
-
<Checkbox id="copy-to-locale-overwrite" name="overwrite" label={t('documentActions.copyToLocale.overwriteLabel')} checked={copyOverwrite} disabled={disabled || copyToLocaleBusy} helpText={t('documentActions.copyToLocale.overwriteHelp')} onCheckedChange={(value) => {
|
|
410
|
-
setCopyOverwrite(value === true);
|
|
411
|
-
}}/>
|
|
412
|
-
</div>
|
|
413
|
-
</Modal.Content>
|
|
414
|
-
<Modal.Actions>
|
|
415
|
-
<button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
|
|
416
|
-
no action
|
|
417
|
-
</button>
|
|
418
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
|
|
419
|
-
if (!copyToLocaleBusy)
|
|
420
|
-
setShowCopyToLocaleConfirm(false);
|
|
421
|
-
}} disabled={disabled || copyToLocaleBusy}>
|
|
422
|
-
{t('common.actions.cancel')}
|
|
423
|
-
</Button>
|
|
424
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="primary" onClick={handleOnCopyToLocale} disabled={disabled || copyToLocaleBusy || !copyTargetLocale}>
|
|
425
|
-
{copyToLocaleBusy
|
|
426
|
-
? t('documentActions.copyToLocale.busyButton')
|
|
427
|
-
: t('documentActions.copyToLocale.confirmButton')}
|
|
428
|
-
</Button>
|
|
429
|
-
</Modal.Actions>
|
|
430
|
-
</Modal.Container>
|
|
431
|
-
</Modal>
|
|
432
|
-
|
|
433
|
-
<Modal isOpen={showDeleteLocaleConfirm} closeOnOverlayClick={!deleteLocaleBusy} onDismiss={() => {
|
|
434
|
-
if (!deleteLocaleBusy)
|
|
435
|
-
setShowDeleteLocaleConfirm(false);
|
|
436
|
-
}}>
|
|
437
|
-
<Modal.Container style={{ maxWidth: '560px' }}>
|
|
438
|
-
<Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
|
|
439
|
-
<h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
|
|
440
|
-
{t('documentActions.deleteLocale.title')}
|
|
441
|
-
</h3>
|
|
442
|
-
<IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
|
|
443
|
-
if (!deleteLocaleBusy)
|
|
444
|
-
setShowDeleteLocaleConfirm(false);
|
|
445
|
-
}}>
|
|
446
|
-
<CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
|
|
447
|
-
</IconButton>
|
|
448
|
-
</Modal.Header>
|
|
449
|
-
<Modal.Content>
|
|
450
|
-
<p>{t('documentActions.deleteLocale.intro')}</p>
|
|
451
|
-
<div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-12)' }}>
|
|
452
|
-
<span className={cx('byline-form-actions-copy-label', styles['copy-label'])} style={{ fontWeight: 500, marginRight: 'var(--spacing-8)' }}>
|
|
453
|
-
{t('documentActions.deleteLocale.localeLabel')}
|
|
454
|
-
</span>
|
|
455
|
-
<Select size="sm" ariaLabel={t('documentActions.deleteLocale.targetAriaLabel')} value={deleteTargetLocale} items={deletableLocales.map((loc) => ({
|
|
456
|
-
value: loc.code,
|
|
457
|
-
label: loc.label,
|
|
458
|
-
}))} onValueChange={(value) => {
|
|
459
|
-
if (value != null)
|
|
460
|
-
setDeleteTargetLocale(value);
|
|
461
|
-
}} disabled={disabled || deleteLocaleBusy}/>
|
|
462
|
-
</div>
|
|
463
|
-
<p style={{ marginTop: 'var(--spacing-12)' }}>
|
|
464
|
-
{t('documentActions.deleteLocale.warning')}
|
|
465
|
-
</p>
|
|
466
|
-
</Modal.Content>
|
|
467
|
-
<Modal.Actions>
|
|
468
|
-
<button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
|
|
469
|
-
no action
|
|
470
|
-
</button>
|
|
471
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
|
|
472
|
-
if (!deleteLocaleBusy)
|
|
473
|
-
setShowDeleteLocaleConfirm(false);
|
|
474
|
-
}} disabled={disabled || deleteLocaleBusy}>
|
|
475
|
-
{t('common.actions.cancel')}
|
|
476
|
-
</Button>
|
|
477
|
-
<Button size="sm" style={{ minWidth: '80px' }} intent="danger" onClick={handleOnDeleteLocale} disabled={disabled || deleteLocaleBusy || !deleteTargetLocale}>
|
|
478
|
-
{deleteLocaleBusy
|
|
479
|
-
? t('documentActions.deleteLocale.busyButton')
|
|
480
|
-
: t('documentActions.deleteLocale.confirmButton')}
|
|
481
|
-
</Button>
|
|
482
|
-
</Modal.Actions>
|
|
483
|
-
</Modal.Container>
|
|
484
|
-
</Modal>
|
|
485
|
-
</>);
|
|
486
|
-
}
|