@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.
Files changed (79) hide show
  1. package/config/griddo-config/index.js +1 -0
  2. package/package.json +2 -2
  3. package/src/components/BulkSelectionOptions/index.tsx +78 -28
  4. package/src/components/BulkSelectionOptions/style.tsx +7 -1
  5. package/src/components/BulkSelectionOptions/utils.tsx +25 -0
  6. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +2 -2
  7. package/src/components/ConfigPanel/GlobalPageForm/index.tsx +14 -4
  8. package/src/components/ConfigPanel/index.tsx +6 -0
  9. package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +9 -9
  10. package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +5 -6
  11. package/src/components/Fields/ReferenceField/ItemList/Item/style.tsx +16 -10
  12. package/src/components/Fields/ReferenceField/ManualPanel/Item/index.tsx +3 -4
  13. package/src/components/Fields/ReferenceField/ManualPanel/Item/style.tsx +7 -1
  14. package/src/components/Fields/VisualUniqueSelection/ScrollableSelection/index.tsx +3 -3
  15. package/src/components/Fields/VisualUniqueSelection/index.tsx +2 -4
  16. package/src/components/FloatingMenu/index.tsx +5 -5
  17. package/src/components/Loader/components/SmallCircle.js +29 -0
  18. package/src/components/Loader/index.tsx +3 -2
  19. package/src/components/MainWrapper/AppBar/atoms.tsx +4 -6
  20. package/src/components/MainWrapper/AppBar/index.tsx +14 -12
  21. package/src/components/MainWrapper/AppBar/style.tsx +23 -18
  22. package/src/components/MainWrapper/index.tsx +3 -3
  23. package/src/components/OcassionalToast/index.tsx +1 -1
  24. package/src/components/OcassionalToast/style.tsx +6 -0
  25. package/src/components/PageFinder/SelectionListItem/index.tsx +5 -4
  26. package/src/components/PageFinder/SelectionListItem/style.tsx +7 -1
  27. package/src/components/PageFinder/index.tsx +1 -0
  28. package/src/constants/index.ts +27 -0
  29. package/src/forms/elements.tsx +8 -24
  30. package/src/forms/index.tsx +0 -2
  31. package/src/helpers/containerEvaluations.tsx +5 -0
  32. package/src/helpers/content.ts +35 -0
  33. package/src/helpers/index.tsx +91 -89
  34. package/src/helpers/strings.tsx +19 -0
  35. package/src/helpers/types.ts +1 -0
  36. package/src/hooks/forms.tsx +2 -1
  37. package/src/locales/en-US.ts +29 -0
  38. package/src/locales/es-ES.ts +29 -0
  39. package/src/locales/index.ts +11 -0
  40. package/src/modules/Categories/CategoriesList/BulkHeader/index.tsx +5 -0
  41. package/src/modules/Categories/CategoriesList/index.tsx +10 -4
  42. package/src/modules/Content/BulkHeader/index.tsx +11 -0
  43. package/src/modules/Content/PageItem/index.tsx +1 -0
  44. package/src/modules/Content/atoms.tsx +1 -1
  45. package/src/modules/Content/index.tsx +27 -2
  46. package/src/modules/FileDrive/BulkGridHeader/index.tsx +6 -1
  47. package/src/modules/FileDrive/BulkListHeader/index.tsx +5 -0
  48. package/src/modules/FileDrive/index.tsx +10 -0
  49. package/src/modules/Forms/FormCategoriesList/BulkHeader/index.tsx +15 -2
  50. package/src/modules/Forms/FormCategoriesList/index.tsx +8 -0
  51. package/src/modules/Forms/FormEditor/index.tsx +10 -1
  52. package/src/modules/Forms/FormList/BulkHeader/index.tsx +5 -0
  53. package/src/modules/Forms/FormList/index.tsx +12 -3
  54. package/src/modules/Forms/FormUseModal/FormUseItem/index.tsx +1 -2
  55. package/src/modules/Forms/FormUseModal/index.tsx +3 -3
  56. package/src/modules/GlobalEditor/index.tsx +1 -0
  57. package/src/modules/MediaGallery/BulkGridHeader/index.tsx +6 -1
  58. package/src/modules/MediaGallery/BulkListHeader/index.tsx +15 -2
  59. package/src/modules/MediaGallery/index.tsx +47 -36
  60. package/src/modules/Navigation/Defaults/BulkHeader/index.tsx +5 -0
  61. package/src/modules/Navigation/Defaults/index.tsx +26 -23
  62. package/src/modules/PageEditor/Editor/index.tsx +6 -0
  63. package/src/modules/PageEditor/index.tsx +52 -0
  64. package/src/modules/Redirects/BulkHeader/index.tsx +6 -1
  65. package/src/modules/Redirects/index.tsx +7 -2
  66. package/src/modules/Settings/Integrations/BulkHeader/index.tsx +5 -0
  67. package/src/modules/Settings/Integrations/index.tsx +7 -1
  68. package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +5 -0
  69. package/src/modules/Sites/SitesList/index.tsx +7 -2
  70. package/src/modules/StructuredData/Form/index.tsx +1 -0
  71. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +5 -0
  72. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/atoms.tsx +3 -2
  73. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +17 -11
  74. package/src/modules/StructuredData/StructuredDataList/index.tsx +6 -0
  75. package/src/modules/Users/Roles/BulkHeader/index.tsx +5 -0
  76. package/src/modules/Users/Roles/index.tsx +6 -1
  77. package/src/modules/Users/UserList/BulkHeader/index.tsx +5 -0
  78. package/src/modules/Users/UserList/index.tsx +12 -7
  79. package/tsconfig.paths.json +4 -1
