@griddo/ax 12.7.1 → 12.8.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 (52) hide show
  1. package/package.json +2 -2
  2. package/src/GlobalStore.tsx +3 -1
  3. package/src/__tests__/components/ConfigPanel/GlobalPageForm/GlobalPageForm.test.tsx +7 -3
  4. package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.style.test.tsx +44 -0
  5. package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.test.tsx +109 -0
  6. package/src/__tests__/components/Nav/Nav.test.tsx +75 -2
  7. package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +50 -21
  8. package/src/__tests__/components/Toast/Toast.test.tsx +37 -1
  9. package/src/__tests__/hooks/broadcast.test.tsx +263 -0
  10. package/src/api/utils.tsx +7 -6
  11. package/src/components/Browser/index.tsx +10 -2
  12. package/src/components/ConfigPanel/GlobalPageForm/index.tsx +3 -4
  13. package/src/components/Fields/Wysiwyg/atoms.tsx +1 -1
  14. package/src/components/Fields/Wysiwyg/index.tsx +28 -0
  15. package/src/components/Fields/Wysiwyg/style.tsx +41 -1
  16. package/src/components/MainWrapper/index.tsx +14 -2
  17. package/src/components/Nav/index.tsx +21 -6
  18. package/src/components/ResizePanel/index.tsx +8 -3
  19. package/src/components/Toast/index.tsx +4 -1
  20. package/src/containers/ActivityLog/actions.tsx +4 -7
  21. package/src/containers/PageEditor/actions.tsx +14 -3
  22. package/src/helpers/containerEvaluations.tsx +8 -0
  23. package/src/hooks/broadcast.ts +160 -0
  24. package/src/hooks/index.tsx +5 -0
  25. package/src/modules/ActivityLog/index.tsx +1 -0
  26. package/src/modules/Analytics/index.tsx +1 -1
  27. package/src/modules/App/index.tsx +21 -6
  28. package/src/modules/Content/PageItem/index.tsx +36 -19
  29. package/src/modules/Content/index.tsx +5 -7
  30. package/src/modules/FileDrive/FileModal/DetailPanel/UsageContent/index.tsx +5 -14
  31. package/src/modules/FileDrive/index.tsx +1 -1
  32. package/src/modules/Forms/FormUseModal/index.tsx +3 -8
  33. package/src/modules/GlobalEditor/atoms.tsx +35 -1
  34. package/src/modules/GlobalEditor/index.tsx +169 -51
  35. package/src/modules/GlobalSettings/Robots/index.tsx +1 -1
  36. package/src/modules/MediaGallery/ImageModal/DetailPanel/UsageContent/index.tsx +6 -15
  37. package/src/modules/MediaGallery/index.tsx +1 -1
  38. package/src/modules/PageEditor/atoms.tsx +35 -1
  39. package/src/modules/PageEditor/index.tsx +168 -48
  40. package/src/modules/Redirects/index.tsx +1 -0
  41. package/src/modules/Settings/Languages/index.tsx +1 -1
  42. package/src/modules/Settings/SeoAnalyticsSettings/Analytics/index.tsx +1 -0
  43. package/src/modules/Settings/Social/index.tsx +1 -1
  44. package/src/modules/StructuredData/Form/index.tsx +108 -10
  45. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +31 -11
  46. package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +17 -3
  47. package/src/modules/StructuredData/StructuredDataList/index.tsx +6 -4
  48. package/src/modules/StructuredData/atoms.tsx +35 -1
  49. package/src/routes/multisite.tsx +34 -18
  50. package/src/routes/site.tsx +40 -21
  51. package/src/storeRegistry.ts +5 -0
  52. package/src/modules/StructuredData/index.tsx +0 -18
