@griddo/ax 11.10.41 → 11.10.42
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/config/griddo-config/index.js +1 -0
- package/package.json +2 -2
- package/src/components/BulkSelectionOptions/index.tsx +78 -28
- package/src/components/BulkSelectionOptions/style.tsx +7 -1
- package/src/components/BulkSelectionOptions/utils.tsx +25 -0
- package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +2 -2
- package/src/components/ConfigPanel/GlobalPageForm/index.tsx +14 -4
- package/src/components/ConfigPanel/index.tsx +6 -0
- package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +9 -9
- package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +5 -6
- package/src/components/Fields/ReferenceField/ItemList/Item/style.tsx +16 -10
- package/src/components/Fields/ReferenceField/ManualPanel/Item/index.tsx +3 -4
- package/src/components/Fields/ReferenceField/ManualPanel/Item/style.tsx +7 -1
- package/src/components/Fields/VisualUniqueSelection/ScrollableSelection/index.tsx +3 -3
- package/src/components/Fields/VisualUniqueSelection/index.tsx +2 -4
- package/src/components/FloatingMenu/index.tsx +5 -5
- package/src/components/Loader/components/SmallCircle.js +29 -0
- package/src/components/Loader/index.tsx +3 -2
- package/src/components/MainWrapper/AppBar/atoms.tsx +4 -6
- package/src/components/MainWrapper/AppBar/index.tsx +14 -12
- package/src/components/MainWrapper/AppBar/style.tsx +23 -18
- package/src/components/MainWrapper/index.tsx +3 -3
- package/src/components/OcassionalToast/index.tsx +1 -1
- package/src/components/OcassionalToast/style.tsx +6 -0
- package/src/components/PageFinder/SelectionListItem/index.tsx +5 -4
- package/src/components/PageFinder/SelectionListItem/style.tsx +7 -1
- package/src/components/PageFinder/index.tsx +1 -0
- package/src/constants/index.ts +27 -0
- package/src/forms/elements.tsx +8 -24
- package/src/forms/index.tsx +0 -2
- package/src/helpers/containerEvaluations.tsx +5 -0
- package/src/helpers/content.ts +35 -0
- package/src/helpers/index.tsx +91 -89
- package/src/helpers/strings.tsx +19 -0
- package/src/helpers/types.ts +1 -0
- package/src/hooks/forms.tsx +2 -1
- package/src/locales/en-US.ts +29 -0
- package/src/locales/es-ES.ts +29 -0
- package/src/locales/index.ts +11 -0
- package/src/modules/Categories/CategoriesList/BulkHeader/index.tsx +5 -0
- package/src/modules/Categories/CategoriesList/index.tsx +10 -4
- package/src/modules/Content/BulkHeader/index.tsx +11 -0
- package/src/modules/Content/PageItem/index.tsx +1 -0
- package/src/modules/Content/atoms.tsx +1 -1
- package/src/modules/Content/index.tsx +27 -2
- package/src/modules/FileDrive/BulkGridHeader/index.tsx +6 -1
- package/src/modules/FileDrive/BulkListHeader/index.tsx +5 -0
- package/src/modules/FileDrive/index.tsx +10 -0
- package/src/modules/Forms/FormCategoriesList/BulkHeader/index.tsx +15 -2
- package/src/modules/Forms/FormCategoriesList/index.tsx +8 -0
- package/src/modules/Forms/FormEditor/index.tsx +10 -1
- package/src/modules/Forms/FormList/BulkHeader/index.tsx +5 -0
- package/src/modules/Forms/FormList/index.tsx +12 -3
- package/src/modules/Forms/FormUseModal/FormUseItem/index.tsx +1 -2
- package/src/modules/Forms/FormUseModal/index.tsx +3 -3
- package/src/modules/GlobalEditor/index.tsx +1 -0
- package/src/modules/MediaGallery/BulkGridHeader/index.tsx +6 -1
- package/src/modules/MediaGallery/BulkListHeader/index.tsx +15 -2
- package/src/modules/MediaGallery/index.tsx +47 -36
- package/src/modules/Navigation/Defaults/BulkHeader/index.tsx +5 -0
- package/src/modules/Navigation/Defaults/index.tsx +26 -23
- package/src/modules/PageEditor/Editor/index.tsx +6 -0
- package/src/modules/PageEditor/index.tsx +52 -0
- package/src/modules/Redirects/BulkHeader/index.tsx +6 -1
- package/src/modules/Redirects/index.tsx +7 -2
- package/src/modules/Settings/Integrations/BulkHeader/index.tsx +5 -0
- package/src/modules/Settings/Integrations/index.tsx +7 -1
- package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +5 -0
- package/src/modules/Sites/SitesList/index.tsx +7 -2
- package/src/modules/StructuredData/Form/index.tsx +1 -0
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +5 -0
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/atoms.tsx +3 -2
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +17 -11
- package/src/modules/StructuredData/StructuredDataList/index.tsx +6 -0
- package/src/modules/Users/Roles/BulkHeader/index.tsx +5 -0
- package/src/modules/Users/Roles/index.tsx +6 -1
- package/src/modules/Users/UserList/BulkHeader/index.tsx +5 -0
- package/src/modules/Users/UserList/index.tsx +12 -7
- package/tsconfig.paths.json +4 -1
|
@@ -89,6 +89,7 @@ const griddoAxAliases = {
|
|
|
89
89
|
"@ax/schemas": path.resolve(__dirname, "../../src/schemas"),
|
|
90
90
|
"@ax/services": path.resolve(__dirname, "../../src/services"),
|
|
91
91
|
"@ax/locales": path.resolve(__dirname, "../../src/locales"),
|
|
92
|
+
"@ax/constants": path.resolve(__dirname, "../../src/constants"),
|
|
92
93
|
};
|
|
93
94
|
|
|
94
95
|
const griddoComponentsLibAliases = getComponentsLibAliases();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griddo/ax",
|
|
3
3
|
"description": "Griddo Author Experience",
|
|
4
|
-
"version": "11.10.
|
|
4
|
+
"version": "11.10.42",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
|
|
7
7
|
"Diego M. Béjar <diego.bejar@secuoyas.com>",
|
|
@@ -217,5 +217,5 @@
|
|
|
217
217
|
"publishConfig": {
|
|
218
218
|
"access": "public"
|
|
219
219
|
},
|
|
220
|
-
"gitHead": "
|
|
220
|
+
"gitHead": "9ae94989b7a0c987e39ebcaaa7f5398aae266c88"
|
|
221
221
|
}
|
|
@@ -1,42 +1,90 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { Button, CheckField, ExportButton, Loader } from "@ax/components";
|
|
4
|
+
import type { ItemLabel } from "@ax/constants";
|
|
2
5
|
import type { IBulkSelectedItems } from "@ax/hooks";
|
|
6
|
+
import { LOCALE, pluralize } from "@ax/locales";
|
|
3
7
|
import type { IBulkAction } from "@ax/types";
|
|
4
8
|
|
|
9
|
+
import { getBulkLoadingText } from "./utils";
|
|
10
|
+
|
|
5
11
|
import * as S from "./style";
|
|
6
12
|
|
|
7
13
|
const BulkSelectionOptions = (props: IBulkSelectionProps) => {
|
|
8
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
isScrolling,
|
|
16
|
+
checkState,
|
|
17
|
+
actions,
|
|
18
|
+
selectItems,
|
|
19
|
+
className,
|
|
20
|
+
exportAction,
|
|
21
|
+
selectedItems,
|
|
22
|
+
isLoading,
|
|
23
|
+
itemLabel = { one: "item", other: "items" },
|
|
24
|
+
} = props;
|
|
9
25
|
|
|
10
26
|
const filteredActions = actions.filter((action) => !!action);
|
|
27
|
+
const [currentAction, setCurrentAction] = useState<string>("");
|
|
28
|
+
|
|
29
|
+
const currentActionText = getBulkLoadingText(currentAction);
|
|
30
|
+
const allSelectedItemsText = selectedItems?.all.length.toString();
|
|
31
|
+
const itemLabelText = pluralize(itemLabel, selectedItems?.all.length);
|
|
32
|
+
const pleaseWaitText = `${LOCALE.common.pleaseWait}...`;
|
|
33
|
+
const bulkProcessingText = `${currentActionText} ${allSelectedItemsText} ${itemLabelText}. ${pleaseWaitText}`;
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!isLoading) {
|
|
37
|
+
setCurrentAction("");
|
|
38
|
+
}
|
|
39
|
+
}, [isLoading]);
|
|
40
|
+
|
|
41
|
+
const handleActionClick = (action: () => void, actionText: string) => {
|
|
42
|
+
setCurrentAction(actionText);
|
|
43
|
+
action();
|
|
44
|
+
};
|
|
11
45
|
|
|
12
46
|
return (
|
|
13
47
|
<S.BulkHeader isScrolling={isScrolling} data-testid="bulk-header-wrapper" className={className}>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
{isLoading ? (
|
|
49
|
+
<>
|
|
50
|
+
<Loader name="smallCircle" size="16" />
|
|
51
|
+
<S.LoadingText>{bulkProcessingText}</S.LoadingText>
|
|
52
|
+
</>
|
|
53
|
+
) : (
|
|
54
|
+
<S.BulkActionsWrapper>
|
|
55
|
+
<S.SelectAllCheckField>
|
|
56
|
+
<CheckField
|
|
57
|
+
key="selectAll"
|
|
58
|
+
name="selectAll"
|
|
59
|
+
value="selectAll"
|
|
60
|
+
onChange={selectItems}
|
|
61
|
+
checked={checkState.isAllSelected}
|
|
62
|
+
indeterminate={checkState.indeterminate}
|
|
63
|
+
disabled={isLoading || false}
|
|
64
|
+
error={false}
|
|
65
|
+
/>
|
|
66
|
+
</S.SelectAllCheckField>
|
|
67
|
+
<S.SelectedCount>{selectedItems?.all?.length} selected</S.SelectedCount>
|
|
68
|
+
<S.BulkActions>
|
|
69
|
+
{filteredActions.map(
|
|
70
|
+
(item) =>
|
|
71
|
+
item && (
|
|
72
|
+
<Button
|
|
73
|
+
key={item.text}
|
|
74
|
+
type="button"
|
|
75
|
+
buttonStyle="text"
|
|
76
|
+
icon={item.icon}
|
|
77
|
+
onClick={() => handleActionClick(item.action, item.text)}
|
|
78
|
+
disabled={isLoading}
|
|
79
|
+
>
|
|
80
|
+
{item.text}
|
|
81
|
+
</Button>
|
|
82
|
+
),
|
|
83
|
+
)}
|
|
84
|
+
{exportAction && <ExportButton onClick={exportAction} />}
|
|
85
|
+
</S.BulkActions>
|
|
86
|
+
</S.BulkActionsWrapper>
|
|
87
|
+
)}
|
|
40
88
|
</S.BulkHeader>
|
|
41
89
|
);
|
|
42
90
|
};
|
|
@@ -50,6 +98,8 @@ interface IBulkSelectionProps {
|
|
|
50
98
|
className?: string;
|
|
51
99
|
exportAction?: (formats: (string | number)[]) => void;
|
|
52
100
|
selectedItems: IBulkSelectedItems;
|
|
101
|
+
isLoading: boolean;
|
|
102
|
+
itemLabel: ItemLabel;
|
|
53
103
|
}
|
|
54
104
|
|
|
55
105
|
export default BulkSelectionOptions;
|
|
@@ -43,4 +43,10 @@ const SelectedCount = styled.span`
|
|
|
43
43
|
font-weight: ${(p) => p.theme.fontWeight.regular};
|
|
44
44
|
`;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
const LoadingText = styled.span`
|
|
47
|
+
margin-left: ${({ theme }) => theme.spacing.xs};
|
|
48
|
+
color: ${({ theme }) => theme.color.interactive01};
|
|
49
|
+
${({ theme }) => theme.textStyle.uiButton};
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
export { BulkActions, BulkActionsWrapper, BulkHeader, Counter, LoadingText, SelectAllCheckField, SelectedCount };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LOCALE } from "@ax/locales";
|
|
2
|
+
|
|
3
|
+
// TODO: Tipar las acciones para que no sean cualquier string...
|
|
4
|
+
// export type BulkActions = "publish" | "unpublish" | "delete" | "processing" | "Move to" | "Deativate";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the appropriate loading text for bulk actions based on the current action and loading state.
|
|
8
|
+
*
|
|
9
|
+
* @param currentAction - The current action being performed ("publish", "unpublish", "delete", etc.).
|
|
10
|
+
* @returns The localized loading message corresponding to the current bulk action.
|
|
11
|
+
*/
|
|
12
|
+
export const getBulkLoadingText = (currentAction: string) => {
|
|
13
|
+
const options = {
|
|
14
|
+
publish: LOCALE.common.publishing,
|
|
15
|
+
unpublish: LOCALE.common.unpublishing,
|
|
16
|
+
delete: LOCALE.common.deleting,
|
|
17
|
+
processing: LOCALE.common.processing,
|
|
18
|
+
download: LOCALE.common.downloading,
|
|
19
|
+
"Move to": LOCALE.common.moving,
|
|
20
|
+
Deactivate: LOCALE.common.deactivating,
|
|
21
|
+
Activate: LOCALE.common.activating,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return options[currentAction as keyof typeof options] || options.processing;
|
|
25
|
+
};
|
|
@@ -60,7 +60,6 @@ const PageConnectedField = (props: any): JSX.Element => {
|
|
|
60
60
|
const overrideableFields = ["header", "footer"];
|
|
61
61
|
const isOverride = selectedContent.type && overrideableFields.includes(selectedContent.type);
|
|
62
62
|
const isPageHome = componentType === "page" && selectedContent.isHome;
|
|
63
|
-
const allowModifySlug = !selectedContent.id && !selectedContent.isHome;
|
|
64
63
|
const isNewPage = componentType === "page" && !selectedContent.id;
|
|
65
64
|
const error = errors.find((err: any) => err.editorID === selectedEditorID && err.key === objKey);
|
|
66
65
|
const isFormPage = selectedContent.component === "FormPage";
|
|
@@ -141,7 +140,8 @@ const PageConnectedField = (props: any): JSX.Element => {
|
|
|
141
140
|
if (isPageTitle) {
|
|
142
141
|
setCurrentPageName(value);
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
const canModifySlug = !selectedContent.id && !selectedContent.isHome;
|
|
144
|
+
if (canModifySlug) {
|
|
145
145
|
updateEditorContent(selectedEditorID, "slug", slugify(value));
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -11,7 +11,7 @@ const noteTitle = "Global content";
|
|
|
11
11
|
const errorText = "You don't have the permissions to edit the original content.";
|
|
12
12
|
|
|
13
13
|
const GlobalPageForm = (props: IGlobalPageFormProps): JSX.Element => {
|
|
14
|
-
const { selectedTab, setSelectedTab, schema, pageTitle, setHistoryPush, actions, header, footer } = props;
|
|
14
|
+
const { selectedTab, setSelectedTab, schema, pageTitle, setHistoryPush, actions, header, footer, isDirty, onNavigateWithDirty } = props;
|
|
15
15
|
const tabs = ["content", "config"];
|
|
16
16
|
|
|
17
17
|
const { themes } = useThemes();
|
|
@@ -24,9 +24,17 @@ const GlobalPageForm = (props: IGlobalPageFormProps): JSX.Element => {
|
|
|
24
24
|
|
|
25
25
|
const handleClick = async () => {
|
|
26
26
|
if (isAllowedToEditGlobalData) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const navigate = async () => {
|
|
28
|
+
await handleGetGlobalPage();
|
|
29
|
+
const path = "/data/pages/editor";
|
|
30
|
+
setHistoryPush?.(path, true);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (isDirty && onNavigateWithDirty) {
|
|
34
|
+
onNavigateWithDirty(navigate);
|
|
35
|
+
} else {
|
|
36
|
+
await navigate();
|
|
37
|
+
}
|
|
30
38
|
} else {
|
|
31
39
|
actions.setNotificationAction({
|
|
32
40
|
type: "error",
|
|
@@ -176,6 +184,8 @@ export interface IGlobalPageFormProps {
|
|
|
176
184
|
setHistoryPush?: (path: string, isEditor: boolean) => void;
|
|
177
185
|
header?: number | null;
|
|
178
186
|
footer?: number | null;
|
|
187
|
+
isDirty?: boolean;
|
|
188
|
+
onNavigateWithDirty?: (navigateCallback: () => void) => void;
|
|
179
189
|
actions: {
|
|
180
190
|
getGlobalFromLocalPageAction(): Promise<void>;
|
|
181
191
|
saveCurrentSiteInfoAction(): Promise<void>;
|
|
@@ -37,6 +37,8 @@ const ConfigPanel = (props: IStateProps): JSX.Element => {
|
|
|
37
37
|
footer,
|
|
38
38
|
isEditLive,
|
|
39
39
|
isDisabled = false,
|
|
40
|
+
isDirty,
|
|
41
|
+
onNavigateWithDirty,
|
|
40
42
|
} = props;
|
|
41
43
|
|
|
42
44
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
@@ -74,6 +76,8 @@ const ConfigPanel = (props: IStateProps): JSX.Element => {
|
|
|
74
76
|
actions={actions}
|
|
75
77
|
header={header}
|
|
76
78
|
footer={footer}
|
|
79
|
+
isDirty={isDirty}
|
|
80
|
+
onNavigateWithDirty={onNavigateWithDirty}
|
|
77
81
|
/>
|
|
78
82
|
);
|
|
79
83
|
} else {
|
|
@@ -139,6 +143,8 @@ export interface IStateProps {
|
|
|
139
143
|
footer?: number | null;
|
|
140
144
|
isEditLive?: boolean;
|
|
141
145
|
isDisabled?: boolean;
|
|
146
|
+
isDirty?: boolean;
|
|
147
|
+
onNavigateWithDirty?: (navigateCallback: () => void) => void;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
export default ConfigPanel;
|
|
@@ -6,6 +6,7 @@ import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable"
|
|
|
6
6
|
import type { IComponent, IModule, INotification, ISchemaField, ITemplate, ModuleCategoryInfo } from "@ax/types";
|
|
7
7
|
import { ComponentContainer, Toast } from "@ax/components";
|
|
8
8
|
import { useBulkSelection, useToast } from "@ax/hooks";
|
|
9
|
+
import { replaceElements } from "@ax/forms";
|
|
9
10
|
|
|
10
11
|
import AddItemButton from "./AddItemButton";
|
|
11
12
|
import { getComponentProps, getModulesToPaste, getTypefromKey } from "../helpers";
|
|
@@ -40,6 +41,10 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
40
41
|
const type = getTypefromKey(objKey);
|
|
41
42
|
const { contentType = type } = field;
|
|
42
43
|
const componentIDs: number[] = value?.length ? value.map((element) => element.editorID) : [];
|
|
44
|
+
const componentType = field.reference ? selectedContent[field.reference] : selectedContent.kind;
|
|
45
|
+
const isModuleArr = contentType === "modules";
|
|
46
|
+
const isComponentModule = contentType === "components";
|
|
47
|
+
const showAddItemButton = !maxItems || (value && value.length < maxItems);
|
|
43
48
|
|
|
44
49
|
const {
|
|
45
50
|
addModuleAction,
|
|
@@ -57,7 +62,6 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
57
62
|
useBulkSelection(componentIDs);
|
|
58
63
|
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
59
64
|
|
|
60
|
-
|
|
61
65
|
const sensors = useSensors(
|
|
62
66
|
useSensor(PointerSensor, {
|
|
63
67
|
activationConstraint: {
|
|
@@ -80,17 +84,13 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
80
84
|
field,
|
|
81
85
|
);
|
|
82
86
|
|
|
87
|
+
const replacedElementsToPaste = replaceElements(modulesToPaste, componentType);
|
|
88
|
+
const showPasteModuleButton = showAddItemButton && replacedElementsToPaste.length > 0;
|
|
89
|
+
|
|
83
90
|
const getText = (name: string, index: number) => {
|
|
84
91
|
return value && value.length > 1 ? `#${index + 1} ${name}` : name;
|
|
85
92
|
};
|
|
86
93
|
|
|
87
|
-
const componentType = field.reference ? selectedContent[field.reference] : selectedContent.kind;
|
|
88
|
-
|
|
89
|
-
const isModuleArr = contentType === "modules";
|
|
90
|
-
const isComponentModule = contentType === "components";
|
|
91
|
-
const showAddItemButton = !maxItems || (value && value.length < maxItems);
|
|
92
|
-
const showPasteModuleButton = showAddItemButton && modulesToPaste.length > 0;
|
|
93
|
-
|
|
94
94
|
const handleAddModule = (moduleType: string) => addModuleAction(moduleType, objKey, editorID, isComponentModule);
|
|
95
95
|
|
|
96
96
|
const handleAddComponent = () => addComponentAction?.(componentType, objKey);
|
|
@@ -242,7 +242,7 @@ const SameComponentArray = (props: ISameComponentArrayProps): JSX.Element => {
|
|
|
242
242
|
setNotification={setNotificationAction}
|
|
243
243
|
setHistoryPush={setHistoryPush}
|
|
244
244
|
arrayKey={objKey}
|
|
245
|
-
modulesToPaste={
|
|
245
|
+
modulesToPaste={replacedElementsToPaste}
|
|
246
246
|
slots={maxItems ? maxItems - value.length : null}
|
|
247
247
|
/>
|
|
248
248
|
)}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { useSortable } from "@dnd-kit/sortable";
|
|
3
|
-
|
|
4
|
-
import { IDataSource, IStructuredDataContent } from "@ax/types";
|
|
5
|
-
import { getFormattedDateWithTimezone } from "@ax/helpers";
|
|
6
|
-
|
|
7
1
|
import { Icon } from "@ax/components";
|
|
2
|
+
import { getFormattedDateWithTimezone, getSlugFromUrl } from "@ax/helpers";
|
|
3
|
+
import type { IDataSource, IStructuredDataContent } from "@ax/types";
|
|
4
|
+
|
|
5
|
+
import { useSortable } from "@dnd-kit/sortable";
|
|
8
6
|
|
|
9
7
|
import * as S from "./style";
|
|
10
8
|
|
|
@@ -50,6 +48,7 @@ const Item = (props: IProps): JSX.Element => {
|
|
|
50
48
|
<S.StyledActionMenu icon="more" options={menuOptions} size="s" tooltip="Actions" />
|
|
51
49
|
</S.Header>
|
|
52
50
|
<S.Title>{item.content.title}</S.Title>
|
|
51
|
+
<S.Slug>{getSlugFromUrl(item.relatedPage?.url)}</S.Slug>
|
|
53
52
|
</S.TextWrapper>
|
|
54
53
|
</S.Item>
|
|
55
54
|
);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import styled from "styled-components";
|
|
3
|
-
import { CSS, Transform } from "@dnd-kit/utilities";
|
|
4
|
-
|
|
5
1
|
import { ActionMenu } from "@ax/components";
|
|
6
2
|
|
|
3
|
+
import { CSS, type Transform } from "@dnd-kit/utilities";
|
|
4
|
+
import styled from "styled-components";
|
|
5
|
+
|
|
7
6
|
const StyledActionMenu = styled((props) => <ActionMenu {...props} />)`
|
|
8
7
|
width: ${(p) => p.theme.spacing.m};
|
|
9
8
|
height: ${(p) => p.theme.spacing.m};
|
|
@@ -54,6 +53,7 @@ const Header = styled.div`
|
|
|
54
53
|
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
55
54
|
`;
|
|
56
55
|
|
|
56
|
+
// biome-ignore lint/suspicious/noShadowRestrictedNames: conflicts with js Date
|
|
57
57
|
const Date = styled.div`
|
|
58
58
|
${(p) => p.theme.textStyle.uiXS};
|
|
59
59
|
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
@@ -96,15 +96,21 @@ const IconHandleWrapper = styled.div`
|
|
|
96
96
|
}
|
|
97
97
|
`;
|
|
98
98
|
|
|
99
|
+
const Slug = styled.span`
|
|
100
|
+
${({ theme }) => theme.textStyle.uiXS};
|
|
101
|
+
color: ${({ theme }) => theme.colors.textMediumEmphasis};
|
|
102
|
+
`;
|
|
103
|
+
|
|
99
104
|
export {
|
|
100
|
-
Item,
|
|
101
|
-
TextWrapper,
|
|
102
|
-
Header,
|
|
103
|
-
Date,
|
|
104
|
-
Type,
|
|
105
|
-
Title,
|
|
106
105
|
ButtonsWrapper,
|
|
106
|
+
Date,
|
|
107
107
|
HandleWrapper,
|
|
108
|
+
Header,
|
|
108
109
|
IconHandleWrapper,
|
|
110
|
+
Item,
|
|
111
|
+
Slug,
|
|
109
112
|
StyledActionMenu,
|
|
113
|
+
TextWrapper,
|
|
114
|
+
Title,
|
|
115
|
+
Type,
|
|
110
116
|
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import { IDataSource, IStructuredDataContent } from "@ax/types";
|
|
4
|
-
import { getFormattedDateWithTimezone } from "@ax/helpers";
|
|
5
1
|
import { CheckField, Tooltip } from "@ax/components";
|
|
2
|
+
import { getFormattedDateWithTimezone, getSlugFromUrl } from "@ax/helpers";
|
|
3
|
+
import type { IDataSource, IStructuredDataContent } from "@ax/types";
|
|
6
4
|
|
|
7
5
|
import * as S from "./style";
|
|
8
6
|
|
|
@@ -24,6 +22,7 @@ const Item = (props: IProps): JSX.Element => {
|
|
|
24
22
|
{item.modified && <S.Date>{getFormattedDateWithTimezone(item.modified, "d MMM Y")}</S.Date>}
|
|
25
23
|
</S.Header>
|
|
26
24
|
<S.Title>{item.content.title}</S.Title>
|
|
25
|
+
<S.Slug>{getSlugFromUrl(item.relatedPage?.url)}</S.Slug>
|
|
27
26
|
</S.TextWrapper>
|
|
28
27
|
</S.Item>
|
|
29
28
|
</Tooltip>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
2
|
|
|
3
|
+
// biome-ignore lint/suspicious/noShadowRestrictedNames: conflicts with js Date
|
|
3
4
|
const Date = styled.div`
|
|
4
5
|
${(p) => p.theme.textStyle.uiXS};
|
|
5
6
|
`;
|
|
@@ -47,4 +48,9 @@ const Header = styled.div`
|
|
|
47
48
|
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
48
49
|
`;
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
const Slug = styled.span`
|
|
52
|
+
${({ theme }) => theme.textStyle.uiXS};
|
|
53
|
+
color: ${({ theme }) => theme.colors.textMediumEmphasis};
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export { Date, Header, Item, Slug, TextWrapper, Title, Type };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState, useRef, useEffect } from "react";
|
|
2
2
|
|
|
3
3
|
import { IconAction, VisualOption } from "@ax/components";
|
|
4
4
|
import { getOptions } from "../utils";
|
|
@@ -33,10 +33,10 @@ const ScrollableSelection = (props: IScrollableSelectionProps): JSX.Element => {
|
|
|
33
33
|
}, [carouselIndex, carouselItemWidth, columns]);
|
|
34
34
|
|
|
35
35
|
useEffect(() => {
|
|
36
|
-
if (carouselRef
|
|
36
|
+
if (carouselRef?.current) {
|
|
37
37
|
setCarouselItemWidth(Math.floor(carouselRef.current.offsetWidth / columns));
|
|
38
38
|
}
|
|
39
|
-
}, [
|
|
39
|
+
}, [columns]);
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<S.Wrapper data-testid="scrollableSelectionComponent">
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import ImageSelection, { IImageSelectionProps } from "./ImageSelection";
|
|
4
|
-
import ScrollableSelection, { IScrollableSelectionProps } from "./ScrollableSelection";
|
|
1
|
+
import ImageSelection, { type IImageSelectionProps } from "./ImageSelection";
|
|
2
|
+
import ScrollableSelection, { type IScrollableSelectionProps } from "./ScrollableSelection";
|
|
5
3
|
|
|
6
4
|
const VisualUniqueSelection = (props: IImageSelectionProps & IScrollableSelectionProps): JSX.Element => {
|
|
7
5
|
const { elementUniqueSelection = false } = props;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
3
|
|
|
3
4
|
import { useHandleClickOutside } from "@ax/hooks";
|
|
4
5
|
|
|
@@ -27,8 +28,7 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
27
28
|
useEffect(() => {
|
|
28
29
|
if (isOpen && menuOptionsRef?.current) {
|
|
29
30
|
const bounding = menuOptionsRef.current.children[0].getBoundingClientRect();
|
|
30
|
-
const boundingChild =
|
|
31
|
-
menuOptionsRef.current.children[0] && menuOptionsRef.current.children[0].getBoundingClientRect();
|
|
31
|
+
const boundingChild = menuOptionsRef.current.children[0]?.getBoundingClientRect();
|
|
32
32
|
if (bounding.bottom > (window.innerHeight || document.documentElement.clientHeight)) {
|
|
33
33
|
menuOptionsRef.current.scrollIntoView({ block: "end", behavior: "smooth" });
|
|
34
34
|
}
|
|
@@ -52,7 +52,7 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
52
52
|
|
|
53
53
|
const closeWhenChecked = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
54
54
|
const target = e.target as HTMLInputElement;
|
|
55
|
-
const isChecked = target
|
|
55
|
+
const isChecked = target?.checked;
|
|
56
56
|
isChecked && setOpen(false);
|
|
57
57
|
};
|
|
58
58
|
|
|
@@ -96,7 +96,7 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
96
96
|
data-testid="floating-menu"
|
|
97
97
|
>
|
|
98
98
|
<S.ButtonWrapper ref={buttonRef} data-testid="floating-menu-button">
|
|
99
|
-
<Button />
|
|
99
|
+
<Button disabled={disabled} />
|
|
100
100
|
</S.ButtonWrapper>
|
|
101
101
|
|
|
102
102
|
{isOpen && (
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function SvgSmallCircle(props) {
|
|
2
|
+
return (
|
|
3
|
+
<svg viewBox="0 0 100 100" {...props}>
|
|
4
|
+
<title>spinning</title>
|
|
5
|
+
<circle
|
|
6
|
+
cx="50"
|
|
7
|
+
cy="50"
|
|
8
|
+
r="40"
|
|
9
|
+
fill="none"
|
|
10
|
+
stroke="#5057FF"
|
|
11
|
+
stroke-width="10"
|
|
12
|
+
stroke-linecap="round"
|
|
13
|
+
stroke-dasharray="200 300"
|
|
14
|
+
>
|
|
15
|
+
<animateTransform
|
|
16
|
+
attributeName="transform"
|
|
17
|
+
attributeType="XML"
|
|
18
|
+
type="rotate"
|
|
19
|
+
from="0 50 50"
|
|
20
|
+
to="360 50 50"
|
|
21
|
+
dur="0.75s"
|
|
22
|
+
repeatCount="indefinite"
|
|
23
|
+
/>
|
|
24
|
+
</circle>
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default SvgSmallCircle;
|
|
@@ -2,13 +2,14 @@ import React from "react";
|
|
|
2
2
|
|
|
3
3
|
import Circle from "./components/Circle";
|
|
4
4
|
import Dots from "./components/Dots";
|
|
5
|
+
import SmallCircle from "./components/SmallCircle";
|
|
5
6
|
|
|
6
|
-
const components: Record<string, () => JSX.Element> = { Circle, Dots };
|
|
7
|
+
const components: Record<string, () => JSX.Element> = { Circle, Dots, SmallCircle };
|
|
7
8
|
|
|
8
9
|
const getImage = (name: string) => {
|
|
9
10
|
try {
|
|
10
11
|
return components[name];
|
|
11
|
-
} catch (
|
|
12
|
+
} catch (_err) {
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
14
15
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { Button, Icon } from "@ax/components";
|
|
3
2
|
|
|
4
3
|
import * as S from "./style";
|
|
@@ -16,8 +15,7 @@ const ActionMenuItem = (item: any, color?: boolean) => {
|
|
|
16
15
|
const ActionMenuBtn = (props: any) => {
|
|
17
16
|
const { menu } = props;
|
|
18
17
|
return (
|
|
19
|
-
menu &&
|
|
20
|
-
menu.button && (
|
|
18
|
+
menu?.button && (
|
|
21
19
|
<S.ButtonWrapper>
|
|
22
20
|
<Button type="button" buttonStyle="line" onClick={menu.button.action} disabled={menu.button.disabled}>
|
|
23
21
|
{menu.button.label}
|
|
@@ -34,13 +32,13 @@ const ActionMenu = (props: any) => {
|
|
|
34
32
|
<S.ActionMenu>
|
|
35
33
|
<S.ActionMenuTitle> More actions </S.ActionMenuTitle>
|
|
36
34
|
<ActionMenuBtn menu={menu} />
|
|
37
|
-
{menu
|
|
35
|
+
{menu?.options.map((item: any) => item && ActionMenuItem(item))}
|
|
38
36
|
</S.ActionMenu>
|
|
39
37
|
);
|
|
40
38
|
};
|
|
41
39
|
|
|
42
40
|
const DownArrowButton = (props: any) => (
|
|
43
|
-
<S.IconWrapper inversed={props.inversed} data-testid="down-arrow-button-wrapper">
|
|
41
|
+
<S.IconWrapper inversed={props.inversed} disabled={props.disabled} data-testid="down-arrow-button-wrapper">
|
|
44
42
|
<Icon name="DownArrow" />
|
|
45
43
|
</S.IconWrapper>
|
|
46
44
|
);
|
|
@@ -57,4 +55,4 @@ const ActionSimpleMenu = (props: any) => {
|
|
|
57
55
|
);
|
|
58
56
|
};
|
|
59
57
|
|
|
60
|
-
export { ActionMenu,
|
|
58
|
+
export { ActionMenu, ActionSimpleMenu, DownArrowButton };
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { type RouteComponentProps, withRouter } from "react-router-dom";
|
|
3
3
|
|
|
4
|
-
import { IErrorItem, ILanguage } from "@ax/types";
|
|
5
|
-
import { getScheduleFormatDate, trimText } from "@ax/helpers";
|
|
6
|
-
import { useModal } from "@ax/hooks";
|
|
7
4
|
import {
|
|
8
5
|
Button,
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
ErrorCenter,
|
|
7
|
+
ExportButton,
|
|
11
8
|
Flag,
|
|
12
9
|
FloatingMenu,
|
|
10
|
+
Icon,
|
|
11
|
+
IconAction,
|
|
13
12
|
LanguageMenu,
|
|
13
|
+
Modal,
|
|
14
|
+
SearchField,
|
|
14
15
|
Tabs,
|
|
15
16
|
Tooltip,
|
|
16
|
-
ErrorCenter,
|
|
17
|
-
SearchField,
|
|
18
|
-
Modal,
|
|
19
|
-
ExportButton,
|
|
20
17
|
} from "@ax/components";
|
|
18
|
+
import { getScheduleFormatDate, trimText } from "@ax/helpers";
|
|
19
|
+
import { useModal } from "@ax/hooks";
|
|
20
|
+
import type { IErrorItem, ILanguage } from "@ax/types";
|
|
21
21
|
|
|
22
22
|
import { ActionMenu, ActionSimpleMenu, DownArrowButton } from "./atoms";
|
|
23
23
|
|
|
@@ -53,6 +53,7 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
53
53
|
isDirty,
|
|
54
54
|
exportAction,
|
|
55
55
|
scheduledPublication,
|
|
56
|
+
isSaving,
|
|
56
57
|
} = props;
|
|
57
58
|
|
|
58
59
|
const publishedTooltip: Record<string, string> = {
|
|
@@ -275,7 +276,7 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
275
276
|
)}
|
|
276
277
|
{downArrowMenu?.displayed && (downArrowMenu.button || downArrowMenu.options.length > 0) && (
|
|
277
278
|
<Tooltip content="Actions" hideOnClick bottom>
|
|
278
|
-
<FloatingMenu Button={DownArrowButton} isInAppBar={true}>
|
|
279
|
+
<FloatingMenu Button={DownArrowButton} isInAppBar={true} disabled={isSaving}>
|
|
279
280
|
<ActionMenu menu={downArrowMenu} />
|
|
280
281
|
</FloatingMenu>
|
|
281
282
|
</Tooltip>
|
|
@@ -317,6 +318,7 @@ export interface IAppBarProps {
|
|
|
317
318
|
isDirty?: boolean;
|
|
318
319
|
exportAction?(formats: (number | string)[]): void;
|
|
319
320
|
scheduledPublication?: string | null;
|
|
321
|
+
isSaving?: boolean;
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
type IProps = IAppBarProps & RouteComponentProps;
|