@@ -184,10 +184,15 @@ const Header = styled.section<{ inversed?: boolean }>`
184
184
  }
185
185
  `;
186
186
 
187
- const IconWrapper = styled.div<{ inversed?: boolean }>`
187
+ const IconWrapper = styled.div<{ inversed?: boolean; disabled?: boolean }>`
188
188
  svg {
189
189
  path {
190
- fill: ${(p) => (p.inversed ? p.theme.color.textHighEmphasisInverse : p.theme.color.interactive01)};
190
+ fill: ${({ disabled, theme, inversed }) =>
191
+ disabled
192
+ ? theme.color.interactiveDisabled
193
+ : inversed
194
+ ? theme.color.textHighEmphasisInverse
195
+ : theme.color.interactive01};
191
196
  }
192
197
  }
193
198
  `;
@@ -228,28 +233,28 @@ const ScheduledDate = styled.div<{ inversed?: boolean }>`
228
233
  `;
229
234
 
230
235
  export {
231
- ActionMenu,
232
- Header,
233
- WrapperTabs,
234
- Title,
235
- Subtitle,
236
- ActionText,
237
236
  ActionItem,
237
+ ActionMenu,
238
238
  ActionMenuTitle,
239
+ ActionText,
239
240
  ButtonWrapper,
240
- IconStatusWrapper,
241
- LanguageWrapper,
242
- LanguageTextWrapper,
241
+ ErrorWrapper,
243
242
  FlagWrapper,
244
- Separator,
243
+ Header,
244
+ HelpText,
245
+ IconStatusWrapper,
245
246
  IconWrapper,
246
- ErrorWrapper,
247
+ LanguageTextWrapper,
248
+ LanguageWrapper,
249
+ ModalContent,
250
+ ScheduledDate,
247
251
  SearchWrapper,
252
+ Separator,
253
+ StatusBtn,
254
+ Subtitle,
255
+ TabsContent,
256
+ Title,
248
257
  WrapperEnd,
258
+ WrapperTabs,
249
259
  WrapperTitle,
250
- TabsContent,
251
- StatusBtn,
252
- HelpText,
253
- ModalContent,
254
- ScheduledDate,
255
260
  };
@@ -1,7 +1,6 @@
1
- import React from "react";
2
- import { IErrorItem, ILanguage } from "@ax/types";
3
- import { useNetworkStatus } from "@ax/hooks";
4
1
  import { Notification } from "@ax/components";
2
+ import { useNetworkStatus } from "@ax/hooks";
3
+ import type { IErrorItem, ILanguage } from "@ax/types";
5
4
 
6
5
  import AppBar from "./AppBar";
7
6
 
@@ -63,6 +62,7 @@ export interface IWrapperProps {
63
62
  isDirty?: boolean;
64
63
  exportAction?(formats: (number | string)[]): void;
65
64
  scheduledPublication?: string | null;
65
+ isSaving?: boolean;
66
66
  }
67
67
 
68
68
  export default MainWrapper;
@@ -18,7 +18,7 @@ const OcassionalToast = (props: IOcassionalToastProps): JSX.Element => {
18
18
  };
19
19
 
20
20
  export interface IOcassionalToastProps {
21
- message: string;
21
+ message: string | React.ReactNode;
22
22
  icon?: string;
23
23
  }
24
24
 
@@ -18,6 +18,12 @@ const Wrapper = styled.div`
18
18
  const Text = styled.div`
19
19
  ${(p) => p.theme.textStyle.uiS};
20
20
  color: ${(p) => p.theme.color.textHighEmphasisInverse};
21
+
22
+ button {
23
+ ${(p) => p.theme.textStyle.uiM};
24
+ text-decoration: underline;
25
+ font-weight: 600;
26
+ }
21
27
  `;