@@ -1,4 +1,4 @@
1
- import { useState } from "react";
1
+ import { type MouseEvent as ReactMouseEvent, useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
4
  import {
@@ -125,11 +125,20 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
125
125
  scheduled: `Scheduled publication: ${isScheduledPub ? getScheduleFormatDate(publicationScheduled) : ""}`,
126
126
  };
127
127
 
128
- const _handleClick = () => {
128
+ const _handleClick = (e?: ReactMouseEvent) => {
129
+ const pageID = globalPage.haveDraftPage ? globalPage.haveDraftPage : globalPage.id;
130
+ if (e?.ctrlKey || e?.metaKey) {
131
+ window.open(`/data/pages/editor/${pageID}`, "_blank");
132
+ return;
133
+ }
129
134
  handleClick(true, globalPage);
130
135
  };
131
136
 
132
- const handleEditLivePage = () => {
137
+ const handleEditLivePage = (e?: ReactMouseEvent) => {
138
+ if (e?.ctrlKey || e?.metaKey) {
139
+ window.open(`/data/pages/editor/${globalPage.id}`, "_blank");
140
+ return;
141
+ }
133
142
  handleClick(true, globalPage, true);
134
143
  };
135
144
 
@@ -215,13 +224,18 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
215
224
  };
216
225
 
217
226
  const handleDuplicatePage = async () => {
218
- const isDuplicated = await duplicatePage(globalPage.id, duplicateModalState);
219
- if (isDuplicated) {
227
+ const duplicatedID = await duplicatePage(globalPage.id, duplicateModalState);
228
+ if (duplicatedID) {
220
229
  toggleModal("duplicate");
221
- setHistoryPush("data/pages/editor", true);
230
+ setHistoryPush(`/data/pages/editor/${duplicatedID}`, true);
222
231
  }
223
232
  };
224
233
 
234
+ const handleOpenInNewTab = () => {
235
+ const pageID = globalPage.haveDraftPage ? globalPage.haveDraftPage : globalPage.id;
236
+ window.open(`/data/pages/editor/${pageID}`, "_blank");
237
+ };
238
+
225
239
  let menuOptions: IPageOption[] = [];
226
240
 
227
241
  if (isAllowedTo.duplicatePages) {
@@ -276,6 +290,12 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
276
290
  action: viewPage,
277
291
  };
278
292
 
293
+ const newTabOption = {
294
+ label: "Open in new tab",
295
+ icon: "openOutside",
296
+ action: handleOpenInNewTab,
297
+ };
298
+
279
299
  const editOptions = [
280
300
  {
281
301
  label: "View live",
@@ -300,7 +320,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
300
320
 
301
321
  menuOptions = globalPage.haveDraftPage ? [...editOptions, ...menuOptions] : menuOptions;
302
322
 
303
- menuOptions = globalPage.liveStatus?.status === pageStatus.PUBLISHED ? [viewOption, ...menuOptions] : menuOptions;
323
+ menuOptions = globalPage.liveStatus?.status === pageStatus.PUBLISHED ? [viewOption, newTabOption, ...menuOptions] : [newTabOption, ...menuOptions];
304
324
 
305
325
  const isTranslated = globalPage.pageLanguages.length > 1;
306
326
 
@@ -333,10 +353,10 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
333
353
  languageActions.setLanguage(lang);
334
354
 
335
355
  const selectedPageLanguage = getSelectedPageLanguage(language);
356
+ const targetPageID = selectedPageLanguage ? selectedPageLanguage.pageId : globalPage.id;
357
+ if (!selectedPageLanguage) languageActions.createNewTranslation?.(true);
336
358
 
337
- selectedPageLanguage ? setCurrentPageID(selectedPageLanguage.pageId) : languageActions.createNewTranslation?.(true);
338
-
339
- setHistoryPush("data/pages/editor", true);
359
+ setHistoryPush(`data/pages/editor/${targetPageID}`, true);
340
360
  };
341
361
 
342
362
  const languageMenu = () => (
@@ -481,7 +501,7 @@ interface IGlobalPageItemProps {
481
501
  isAllPages?: boolean;
482
502
  globalPage: IPage;
483
503
  updatePageStatus(ids: number[], status: string, updatedFromList: boolean): Promise<boolean>;
484
- duplicatePage(pageID: number, data: { title: string; slug: string }, siteID?: number): Promise<boolean>;
504
+ duplicatePage(pageID: number, data: { title: string; slug: string }, siteID?: number): Promise<number | false>;
485
505
  getPage(pageID?: number, global?: boolean): Promise<void>;
486
506
  validatePage(publish?: boolean, browserRef?: any, currentPage?: IPage): Promise<boolean>;
487
507
  setHistoryPush(path: string, isEditor: boolean): void;
@@ -1,4 +1,4 @@
1
- import { useState } from "react";
1
+ import { type MouseEvent as ReactMouseEvent, useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
4
  import {
@@ -103,7 +103,12 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
103
103
  scheduled: `Scheduled publication: ${isScheduledPub ? getScheduleFormatDate(publicationScheduled) : ""}`,
104
104
  };
105
105
 
106
- const _handleClick = () => {
106
+ const _handleClick = (e?: ReactMouseEvent<HTMLDivElement>) => {
107
+ if (e?.ctrlKey || e?.metaKey) {
108
+ const prefix = currentSiteInfo ? "/sites" : "";
109
+ window.open(`${prefix}/data/${currentStructuredData?.id}/content/${structuredData.id}`, "_blank");
110
+ return;
111
+ }
107
112
  getDataContent(structuredData.id);
108
113
  setCurrentDataID(structuredData.id);
109
114
  handleClick();
@@ -130,6 +135,11 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
130
135
  handleClick();
131
136
  };
132
137
 
138
+ const handleOpenInNewTab = () => {
139
+ const prefix = currentSiteInfo ? "/sites" : "";
140
+ window.open(`${prefix}/data/${currentStructuredData?.id}/content/${structuredData.id}`, "_blank");
141
+ };
142
+
133
143
  const checkStatus = () => {
134
144
  return isScheduledPub ? "scheduled" : structuredData.draft ? "offline" : "active";
135
145
  };
@@ -210,7 +220,11 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
210
220
  "Not translatable"
211
221
  );
212
222
 
213
- const menuOptions = [];
223
+ const menuOptions = [{
224
+ label: "Open in new tab",
225
+ icon: "openOutside",
226
+ action: handleOpenInNewTab,
227
+ }];
214
228
 
215
229
  if (!isDisabled && isEditable && isAllowedTo.duplicatePages) {
216
230
  menuOptions.push({
@@ -324,11 +324,13 @@ const StructuredDataList = (props: IProps): JSX.Element => {
324
324
  }, [filterValues]);
325
325
 
326
326
  const handleClick = (isFromPage?: boolean, globalPage?: IPage, forceLive?: boolean) => {
327
+ let path: string;
327
328
  if (isFromPage && globalPage) {
328
329
  const pageID = globalPage.haveDraftPage && !forceLive ? globalPage.haveDraftPage : globalPage.id;
329
- setCurrentPageID(pageID);
330
+ path = `data/pages/editor/${pageID}`;
331
+ } else {
332
+ path = `data/${currentStructuredData?.id}/content`;
330
333
  }
331
- const path = isFromPage ? "data/pages/editor" : `data/${currentStructuredData?.id}/editor`;
332
334
  setHistoryPush(path, isFromPage);
333
335
  };
334
336
 
@@ -516,14 +518,14 @@ const StructuredDataList = (props: IProps): JSX.Element => {
516
518
  setSelectedStructuredData(dataID, scope);
517
519
  setCurrentDataID(null);
518
520
  resetForm(true);
519
- const path = `data/${dataID}/editor`;
521
+ const path = `data/${dataID}/content`;
520
522
  setHistoryPush(path, false);
521
523
  } else {
522
524
  addTemplate(template);
523
525
  setCurrentPageID(null);
524
526
  setCurrentPageStatus("offline");
525
527
  setCurrentPageName("New Global Page");
526
- const path = "/data/pages/editor/new";
528
+ const path = "/data/pages/editor";
527
529
  setHistoryPush(path, true);
528
530
  }
529
531
  };
@@ -84,4 +84,38 @@ interface IDeleteModal extends IModal {
84
84
  title?: string;
85
85
  }
86
86
 
87
- export { DeleteModal };
87
+ const ConflictSaveModal = (props: IConflictSaveModal): JSX.Element => {
88
+ const { isOpen, toggleModal, onSaveAnyway } = props;
89
+
90
+ const mainAction = {
91
+ title: "Continue anyway",
92
+ onClick: onSaveAnyway,
93
+ };
94
+
95
+ const secondaryAction = { title: "Cancel", onClick: toggleModal };
96
+
97
+ return (
98
+ <Modal
99
+ isOpen={isOpen}
100
+ hide={toggleModal}
101
+ size="S"
102
+ height="auto"
103
+ title="Continue with an outdated version?"
104
+ mainAction={mainAction}
105
+ secondaryAction={secondaryAction}
106
+ >
107
+ <S.ModalContent>
108
+ <p>
109
+ This content <strong>was updated in another tab</strong> after you opened it, so what you see here{" "}
110
+ <strong>is out of date</strong>. Reload to get the latest version first.
111
+ </p>
112
+ </S.ModalContent>
113
+ </Modal>
114
+ );
115
+ };
116
+
117
+ interface IConflictSaveModal extends IModal {
118
+ onSaveAnyway: () => void;
119
+ }
120
+
121
+ export { DeleteModal, ConflictSaveModal };
@@ -1,21 +1,21 @@
1
- import StructuredDataList from "./../modules/StructuredData/StructuredDataList";
1
+ import ActivityLog from "../modules/ActivityLog";
2
+ import AnalyticsSettings from "../modules/Analytics";
2
3
  import CategoriesList from "./../modules/Categories/CategoriesList";
4
+ import FileDrive from "../modules/FileDrive";
5
+ import FormCategoriesList from "../modules/Forms/FormCategoriesList";
6
+ import FormEditor from "../modules/Forms/FormEditor";
7
+ import FormList from "../modules/Forms/FormList";
8
+ import FramePreview from "../modules/FramePreview";
9
+ import Editor from "./../modules/GlobalEditor";
10
+ import GlobalSettings from "./../modules/GlobalSettings";
11
+ import MediaGallery from "../modules/MediaGallery";
3
12
  import Sites from "./../modules/Sites";
4
- import StructuredData from "./../modules/StructuredData";
13
+ import StructuredDataForm from "./../modules/StructuredData/Form";
14
+ import StructuredDataList from "./../modules/StructuredData/StructuredDataList";
5
15
  import Users from "./../modules/Users";
6
16
  import Profile from "../modules/Users/Profile";
7
17
  import UserCreate from "../modules/Users/UserCreate";
8
18
  import UserEdit from "../modules/Users/UserEdit";
9
- import Editor from "./../modules/GlobalEditor";
10
- import GlobalSettings from "./../modules/GlobalSettings";
11
- import AnalyticsSettings from "../modules/Analytics";
12
- import FramePreview from "../modules/FramePreview";
13
- import FileDrive from "../modules/FileDrive";
14
- import FormList from "../modules/Forms/FormList";
15
- import FormEditor from "../modules/Forms/FormEditor";
16
- import FormCategoriesList from "../modules/Forms/FormCategoriesList";
17
- import MediaGallery from "../modules/MediaGallery";
18
- import ActivityLog from "../modules/ActivityLog";
19
19
 
20
20
  export default [
21
21
  {
@@ -37,27 +37,43 @@ export default [
37
37
  {
38
38
  path: `/data/pages/editor`,
39
39
  component: Editor,
40
+ name: "New Page Editor",
41
+ showInNav: false,
42
+ hideNav: true,
43
+ permission: "global.globalData.createAllGlobalData",
44
+ },
45
+ {
46
+ path: `/data/pages/editor/:pageID`,
47
+ component: Editor,
40
48
  name: "Page Editor",
41
49
  showInNav: false,
42
50
  hideNav: true,
43
51
  permission: "global.globalData.readGlobalData",
44
52
  },
45
53
  {
46
- path: `/data/pages/editor/new`,
47
- component: Editor,
48
- name: "New Page Editor",
54
+ path: "/data/:id/content/:contentId",
55
+ component: StructuredDataForm,
49
56
  showInNav: false,
57
+ name: "StructuredData Item",
58
+ permission: "global.globalData.readGlobalData",
50
59
  hideNav: true,
51
- permission: "global.globalData.createAllGlobalData",
52
60
  },
53
61
  {
54
- path: "/data/:id/editor",
55
- component: StructuredData,
62
+ path: "/data/:id/content",
63
+ component: StructuredDataForm,
56
64
  showInNav: false,
57
65
  name: "New StructuredData",
58
66
  permission: "global.globalData.readGlobalData",
59
67
  hideNav: true,
60
68
  },
69
+ {
70
+ path: "/data/:id",
71
+ component: StructuredDataList,
72
+ showInNav: false,
73
+ name: "StructuredData List",
74
+ permission: "global.globalData.accessToGlobalData",
75
+ hideNav: true,
76
+ },
61
77
  {
62
78
  path: "/categories",
63
79
  component: CategoriesList,
@@ -1,25 +1,26 @@
1
- import Menus from "./../modules/Navigation/Menus";
1
+ import CategoriesList from "./../modules/Categories/CategoriesList";
2
+ import Content from "./../modules/Content";
3
+ import FileDrive from "./../modules/FileDrive";
4
+ import FormCategoriesList from "../modules/Forms/FormCategoriesList";
5
+ import FormEditor from "../modules/Forms/FormEditor";
6
+ import FormList from "../modules/Forms/FormList";
7
+ import MediaGallery from "../modules/MediaGallery";
2
8
  import Defaults from "./../modules/Navigation/Defaults";
3
9
  import DefaultsEditor from "../modules/Navigation/Defaults/DefaultsEditor";
10
+ import Menus from "./../modules/Navigation/Menus";
4
11
  import Editor from "./../modules/PageEditor";
5
- import Content from "./../modules/Content";
6
- import ContentTypes from "./../modules/Settings/ContentTypes";
7
12
  import Settings from "./../modules/Settings";
8
- import CategoriesList from "./../modules/Categories/CategoriesList";
9
- import StructuredData from "./../modules/StructuredData";
10
- import SeoAnalyticsSettings from "./../modules/Settings/SeoAnalyticsSettings";
13
+ import ContentTypes from "./../modules/Settings/ContentTypes";
11
14
  import TemplateEditor from "../modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor";
15
+ import Integrations from "./../modules/Settings/Integrations";
16
+ import IntegrationForm from "./../modules/Settings/Integrations/IntegrationForm";
17
+ import SeoAnalyticsSettings from "./../modules/Settings/SeoAnalyticsSettings";
18
+ import StructuredDataForm from "./../modules/StructuredData/Form";
19
+ import StructuredDataList from "./../modules/StructuredData/StructuredDataList";
12
20
  import Users from "./../modules/Users";
21
+ import Profile from "./../modules/Users/Profile";
13
22
  import UserCreate from "./../modules/Users/UserCreate";
14
23
  import UserEdit from "./../modules/Users/UserEdit";
15
- import Profile from "./../modules/Users/Profile";
16
- import Integrations from "./../modules/Settings/Integrations";
17
- import IntegrationForm from "./../modules/Settings/Integrations/IntegrationForm";
18
- import FileDrive from "./../modules/FileDrive";
19
- import FormList from "../modules/Forms/FormList";
20
- import FormEditor from "../modules/Forms/FormEditor";
21
- import FormCategoriesList from "../modules/Forms/FormCategoriesList";
22
- import MediaGallery from "../modules/MediaGallery";
23
24
 
24
25
  const BASE_PATH = "/sites";
25
26
 
@@ -35,18 +36,18 @@ export default [
35
36
  {
36
37
  path: `${BASE_PATH}/pages/editor`,
37
38
  component: Editor,
38
- name: "Page Editor",
39
+ name: "New Page Editor",
39
40
  showInNav: false,
40
41
  hideNav: true,
41
- permission: "content.accessToPages",
42
+ permission: "content.createPages",
42
43
  },
43
44
  {
44
- path: `${BASE_PATH}/pages/editor/new`,
45
+ path: `${BASE_PATH}/pages/editor/:pageID`,
45
46
  component: Editor,
46
- name: "New Page Editor",
47
+ name: "Page Editor",
47
48
  showInNav: false,
48
49
  hideNav: true,
49
- permission: "content.createPages",
50
+ permission: "content.accessToPages",
50
51
  },
51
52
  {
52
53
  path: `${BASE_PATH}/categories`,
@@ -57,14 +58,32 @@ export default [
57
58
  permission: "categories.accessToSiteCategories",
58
59
  },
59
60
  {
60
- path: `${BASE_PATH}/data/:id/editor`,
61
- component: StructuredData,
61
+ path: `${BASE_PATH}/data/:id/content/:contentId`,
62
+ component: StructuredDataForm,
63
+ showInNav: false,
64
+ icon: "",
65
+ name: "StructuredData Item",
66
+ permission: "content.accessToPages",
67
+ hideNav: true,
68
+ },
69
+ {
70
+ path: `${BASE_PATH}/data/:id/content`,
71
+ component: StructuredDataForm,
62
72
  showInNav: false,
63
73
  icon: "",
64
74
  name: "New StructuredData",
65
75
  permission: "content.accessToPages",
66
76
  hideNav: true,
67
77
  },
78
+ {
79
+ path: `${BASE_PATH}/data/:id`,
80
+ component: StructuredDataList,
81
+ showInNav: false,
82
+ icon: "",
83
+ name: "StructuredData List",
84
+ permission: "content.accessToPages",
85
+ hideNav: true,
86
+ },
68
87
  { path: `${BASE_PATH}/profile`, component: Profile, name: "Profile", showInNav: false, icon: "User" },
69
88
  {
70
89
  path: `${BASE_PATH}/navigations`,
@@ -0,0 +1,5 @@
1
+ let _store: any = null;
2
+ export const setStore = (store: any): void => {
3
+ _store = store;
4
+ };
5
+ export const getStore = (): any => _store;
@@ -1,18 +0,0 @@
1
- import React from "react";
2
- import { Route, Switch } from "react-router-dom";
3
-
4
- import StructuredDataList from "./StructuredDataList";
5
- import Form from "./Form";
6
-
7
- const StructuredData = (): JSX.Element => {
8
- return (
9
- <Switch>
10
- <Route exact path="/data/:id" component={StructuredDataList} />
11
- <Route exact path="/data/pages/editor" />
12
- <Route exact path="/data/:id/editor" component={Form} />
13
- <Route exact path="/sites/data/:id/editor" component={Form} />
14
- </Switch>
15
- );
16
- };
17
-
18
- export default StructuredData;