22
28
 
23
29
  const IconWrapper = styled.div`
@@ -1,12 +1,11 @@
1
- import React from "react";
2
- import { getFormattedDateWithTimezone } from "@ax/helpers";
3
1
  import { CheckField } from "@ax/components";
4
- import { ICheck, IPage } from "@ax/types";
2
+ import { getFormattedDateWithTimezone } from "@ax/helpers";
3
+ import type { ICheck, IPage } from "@ax/types";
5
4
 
6
5
  import * as S from "./style";
7
6
 
8
7
  const SelectionListItem = (props: ISelectionListItemProps): JSX.Element => {
9
- const { option, title, type, date, onClick, pageID, isSelected, onChange, multiple } = props;
8
+ const { option, title, type, date, onClick, pageID, isSelected, onChange, multiple, slug } = props;
10
9
 
11
10
  const handleClick = () => (multiple ? onChange({ value: option, isChecked: !isSelected }) : onClick(option));
12
11
  const handleChange = (value: ICheck) => onChange({ value: option, isChecked: value.isChecked });
@@ -26,6 +25,7 @@ const SelectionListItem = (props: ISelectionListItemProps): JSX.Element => {
26
25
  <S.Date>{getFormattedDateWithTimezone(date, "d MMM Y")}</S.Date>
27
26
  </S.Header>
28
27
  <S.Title>{title}</S.Title>
28
+ <S.Slug>{slug}</S.Slug>
29
29
  </S.Content>
30
30
  </S.ListItem>
31
31
  );
@@ -36,6 +36,7 @@ interface ISelectionListItemProps {
36
36
  title: string;
37
37
  type: string;
38
38
  date: Date;
39
+ slug: string;
39
40
  onClick: (value: any) => void;
40
41
  pageID: number;
41
42
  isSelected: boolean;
@@ -29,6 +29,7 @@ const Type = styled.div`
29
29
  color: ${(p) => p.theme.colors.textLowEmphasis};
30
30
  `;
31
31
 
32
+ // biome-ignore lint/suspicious/noShadowRestrictedNames: conflicts with js Date
32
33
  const Date = styled.div`
33
34
  ${(p) => p.theme.textStyle.uiXS};
34
35
  color: ${(p) => p.theme.colors.textLowEmphasis};
@@ -43,4 +44,9 @@ const Content = styled.div`
43
44
  width: 100%;
44
45
  `;
45
46
 
46
- export { ListItem, Title, Header, Type, Date, CheckWrapper, Content };
47
+ const Slug = styled.span`
48
+ ${({ theme }) => theme.textStyle.uiXS};
49
+ color: ${({ theme }) => theme.colors.textMediumEmphasis};
50
+ `;
51
+
52
+ export { CheckWrapper, Content, Date, Header, ListItem, Slug, Title, Type };
@@ -190,6 +190,7 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
190
190
  isSelected={selectedPagesIds.includes(page.id)}
191
191
  onChange={handleChange}
192
192
  multiple={multiple}
193
+ slug={page.slug.replace(/^\//, "")}
193
194
  />
194
195
  ));
195
196
 
@@ -0,0 +1,27 @@
1
+ import type { ValueOf } from "@ax/helpers/types";
2
+ import { LOCALE } from "@ax/locales";
3
+
4
+ // TODO: localize strings...
5
+ const itemLabel = {
6
+ COTENT_TYPE: LOCALE.entityLabel.contentType,
7
+ SIMPLE_CONTENT_TYPE: LOCALE.entityLabel.simpleContentType,
8
+ PAGE_CONTENT_TYPE: LOCALE.entityLabel.pageContentType,
9
+ CATEGORY: LOCALE.entityLabel.category,
10
+ PAGE: LOCALE.entityLabel.page,
11
+ GLOBAL_PAGE: LOCALE.entityLabel.globalPage,
12
+ CONTENT: LOCALE.entityLabel.content,
13
+ ITEM: LOCALE.entityLabel.item,
14
+ REDIRECT: LOCALE.entityLabel.redirect,
15
+ ADDON: LOCALE.entityLabel.addon,
16
+ FILE: LOCALE.entityLabel.file,
17
+ IMAGE: LOCALE.entityLabel.image,
18
+ FORM: LOCALE.entityLabel.form,
19
+ SITE: LOCALE.entityLabel.site,
20
+ NAVIGATION: LOCALE.entityLabel.navigation,
21
+ USER: LOCALE.entityLabel.user,
22
+ ROL: LOCALE.entityLabel.rol,
23
+ } as const;
24
+
25
+ type ItemLabel = ValueOf<typeof itemLabel>;
26
+
27
+ export { itemLabel, type ItemLabel };
@@ -1,6 +1,6 @@
1
1
  import { getDefaultSchema, camelize, isSelectedEditorID, deepClone } from "@ax/helpers";
2
2
  import { findByEditorID } from "./editor";
3
- import { IComponent, IModule } from "@ax/types";
3
+ import type { IComponent, IModule } from "@ax/types";
4
4
 
5
5
  const updateElementCollection = (elementType: string, prevCollection: any[]) => {
6
6
  const newElement = getDefaultSchema(elementType);
@@ -24,8 +24,9 @@ const updateComponent = (component: any, schema: any) => {
24
24
  }
25
25
  };
26
26
 
27
- const updateCollection = (type: string, item: IModule, key: string) =>
28
- (item[key] = updateElementCollection(type, item[key]));
27
+ const updateCollection = (type: string, item: IModule, key: string) => {
28
+ item[key] = updateElementCollection(type, item[key]);
29
+ };
29
30
 
30
31
  const getUpdatedComponents = (
31
32
  sections: any[],
@@ -115,24 +116,6 @@ const deleteComponent = (elements: any, editorID: number) => {
115
116
  return elements;
116
117
  };
117
118
 
118
- function deleteModules(sections: any, editorID: number) {
119
- return [...sections].map((section: any) => {
120
- section.modules = section.modules.filter((module: any) => {
121
- if (module.elements) {
122
- module.elements.forEach((element: any) => {
123
- return element.componentModules
124
- ? (element.componentModules = deleteComponent(element.componentModules, editorID))
125
- : null;
126
- });
127
-
128
- module.elements = deleteComponent(module.elements, editorID);
129
- }
130
- return module.editorID !== editorID;
131
- });
132
- return section;
133
- });
134
- }
135
-
136
119
  const setKeyValue = (obj: any, key: string, val: any) => {
137
120
  const [parentKey, childKey] = key.split(".");
138
121
  if (childKey) {
@@ -151,7 +134,9 @@ const updateByEditorID = (content: any, editorID: number, contentKey: string | s
151
134
  if (Array.isArray(contentKey)) {
152
135
  const keys = contentKey;
153
136
  const values = Array.isArray(value) ? value : [value];
154
- keys.forEach((k, i) => setKeyValue(content, k, values[i]));
137
+ keys.forEach((k, i) => {
138
+ setKeyValue(content, k, values[i]);
139
+ });
155
140
  } else {
156
141
  setKeyValue(content, contentKey, value);
157
142
  }
@@ -186,7 +171,7 @@ const moveElement = (elementID: number[], arr: any[], newIndex: number, idKey =
186
171
  const moveModule = (params: IMoveElementParams) => {
187
172
  const { elementID, content, selectedContent, newIndex, page, key } = params;
188
173
  const isPage = ["Page", "GlobalPage"].includes(selectedContent.component);
189
- let newContent;
174
+ let newContent: any;
190
175
  if (isPage) {
191
176
  const newModules = moveElement(elementID, content[key], newIndex);
192
177
  const { template } = selectedContent;
@@ -252,7 +237,6 @@ export {
252
237
  getUpdatedComponents,
253
238
  getUpdatedSections,
254
239
  updateComponent,
255
- deleteModules,
256
240
  updateByEditorID,
257
241
  moveModule,
258
242
  moveElement,
@@ -18,7 +18,6 @@ import {
18
18
  getUpdatedComponents,
19
19
  getUpdatedSections,
20
20
  updateComponent,
21
- deleteModules,
22
21
  updateByEditorID,
23
22
  moveModule,
24
23
  moveElement,
@@ -50,7 +49,6 @@ export {
50
49
  getUpdatedComponents,
51
50
  updateComponent,
52
51
  getUpdatedSections,
53
- deleteModules,
54
52
  deleteComponent,
55
53
  replaceElements,
56
54
  updateByEditorID,
@@ -53,6 +53,11 @@ const areEqual = (prevProps: any, newProps: any): boolean => {
53
53
  return false;
54
54
  }
55
55
 
56
+ // Re-render si el id de la página cambia (ej: después de guardar)
57
+ if (prevProps.selectedContent.id !== newProps.selectedContent.id) {
58
+ return false;
59
+ }
60
+
56
61
  const {
57
62
  selectedContent: { type },
58
63
  } = prevProps;
@@ -0,0 +1,35 @@
1
+ import { type ItemLabel, itemLabel } from "@ax/constants";
2
+
3
+ /**
4
+ * Determines the content kind label based on the content type flags.
5
+ * @param isSimpleContentType - Whether the content is a simple content type
6
+ * @param isPageContentType - Whether the content is a page content type
7
+ * @param isStandardPage - Whether the content is a standard page
8
+ * @returns The corresponding content kind label
9
+ */
10
+ function getContentItemLabel({
11
+ isSimpleContentType,
12
+ isPageContentType,
13
+ isStandardPage,
14
+ }: {
15
+ isSimpleContentType: boolean;
16
+ isPageContentType: boolean;
17
+ isStandardPage: boolean;
18
+ }) {
19
+ let contentItem: ItemLabel | null = null;
20
+
21
+ if (isSimpleContentType) {
22
+ contentItem = itemLabel.SIMPLE_CONTENT_TYPE;
23
+ } else if (isPageContentType) {
24
+ contentItem = itemLabel.PAGE_CONTENT_TYPE;
25
+ } else if (isStandardPage) {
26
+ contentItem = itemLabel.PAGE;
27
+ } else {
28
+ // fallback
29
+ contentItem = itemLabel.ITEM;
30
+ }
31
+
32
+ return contentItem;
33
+ }
34
+
35
+ export { getContentItemLabel };
@@ -81,6 +81,7 @@ import {
81
81
  filterImageText,
82
82
  getFileExtension,
83
83
  getInitials,
84
+ getSlugFromUrl,
84
85
  isNumber,
85
86
  slugify,
86
87
  splitAndJoin,
@@ -109,113 +110,114 @@ import {
109
110
  import { getFormTemplateThumbnailProps, getThumbnailProps } from "./thumbnails";
110
111
 
111
112
  export {
112
- isComponentEmpty,
113
- setAsContainedComponent,
114
113
  areAllComponentsEmpty,
115
- isEmptyContainer,
116
- formatBytes,
117
- imageToBase64,
118
- getImageFromHtml,
119
- getImageFromIFrame,
120
- filterImageText,
114
+ areEqual,
115
+ areEqualDates,
116
+ areEquals,
117
+ arrayInsert,
121
118
  camelize,
122
- splitCamelCase,
123
- isEmptyObj,
119
+ capitalize,
120
+ compressImage,
121
+ copyTextToClipboard,
122
+ dateToString,
123
+ decodeEntities,
124
124
  deepClone,
125
- isSelectedEditorID,
126
- resetMultipleValues,
127
- getNullValue,
128
- removeEditorIds,
129
- trimObject,
130
- hasProps,
125
+ delay,
126
+ encodeData,
127
+ filterByCategory,
131
128
  filterDuplicatedValues,
132
- areEquals,
133
- removeMenuEditorIds,
134
- sortBy,
135
- getSchema,
129
+ filterImageText,
130
+ filterThemeDatapacks,
131
+ filterThemeModules,
132
+ filterThemeTemplates,
133
+ findObjectValue,
134
+ formatBytes,
135
+ getActivatedDataPacksIds,
136
+ getCurrentPageStructuredData,
137
+ getDataPackSchema,
138
+ getDateRange,
139
+ getDaysAgo,
140
+ getDeactivatedModules,
141
+ getDefaultFormTemplate,
142
+ getDefaultNavigationModules,
136
143
  getDefaultSchema,
137
- getTemplate,
138
144
  getDefaultTemplate,
145
+ getDefaultTheme,
139
146
  getDisplayName,
140
- getTemplateType,
141
- getTemplateDisplayName,
142
- getSchemaThumbnails,
143
- getTemplateThumbnails,
144
- getMenuItems,
145
- filterByCategory,
146
- getStructuredDataFromPage,
147
- getCurrentPageStructuredData,
148
- getThumbnailProps,
149
- getFormTemplateThumbnailProps,
150
- slugify,
151
147
  getFieldByPath,
152
- isReqOk,
153
- dateToString,
154
- stringToDate,
155
- isValidDate,
156
- isValidDateRange,
157
- getDateRange,
158
- areEqualDates,
159
- getStringifyDateRange,
160
- getHumanLastModifiedDate,
148
+ getFileExtension,
149
+ getFileIcon,
161
150
  getFormattedDateWithTimezone,
162
- getDaysAgo,
163
- getRange,
164
- getScheduleFormatDate,
165
- imageResizeCropAndCompress,
166
- compressImage,
167
- validateEmail,
168
- capitalize,
169
- isEmptyArray,
170
- handleRequest,
171
- getActivatedDataPacksIds,
172
- isModuleDisabled,
173
- getDeactivatedModules,
151
+ getFormTemplate,
152
+ getFormTemplateCategories,
153
+ getFormTemplates,
154
+ getFormTemplateThumbnailProps,
155
+ getFormTemplateThumbnails,
156
+ getGlobalPageTypes,
157
+ getHumanLastModifiedDate,
158
+ getImageFromHtml,
159
+ getImageFromIFrame,
174
160
  getInitials,
175
- getSchemaType,
161
+ getMaxColumns,
162
+ getMenuItems,
176
163
  getModuleCategories,
177
164
  getModuleStyles,
178
- trimText,
179
- decodeEntities,
165
+ getNavigationModules,
166
+ getNewBreadcrumb,
167
+ getNullValue,
168
+ getRange,
169
+ getScheduleFormatDate,
170
+ getSchema,
171
+ getSchemaFormCategories,
172
+ getSchemaThumbnails,
173
+ getSchemaType,
174
+ getSlugFromUrl,
175
+ getStringifyDateRange,
176
+ getStructuredDataFromPage,
180
177
  getStructuredDataTitle,
181
- isStructuredDataFromPage,
178
+ getTemplate,
179
+ getTemplateDisplayName,
180
+ getTemplateThumbnails,
181
+ getTemplateType,
182
+ getThemeElements,
183
+ getThumbnailProps,
184
+ handleRequest,
185
+ hasProps,
186
+ imageResizeCropAndCompress,
187
+ imageToBase64,
188
+ isComponentEmpty,
189
+ isDevelopment,
190
+ isEmptyArray,
191
+ isEmptyContainer,
192
+ isEmptyObj,
182
193
  isGlobalStructuredData,
183
- getGlobalPageTypes,
194
+ isModuleDisabled,
195
+ isMultipleNavigationModules,
184
196
  isNumber,
185
- getFileExtension,
197
+ isReqOk,
198
+ isSelectedEditorID,
199
+ isStructuredDataFromPage,
200
+ isTemplateExcludedFromTheme,
201
+ isValidDate,
202
+ isValidDateRange,
186
203
  moveArrayElement,
187
- isDevelopment,
188
- getDataPackSchema,
204
+ parseTheme,
205
+ protectFormKeys,
206
+ removeDuplicatesByProperty,
207
+ removeEditorIds,
208
+ removeMenuEditorIds,
209
+ resetMultipleValues,
210
+ setAsContainedComponent,
211
+ slugify,
212
+ sortBy,
189
213
  splitAndJoin,
190
214
  splitAndTrim,
191
- getDefaultTheme,
192
- getThemeElements,
193
- filterThemeModules,
194
- filterThemeTemplates,
195
- filterThemeDatapacks,
196
- isTemplateExcludedFromTheme,
197
- copyTextToClipboard,
198
- getNavigationModules,
199
- getDefaultNavigationModules,
200
- isMultipleNavigationModules,
201
- getFormTemplate,
202
- getDefaultFormTemplate,
203
- getFormTemplates,
204
- getFormTemplateThumbnails,
205
- getSchemaFormCategories,
206
- getFormTemplateCategories,
207
- areEqual,
208
- parseTheme,
215
+ splitCamelCase,
216
+ stringToDate,
209
217
  stripHtml,
210
- encodeData,
211
- getFileIcon,
212
- getNewBreadcrumb,
213
- updatePropertyById,
214
- arrayInsert,
215
- getMaxColumns,
218
+ trimObject,
219
+ trimText,
216
220
  updateColumns,
217
- findObjectValue,
218
- removeDuplicatesByProperty,
219
- delay,
220
- protectFormKeys,
221
+ updatePropertyById,
222
+ validateEmail,
221
223
  };
@@ -129,6 +129,24 @@ const stripHtml = (html: string | null) => {
129
129
  return tmp.textContent || tmp.innerText || "";
130
130
  };
131
131
 
132
+ /**
133
+ * Obtiene el último segmento (slug) de una URL,
134
+ * ignorando slashes finales o parámetros de búsqueda.
135
+ */
136
+ const getSlugFromUrl = (urlText?: string): string | undefined => {
137
+ if (!urlText) return "";
138
+
139
+ try {
140
+ const url = new URL(urlText);
141
+ // pathname devuelve algo como "/hisco-mk-i/en/slug-final/"
142
+ const segments = url.pathname.split("/").filter(Boolean);
143
+ return segments.pop();
144
+ } catch (error) {
145
+ console.error("URL no válida", error);
146
+ return undefined;
147
+ }
148
+ };
149
+
132
150
  export {
133
151
  filterImageText,
134
152
  splitCamelCase,
@@ -145,4 +163,5 @@ export {
145
163
  splitAndTrim,
146
164
  copyTextToClipboard,
147
165
  stripHtml,
166
+ getSlugFromUrl,
148
167
  };
@@ -0,0 +1 @@
1
+ export type ValueOf<T> = T[keyof T];
@@ -50,8 +50,9 @@ const usePrevious = (value: Record<string, unknown> | string, isSaved?: boolean)
50
50
  const isSavedData = getIsSavedData();
51
51
 
52
52
  useEffect(() => {
53
+ const currentValue = valueStr && JSON.parse(valueStr);
53
54
  if (!ref.current || isEmptyObj(ref.current)) {
54
- ref.current = valueStr && JSON.parse(valueStr);
55
+ ref.current = currentValue;
55
56
  }
56
57
  }, [valueStr]);
57
58
 
@@ -16,6 +16,16 @@ export const enUS = {
16
16
  noResults: "No results found",
17
17
  copyUrl: "Copy URL",
18
18
  filterByPageType: "Filter by page type",
19
+ publishing: "publishing",
20
+ unpublishing: "unpublishing",
21
+ deleting: "deleting",
22
+ processing: "processing",
23
+ pages: "pages",
24
+ pleaseWait: "please wait",
25
+ downloading: "downloading",
26
+ moving: "moving",
27
+ deactivating: "deactivating",
28
+ activating: "activating",
19
29
  },
20
30
  fields: {
21
31
  tags: {
@@ -45,4 +55,23 @@ export const enUS = {
45
55
  network: "Network error. Please check your connection.",
46
56
  unauthorized: "You are not authorized to perform this action.",
47
57
  },
58
+ entityLabel: {
59
+ contentType: { one: "content type", other: "content types" },
60
+ simpleContentType: { one: "simple content type", other: "simple content types" },
61
+ pageContentType: { one: "page content type", other: "page content types" },
62
+ category: { one: "category", other: "categories" },
63
+ page: { one: "page", other: "pages" },
64
+ globalPage: { one: "global page", other: "global pages" },
65
+ content: { one: "content", other: "contents" },
66
+ item: { one: "item", other: "items" },
67
+ form: { one: "form", other: "forms" },
68
+ image: { one: "image", other: "images" },
69
+ redirect: { one: "redirect", other: "redirects" },
70
+ addon: { one: "addon", other: "addons" },
71
+ file: { one: "file", other: "files" },
72
+ site: { one: "site", other: "sites" },
73
+ navigation: { one: "navigation", other: "navigations" },
74
+ user: { one: "user", other: "users" },
75
+ rol: { one: "rol", other: "roles" },
76
+ },
48
77
  } as const;
@@ -16,6 +16,16 @@ export const esES = {
16
16
  noResults: "No se encontraron resultados",
17
17
  copyUrl: "Copiar URL",
18
18
  filterByPageType: "Filtrar por tipo de página",
19
+ publishing: "publicando",
20
+ unpublishing: "despublicando",
21
+ deleting: "eliminando",
22
+ processing: "procesando",
23
+ pages: "páginas",
24
+ pleaseWait: "por favor, espere",
25
+ downloading: "descargando",
26
+ moving: "moviendo",
27
+ deactivating: "desactivando",
28
+ activating: "activando",
19
29
  },
20
30
  fields: {
21
31
  tags: {
@@ -45,4 +55,23 @@ export const esES = {
45
55
  network: "Error de red. Por favor, verifique su conexión.",
46
56
  unauthorized: "No está autorizado para realizar esta acción.",
47
57
  },
58
+ entityLabel: {
59
+ contentType: { one: "tipo de contenido", other: "tipo de contenidos" },
60
+ simpleContentType: { one: "tipo de contenido simple", other: "tipos de contenido simple" },
61
+ pageContentType: { one: "tipo de contenido de página", other: "tipos de contenido de página" },
62
+ category: { one: "categoría", other: "categorías" },
63
+ page: { one: "página", other: "páginas" },
64
+ globalPage: { one: "página global", other: "páginas globales" },
65
+ content: { one: "contenido", other: "contenidos" },
66
+ item: { one: "elemento", other: "elementos" },
67
+ form: { one: "formulario", other: "formularios" },
68
+ image: { one: "imagen", other: "imágenes" },
69
+ redirect: { one: "redirección", other: "redirecciones" },
70
+ addon: { one: "addon", other: "addons" },
71
+ file: { one: "archivo", other: "archivos" },
72
+ site: { one: "web", other: "webs" },
73
+ navigation: { one: "navegacion", other: "navegaciones" },
74
+ user: { one: "usuario", other: "usuarios" },
75
+ rol: { one: "rol", other: "roles" },
76
+ },
48
77
  } as const;