@strapi/content-manager 5.0.0-rc.17 → 5.0.0-rc.19

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 (69) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-CnL10QYC.mjs → ComponentConfigurationPage-DJ5voqEK.mjs} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-CnL10QYC.mjs.map → ComponentConfigurationPage-DJ5voqEK.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-G4EIirP8.js → ComponentConfigurationPage-_6osrv39.js} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-G4EIirP8.js.map → ComponentConfigurationPage-_6osrv39.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-I2kKh9dx.mjs → EditConfigurationPage-CZofxSLy.mjs} +3 -3
  6. package/dist/_chunks/{EditConfigurationPage-I2kKh9dx.mjs.map → EditConfigurationPage-CZofxSLy.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-B2AA1kVF.js → EditConfigurationPage-ZN3s568V.js} +3 -3
  8. package/dist/_chunks/{EditConfigurationPage-B2AA1kVF.js.map → EditConfigurationPage-ZN3s568V.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-CHgoNwlc.js → EditViewPage-Co2IKQZH.js} +3 -3
  10. package/dist/_chunks/{EditViewPage-CHgoNwlc.js.map → EditViewPage-Co2IKQZH.js.map} +1 -1
  11. package/dist/_chunks/{EditViewPage-zFjJK0s8.mjs → EditViewPage-HYljoEY7.mjs} +3 -3
  12. package/dist/_chunks/{EditViewPage-zFjJK0s8.mjs.map → EditViewPage-HYljoEY7.mjs.map} +1 -1
  13. package/dist/_chunks/{Field-DPAzUS1M.mjs → Field-BOPUMZ1u.mjs} +3 -3
  14. package/dist/_chunks/{Field-DPAzUS1M.mjs.map → Field-BOPUMZ1u.mjs.map} +1 -1
  15. package/dist/_chunks/{Field-9DePZh-0.js → Field-G9CkFUtP.js} +3 -3
  16. package/dist/_chunks/{Field-9DePZh-0.js.map → Field-G9CkFUtP.js.map} +1 -1
  17. package/dist/_chunks/{Form-CEkENbkF.mjs → Form-CDwNp7pU.mjs} +2 -2
  18. package/dist/_chunks/{Form-CEkENbkF.mjs.map → Form-CDwNp7pU.mjs.map} +1 -1
  19. package/dist/_chunks/{Form-DPm-KZ1A.js → Form-crsbkGxI.js} +2 -2
  20. package/dist/_chunks/{Form-DPm-KZ1A.js.map → Form-crsbkGxI.js.map} +1 -1
  21. package/dist/_chunks/{History-utls71em.mjs → History-BDZrgfZ3.mjs} +4 -4
  22. package/dist/_chunks/{History-utls71em.mjs.map → History-BDZrgfZ3.mjs.map} +1 -1
  23. package/dist/_chunks/{History-DXSbTWez.js → History-CWcM9HnW.js} +4 -4
  24. package/dist/_chunks/{History-DXSbTWez.js.map → History-CWcM9HnW.js.map} +1 -1
  25. package/dist/_chunks/{ListConfigurationPage-CuMXWWqb.mjs → ListConfigurationPage-BZ3ScUna.mjs} +2 -2
  26. package/dist/_chunks/{ListConfigurationPage-CuMXWWqb.mjs.map → ListConfigurationPage-BZ3ScUna.mjs.map} +1 -1
  27. package/dist/_chunks/{ListConfigurationPage-D5C7ACZ_.js → ListConfigurationPage-DGzoQD_I.js} +2 -2
  28. package/dist/_chunks/{ListConfigurationPage-D5C7ACZ_.js.map → ListConfigurationPage-DGzoQD_I.js.map} +1 -1
  29. package/dist/_chunks/{ListViewPage-DfuwH1tt.js → ListViewPage-BBAC9aPu.js} +3 -3
  30. package/dist/_chunks/{ListViewPage-DfuwH1tt.js.map → ListViewPage-BBAC9aPu.js.map} +1 -1
  31. package/dist/_chunks/{ListViewPage-CdKd-PS_.mjs → ListViewPage-CsX7tWx-.mjs} +3 -3
  32. package/dist/_chunks/{ListViewPage-CdKd-PS_.mjs.map → ListViewPage-CsX7tWx-.mjs.map} +1 -1
  33. package/dist/_chunks/{NoContentTypePage-BIxlkWWi.js → NoContentTypePage-CwVDx_YC.js} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-BIxlkWWi.js.map → NoContentTypePage-CwVDx_YC.js.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-DkToTT7u.mjs → NoContentTypePage-LClTUPWs.mjs} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-DkToTT7u.mjs.map → NoContentTypePage-LClTUPWs.mjs.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-Bu4GWYb-.js → NoPermissionsPage-D2iWw-sn.js} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-Bu4GWYb-.js.map → NoPermissionsPage-D2iWw-sn.js.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-DlWi4BAH.mjs → NoPermissionsPage-S4Re3FwO.mjs} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-DlWi4BAH.mjs.map → NoPermissionsPage-S4Re3FwO.mjs.map} +1 -1
  41. package/dist/_chunks/{Relations-QP5yn9_z.mjs → Relations-Dmv0Tpe5.mjs} +3 -3
  42. package/dist/_chunks/{Relations-QP5yn9_z.mjs.map → Relations-Dmv0Tpe5.mjs.map} +1 -1
  43. package/dist/_chunks/{Relations-CFjTESWQ.js → Relations-jwuTFGOV.js} +3 -3
  44. package/dist/_chunks/{Relations-CFjTESWQ.js.map → Relations-jwuTFGOV.js.map} +1 -1
  45. package/dist/_chunks/{en-BVzUkPxZ.js → en-BlhnxQfj.js} +2 -2
  46. package/dist/_chunks/{en-BVzUkPxZ.js.map → en-BlhnxQfj.js.map} +1 -1
  47. package/dist/_chunks/{en-CPTj6CjC.mjs → en-C8YBvRrK.mjs} +2 -2
  48. package/dist/_chunks/{en-CPTj6CjC.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
  49. package/dist/_chunks/{index-BHfS6_D5.mjs → index-BmUAydCA.mjs} +868 -816
  50. package/dist/_chunks/index-BmUAydCA.mjs.map +1 -0
  51. package/dist/_chunks/{index-DXiHxy70.js → index-CBX6KyXv.js} +866 -814
  52. package/dist/_chunks/index-CBX6KyXv.js.map +1 -0
  53. package/dist/_chunks/{layout-DX_52HSH.mjs → layout-ClP-DC72.mjs} +3 -3
  54. package/dist/_chunks/{layout-DX_52HSH.mjs.map → layout-ClP-DC72.mjs.map} +1 -1
  55. package/dist/_chunks/{layout-bE-WUnQ0.js → layout-CxxkX9jY.js} +3 -3
  56. package/dist/_chunks/{layout-bE-WUnQ0.js.map → layout-CxxkX9jY.js.map} +1 -1
  57. package/dist/_chunks/{relations-D706vblp.js → relations-DIjTADIu.js} +2 -2
  58. package/dist/_chunks/{relations-D706vblp.js.map → relations-DIjTADIu.js.map} +1 -1
  59. package/dist/_chunks/{relations-SCVAL_aJ.mjs → relations-op89RClB.mjs} +2 -2
  60. package/dist/_chunks/{relations-SCVAL_aJ.mjs.map → relations-op89RClB.mjs.map} +1 -1
  61. package/dist/admin/index.js +2 -1
  62. package/dist/admin/index.js.map +1 -1
  63. package/dist/admin/index.mjs +3 -2
  64. package/dist/admin/src/exports.d.ts +1 -1
  65. package/dist/admin/src/hooks/useDocument.d.ts +30 -1
  66. package/package.json +8 -8
  67. package/dist/_chunks/index-BHfS6_D5.mjs.map +0 -1
  68. package/dist/_chunks/index-DXiHxy70.js.map +0 -1
  69. package/strapi-server.js +0 -3
@@ -1,6 +1,6 @@
1
1
  import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
3
+ import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, useQueryParams, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
4
  import * as React from "react";
5
5
  import { lazy } from "react";
6
6
  import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
@@ -789,19 +789,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
789
789
  }, {});
790
790
  return componentsByKey;
791
791
  };
792
- const useDocument = (args, opts) => {
792
+ const HOOKS = {
793
+ /**
794
+ * Hook that allows to mutate the displayed headers of the list view table
795
+ * @constant
796
+ * @type {string}
797
+ */
798
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
799
+ /**
800
+ * Hook that allows to mutate the CM's collection types links pre-set filters
801
+ * @constant
802
+ * @type {string}
803
+ */
804
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
805
+ /**
806
+ * Hook that allows to mutate the CM's edit view layout
807
+ * @constant
808
+ * @type {string}
809
+ */
810
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
811
+ /**
812
+ * Hook that allows to mutate the CM's single types links pre-set filters
813
+ * @constant
814
+ * @type {string}
815
+ */
816
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
817
+ };
818
+ const contentTypesApi = contentManagerApi.injectEndpoints({
819
+ endpoints: (builder) => ({
820
+ getContentTypeConfiguration: builder.query({
821
+ query: (uid) => ({
822
+ url: `/content-manager/content-types/${uid}/configuration`,
823
+ method: "GET"
824
+ }),
825
+ transformResponse: (response) => response.data,
826
+ providesTags: (_result, _error, uid) => [
827
+ { type: "ContentTypesConfiguration", id: uid },
828
+ { type: "ContentTypeSettings", id: "LIST" }
829
+ ]
830
+ }),
831
+ getAllContentTypeSettings: builder.query({
832
+ query: () => "/content-manager/content-types-settings",
833
+ transformResponse: (response) => response.data,
834
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
835
+ }),
836
+ updateContentTypeConfiguration: builder.mutation({
837
+ query: ({ uid, ...body }) => ({
838
+ url: `/content-manager/content-types/${uid}/configuration`,
839
+ method: "PUT",
840
+ data: body
841
+ }),
842
+ transformResponse: (response) => response.data,
843
+ invalidatesTags: (_result, _error, { uid }) => [
844
+ { type: "ContentTypesConfiguration", id: uid },
845
+ { type: "ContentTypeSettings", id: "LIST" },
846
+ // Is this necessary?
847
+ { type: "InitialData" }
848
+ ]
849
+ })
850
+ })
851
+ });
852
+ const {
853
+ useGetContentTypeConfigurationQuery,
854
+ useGetAllContentTypeSettingsQuery,
855
+ useUpdateContentTypeConfigurationMutation
856
+ } = contentTypesApi;
857
+ const checkIfAttributeIsDisplayable = (attribute) => {
858
+ const { type } = attribute;
859
+ if (type === "relation") {
860
+ return !attribute.relation.toLowerCase().includes("morph");
861
+ }
862
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
863
+ };
864
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
865
+ if (!mainFieldName) {
866
+ return void 0;
867
+ }
868
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
869
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
870
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
871
+ );
872
+ return {
873
+ name: mainFieldName,
874
+ type: mainFieldType ?? "string"
875
+ };
876
+ };
877
+ const DEFAULT_SETTINGS = {
878
+ bulkable: false,
879
+ filterable: false,
880
+ searchable: false,
881
+ pagination: false,
882
+ defaultSortBy: "",
883
+ defaultSortOrder: "asc",
884
+ mainField: "id",
885
+ pageSize: 10
886
+ };
887
+ const useDocumentLayout = (model) => {
888
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
889
+ const [{ query }] = useQueryParams();
890
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
793
891
  const { toggleNotification } = useNotification();
794
892
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
893
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
795
894
  const {
796
- currentData: data,
797
- isLoading: isLoadingDocument,
798
- isFetching: isFetchingDocument,
799
- error
800
- } = useGetDocumentQuery(args, {
801
- ...opts,
802
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
803
- });
804
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
895
+ data,
896
+ isLoading: isLoadingConfigs,
897
+ error,
898
+ isFetching: isFetchingConfigs
899
+ } = useGetContentTypeConfigurationQuery(model);
900
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
805
901
  React.useEffect(() => {
806
902
  if (error) {
807
903
  toggleNotification({
@@ -809,396 +905,435 @@ const useDocument = (args, opts) => {
809
905
  message: formatAPIError(error)
810
906
  });
811
907
  }
812
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
813
- const validationSchema = React.useMemo(() => {
814
- if (!schema) {
815
- return null;
816
- }
817
- return createYupSchema(schema.attributes, components);
818
- }, [schema, components]);
819
- const validate = React.useCallback(
820
- (document) => {
821
- if (!validationSchema) {
822
- throw new Error(
823
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
824
- );
825
- }
826
- try {
827
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
828
- return null;
829
- } catch (error2) {
830
- if (error2 instanceof ValidationError) {
831
- return getYupValidationErrors(error2);
832
- }
833
- throw error2;
834
- }
908
+ }, [error, formatAPIError, toggleNotification]);
909
+ const editLayout = React.useMemo(
910
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
911
+ layout: [],
912
+ components: {},
913
+ metadatas: {},
914
+ options: {},
915
+ settings: DEFAULT_SETTINGS
835
916
  },
836
- [validationSchema]
917
+ [data, isLoading, schemas, schema, components]
918
+ );
919
+ const listLayout = React.useMemo(() => {
920
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
921
+ layout: [],
922
+ metadatas: {},
923
+ options: {},
924
+ settings: DEFAULT_SETTINGS
925
+ };
926
+ }, [data, isLoading, schemas, schema, components]);
927
+ const { layout: edit } = React.useMemo(
928
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
929
+ layout: editLayout,
930
+ query
931
+ }),
932
+ [editLayout, query, runHookWaterfall]
837
933
  );
838
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
839
934
  return {
840
- components,
841
- document: data?.data,
842
- meta: data?.meta,
935
+ error,
843
936
  isLoading,
844
- schema,
845
- validate
846
- };
847
- };
848
- const useDoc = () => {
849
- const { id, slug, collectionType, origin } = useParams();
850
- const [{ query }] = useQueryParams();
851
- const params = React.useMemo(() => buildValidParams(query), [query]);
852
- if (!collectionType) {
853
- throw new Error("Could not find collectionType in url params");
854
- }
855
- if (!slug) {
856
- throw new Error("Could not find model in url params");
857
- }
858
- return {
859
- collectionType,
860
- model: slug,
861
- id: origin || id === "create" ? void 0 : id,
862
- ...useDocument(
863
- { documentId: origin || id, model: slug, collectionType, params },
864
- {
865
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
866
- }
867
- )
937
+ edit,
938
+ list: listLayout
868
939
  };
869
940
  };
870
- const prefixPluginTranslations = (trad, pluginId) => {
871
- if (!pluginId) {
872
- throw new TypeError("pluginId can't be empty");
873
- }
874
- return Object.keys(trad).reduce((acc, current) => {
875
- acc[`${pluginId}.${current}`] = trad[current];
876
- return acc;
877
- }, {});
878
- };
879
- const getTranslation = (id) => `content-manager.${id}`;
880
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
881
- id: "notification.error",
882
- defaultMessage: "An error occurred, please try again"
941
+ const useDocLayout = () => {
942
+ const { model } = useDoc();
943
+ return useDocumentLayout(model);
883
944
  };
884
- const useDocumentActions = () => {
885
- const { toggleNotification } = useNotification();
886
- const { formatMessage } = useIntl();
887
- const { trackUsage } = useTracking();
888
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
- const navigate = useNavigate();
890
- const [deleteDocument] = useDeleteDocumentMutation();
891
- const _delete = React.useCallback(
892
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
893
- try {
894
- trackUsage("willDeleteEntry", trackerProperty);
895
- const res = await deleteDocument({
896
- collectionType,
897
- model,
898
- documentId,
899
- params
900
- });
901
- if ("error" in res) {
902
- toggleNotification({
903
- type: "danger",
904
- message: formatAPIError(res.error)
905
- });
906
- return { error: res.error };
907
- }
908
- toggleNotification({
909
- type: "success",
910
- message: formatMessage({
911
- id: getTranslation("success.record.delete"),
912
- defaultMessage: "Deleted document"
913
- })
914
- });
915
- trackUsage("didDeleteEntry", trackerProperty);
916
- return res.data;
917
- } catch (err) {
918
- toggleNotification({
919
- type: "danger",
920
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
921
- });
922
- trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
923
- throw err;
924
- }
925
- },
926
- [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
927
- );
928
- const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
929
- const deleteMany = React.useCallback(
930
- async ({ model, documentIds, params }) => {
931
- try {
932
- trackUsage("willBulkDeleteEntries");
933
- const res = await deleteManyDocuments({
934
- model,
935
- documentIds,
936
- params
937
- });
938
- if ("error" in res) {
939
- toggleNotification({
940
- type: "danger",
941
- message: formatAPIError(res.error)
942
- });
943
- return { error: res.error };
944
- }
945
- toggleNotification({
946
- type: "success",
947
- title: formatMessage({
948
- id: getTranslation("success.records.delete"),
949
- defaultMessage: "Successfully deleted."
950
- }),
951
- message: ""
952
- });
953
- trackUsage("didBulkDeleteEntries");
954
- return res.data;
955
- } catch (err) {
956
- toggleNotification({
957
- type: "danger",
958
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
959
- });
960
- trackUsage("didNotBulkDeleteEntries");
961
- throw err;
945
+ const formatEditLayout = (data, {
946
+ schemas,
947
+ schema,
948
+ components
949
+ }) => {
950
+ let currentPanelIndex = 0;
951
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
952
+ data.contentType.layouts.edit,
953
+ schema?.attributes,
954
+ data.contentType.metadatas,
955
+ { configurations: data.components, schemas: components },
956
+ schemas
957
+ ).reduce((panels, row) => {
958
+ if (row.some((field) => field.type === "dynamiczone")) {
959
+ panels.push([row]);
960
+ currentPanelIndex += 2;
961
+ } else {
962
+ if (!panels[currentPanelIndex]) {
963
+ panels.push([]);
962
964
  }
963
- },
964
- [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
965
- );
966
- const [discardDocument] = useDiscardDocumentMutation();
967
- const discard = React.useCallback(
968
- async ({ collectionType, model, documentId, params }) => {
969
- try {
970
- const res = await discardDocument({
971
- collectionType,
972
- model,
973
- documentId,
974
- params
975
- });
976
- if ("error" in res) {
977
- toggleNotification({
978
- type: "danger",
979
- message: formatAPIError(res.error)
980
- });
981
- return { error: res.error };
965
+ panels[currentPanelIndex].push(row);
966
+ }
967
+ return panels;
968
+ }, []);
969
+ const componentEditAttributes = Object.entries(data.components).reduce(
970
+ (acc, [uid, configuration]) => {
971
+ acc[uid] = {
972
+ layout: convertEditLayoutToFieldLayouts(
973
+ configuration.layouts.edit,
974
+ components[uid].attributes,
975
+ configuration.metadatas,
976
+ { configurations: data.components, schemas: components }
977
+ ),
978
+ settings: {
979
+ ...configuration.settings,
980
+ icon: components[uid].info.icon,
981
+ displayName: components[uid].info.displayName
982
982
  }
983
- toggleNotification({
984
- type: "success",
985
- message: formatMessage({
986
- id: "content-manager.success.record.discard",
987
- defaultMessage: "Changes discarded"
988
- })
989
- });
990
- return res.data;
991
- } catch (err) {
992
- toggleNotification({
993
- type: "danger",
994
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
995
- });
996
- throw err;
997
- }
983
+ };
984
+ return acc;
998
985
  },
999
- [discardDocument, formatAPIError, formatMessage, toggleNotification]
986
+ {}
1000
987
  );
1001
- const [publishDocument] = usePublishDocumentMutation();
1002
- const publish = React.useCallback(
1003
- async ({ collectionType, model, documentId, params }, data) => {
1004
- try {
1005
- trackUsage("willPublishEntry");
1006
- const res = await publishDocument({
1007
- collectionType,
1008
- model,
1009
- documentId,
1010
- data,
1011
- params
1012
- });
1013
- if ("error" in res) {
1014
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1015
- return { error: res.error };
1016
- }
1017
- trackUsage("didPublishEntry");
1018
- toggleNotification({
1019
- type: "success",
1020
- message: formatMessage({
1021
- id: getTranslation("success.record.publish"),
1022
- defaultMessage: "Published document"
1023
- })
1024
- });
1025
- return res.data;
1026
- } catch (err) {
1027
- toggleNotification({
1028
- type: "danger",
1029
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1030
- });
1031
- throw err;
1032
- }
988
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
989
+ (acc, [attribute, metadata]) => {
990
+ return {
991
+ ...acc,
992
+ [attribute]: metadata.edit
993
+ };
1033
994
  },
1034
- [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
995
+ {}
1035
996
  );
1036
- const [publishManyDocuments] = usePublishManyDocumentsMutation();
1037
- const publishMany = React.useCallback(
1038
- async ({ model, documentIds, params }) => {
1039
- try {
1040
- const res = await publishManyDocuments({
1041
- model,
1042
- documentIds,
1043
- params
1044
- });
1045
- if ("error" in res) {
1046
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1047
- return { error: res.error };
1048
- }
1049
- toggleNotification({
1050
- type: "success",
1051
- message: formatMessage({
1052
- id: getTranslation("success.record.publish"),
1053
- defaultMessage: "Published document"
1054
- })
1055
- });
1056
- return res.data;
1057
- } catch (err) {
1058
- toggleNotification({
1059
- type: "danger",
1060
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1061
- });
1062
- throw err;
997
+ return {
998
+ layout: panelledEditAttributes,
999
+ components: componentEditAttributes,
1000
+ metadatas: editMetadatas,
1001
+ settings: {
1002
+ ...data.contentType.settings,
1003
+ displayName: schema?.info.displayName
1004
+ },
1005
+ options: {
1006
+ ...schema?.options,
1007
+ ...schema?.pluginOptions,
1008
+ ...data.contentType.options
1009
+ }
1010
+ };
1011
+ };
1012
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1013
+ return rows.map(
1014
+ (row) => row.map((field) => {
1015
+ const attribute = attributes[field.name];
1016
+ if (!attribute) {
1017
+ return null;
1063
1018
  }
1019
+ const { edit: metadata } = metadatas[field.name];
1020
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1021
+ return {
1022
+ attribute,
1023
+ disabled: !metadata.editable,
1024
+ hint: metadata.description,
1025
+ label: metadata.label ?? "",
1026
+ name: field.name,
1027
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1028
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1029
+ schemas,
1030
+ components: components?.schemas ?? {}
1031
+ }),
1032
+ placeholder: metadata.placeholder ?? "",
1033
+ required: attribute.required ?? false,
1034
+ size: field.size,
1035
+ unique: "unique" in attribute ? attribute.unique : false,
1036
+ visible: metadata.visible ?? true,
1037
+ type: attribute.type
1038
+ };
1039
+ }).filter((field) => field !== null)
1040
+ );
1041
+ };
1042
+ const formatListLayout = (data, {
1043
+ schemas,
1044
+ schema,
1045
+ components
1046
+ }) => {
1047
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1048
+ (acc, [attribute, metadata]) => {
1049
+ return {
1050
+ ...acc,
1051
+ [attribute]: metadata.list
1052
+ };
1064
1053
  },
1065
- [
1066
- // trackUsage,
1067
- publishManyDocuments,
1068
- toggleNotification,
1069
- formatMessage,
1070
- formatAPIError
1071
- ]
1054
+ {}
1072
1055
  );
1073
- const [updateDocument] = useUpdateDocumentMutation();
1074
- const update = React.useCallback(
1075
- async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1076
- try {
1077
- trackUsage("willEditEntry", trackerProperty);
1078
- const res = await updateDocument({
1079
- collectionType,
1080
- model,
1081
- documentId,
1082
- data,
1083
- params
1084
- });
1085
- if ("error" in res) {
1086
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1087
- trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1088
- return { error: res.error };
1089
- }
1090
- trackUsage("didEditEntry", trackerProperty);
1091
- toggleNotification({
1092
- type: "success",
1093
- message: formatMessage({
1094
- id: getTranslation("success.record.save"),
1095
- defaultMessage: "Saved document"
1096
- })
1097
- });
1098
- return res.data;
1099
- } catch (err) {
1100
- trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1101
- toggleNotification({
1102
- type: "danger",
1103
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1104
- });
1105
- throw err;
1056
+ const listAttributes = convertListLayoutToFieldLayouts(
1057
+ data.contentType.layouts.list,
1058
+ schema?.attributes,
1059
+ listMetadatas,
1060
+ { configurations: data.components, schemas: components },
1061
+ schemas
1062
+ );
1063
+ return {
1064
+ layout: listAttributes,
1065
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1066
+ metadatas: listMetadatas,
1067
+ options: {
1068
+ ...schema?.options,
1069
+ ...schema?.pluginOptions,
1070
+ ...data.contentType.options
1071
+ }
1072
+ };
1073
+ };
1074
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1075
+ return columns.map((name) => {
1076
+ const attribute = attributes[name];
1077
+ if (!attribute) {
1078
+ return null;
1079
+ }
1080
+ const metadata = metadatas[name];
1081
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1082
+ return {
1083
+ attribute,
1084
+ label: metadata.label ?? "",
1085
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1086
+ schemas,
1087
+ components: components?.schemas ?? {}
1088
+ }),
1089
+ name,
1090
+ searchable: metadata.searchable ?? true,
1091
+ sortable: metadata.sortable ?? true
1092
+ };
1093
+ }).filter((field) => field !== null);
1094
+ };
1095
+ const useDocument = (args, opts) => {
1096
+ const { toggleNotification } = useNotification();
1097
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1098
+ const {
1099
+ currentData: data,
1100
+ isLoading: isLoadingDocument,
1101
+ isFetching: isFetchingDocument,
1102
+ error
1103
+ } = useGetDocumentQuery(args, {
1104
+ ...opts,
1105
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1106
+ });
1107
+ const {
1108
+ components,
1109
+ schema,
1110
+ schemas,
1111
+ isLoading: isLoadingSchema
1112
+ } = useContentTypeSchema(args.model);
1113
+ React.useEffect(() => {
1114
+ if (error) {
1115
+ toggleNotification({
1116
+ type: "danger",
1117
+ message: formatAPIError(error)
1118
+ });
1119
+ }
1120
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1121
+ const validationSchema = React.useMemo(() => {
1122
+ if (!schema) {
1123
+ return null;
1124
+ }
1125
+ return createYupSchema(schema.attributes, components);
1126
+ }, [schema, components]);
1127
+ const validate = React.useCallback(
1128
+ (document) => {
1129
+ if (!validationSchema) {
1130
+ throw new Error(
1131
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1132
+ );
1133
+ }
1134
+ try {
1135
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1136
+ return null;
1137
+ } catch (error2) {
1138
+ if (error2 instanceof ValidationError) {
1139
+ return getYupValidationErrors(error2);
1140
+ }
1141
+ throw error2;
1106
1142
  }
1107
1143
  },
1108
- [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1144
+ [validationSchema]
1109
1145
  );
1110
- const [unpublishDocument] = useUnpublishDocumentMutation();
1111
- const unpublish = React.useCallback(
1112
- async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1146
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1147
+ return {
1148
+ components,
1149
+ document: data?.data,
1150
+ meta: data?.meta,
1151
+ isLoading,
1152
+ schema,
1153
+ schemas,
1154
+ validate
1155
+ };
1156
+ };
1157
+ const useDoc = () => {
1158
+ const { id, slug, collectionType, origin } = useParams();
1159
+ const [{ query }] = useQueryParams();
1160
+ const params = React.useMemo(() => buildValidParams(query), [query]);
1161
+ if (!collectionType) {
1162
+ throw new Error("Could not find collectionType in url params");
1163
+ }
1164
+ if (!slug) {
1165
+ throw new Error("Could not find model in url params");
1166
+ }
1167
+ return {
1168
+ collectionType,
1169
+ model: slug,
1170
+ id: origin || id === "create" ? void 0 : id,
1171
+ ...useDocument(
1172
+ { documentId: origin || id, model: slug, collectionType, params },
1173
+ {
1174
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1175
+ }
1176
+ )
1177
+ };
1178
+ };
1179
+ const useContentManagerContext = () => {
1180
+ const {
1181
+ collectionType,
1182
+ model,
1183
+ id,
1184
+ components,
1185
+ isLoading: isLoadingDoc,
1186
+ schema,
1187
+ schemas
1188
+ } = useDoc();
1189
+ const layout = useDocumentLayout(model);
1190
+ const form = useForm("useContentManagerContext", (state) => state);
1191
+ const isSingleType = collectionType === SINGLE_TYPES;
1192
+ const slug = model;
1193
+ const isCreatingEntry = id === "create";
1194
+ useContentTypeSchema();
1195
+ const isLoading = isLoadingDoc || layout.isLoading;
1196
+ const error = layout.error;
1197
+ return {
1198
+ error,
1199
+ isLoading,
1200
+ // Base metadata
1201
+ model,
1202
+ collectionType,
1203
+ id,
1204
+ slug,
1205
+ isCreatingEntry,
1206
+ isSingleType,
1207
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1208
+ // All schema infos
1209
+ components,
1210
+ contentType: schema,
1211
+ contentTypes: schemas,
1212
+ // Form state
1213
+ form,
1214
+ // layout infos
1215
+ layout
1216
+ };
1217
+ };
1218
+ const prefixPluginTranslations = (trad, pluginId) => {
1219
+ if (!pluginId) {
1220
+ throw new TypeError("pluginId can't be empty");
1221
+ }
1222
+ return Object.keys(trad).reduce((acc, current) => {
1223
+ acc[`${pluginId}.${current}`] = trad[current];
1224
+ return acc;
1225
+ }, {});
1226
+ };
1227
+ const getTranslation = (id) => `content-manager.${id}`;
1228
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1229
+ id: "notification.error",
1230
+ defaultMessage: "An error occurred, please try again"
1231
+ };
1232
+ const useDocumentActions = () => {
1233
+ const { toggleNotification } = useNotification();
1234
+ const { formatMessage } = useIntl();
1235
+ const { trackUsage } = useTracking();
1236
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1237
+ const navigate = useNavigate();
1238
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1239
+ const [deleteDocument] = useDeleteDocumentMutation();
1240
+ const _delete = React.useCallback(
1241
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1113
1242
  try {
1114
- trackUsage("willUnpublishEntry");
1115
- const res = await unpublishDocument({
1243
+ trackUsage("willDeleteEntry", trackerProperty);
1244
+ const res = await deleteDocument({
1116
1245
  collectionType,
1117
1246
  model,
1118
1247
  documentId,
1119
- params,
1120
- data: {
1121
- discardDraft
1122
- }
1248
+ params
1123
1249
  });
1124
1250
  if ("error" in res) {
1125
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1251
+ toggleNotification({
1252
+ type: "danger",
1253
+ message: formatAPIError(res.error)
1254
+ });
1126
1255
  return { error: res.error };
1127
1256
  }
1128
- trackUsage("didUnpublishEntry");
1129
1257
  toggleNotification({
1130
1258
  type: "success",
1131
1259
  message: formatMessage({
1132
- id: getTranslation("success.record.unpublish"),
1133
- defaultMessage: "Unpublished document"
1260
+ id: getTranslation("success.record.delete"),
1261
+ defaultMessage: "Deleted document"
1134
1262
  })
1135
1263
  });
1264
+ trackUsage("didDeleteEntry", trackerProperty);
1136
1265
  return res.data;
1137
1266
  } catch (err) {
1138
1267
  toggleNotification({
1139
1268
  type: "danger",
1140
1269
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1141
1270
  });
1271
+ trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
1142
1272
  throw err;
1143
1273
  }
1144
1274
  },
1145
- [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1275
+ [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
1146
1276
  );
1147
- const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1148
- const unpublishMany = React.useCallback(
1277
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
1278
+ const deleteMany = React.useCallback(
1149
1279
  async ({ model, documentIds, params }) => {
1150
1280
  try {
1151
- trackUsage("willBulkUnpublishEntries");
1152
- const res = await unpublishManyDocuments({
1281
+ trackUsage("willBulkDeleteEntries");
1282
+ const res = await deleteManyDocuments({
1153
1283
  model,
1154
1284
  documentIds,
1155
1285
  params
1156
1286
  });
1157
1287
  if ("error" in res) {
1158
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1288
+ toggleNotification({
1289
+ type: "danger",
1290
+ message: formatAPIError(res.error)
1291
+ });
1159
1292
  return { error: res.error };
1160
1293
  }
1161
- trackUsage("didBulkUnpublishEntries");
1162
1294
  toggleNotification({
1163
1295
  type: "success",
1164
1296
  title: formatMessage({
1165
- id: getTranslation("success.records.unpublish"),
1166
- defaultMessage: "Successfully unpublished."
1297
+ id: getTranslation("success.records.delete"),
1298
+ defaultMessage: "Successfully deleted."
1167
1299
  }),
1168
1300
  message: ""
1169
1301
  });
1302
+ trackUsage("didBulkDeleteEntries");
1170
1303
  return res.data;
1171
1304
  } catch (err) {
1172
1305
  toggleNotification({
1173
1306
  type: "danger",
1174
1307
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1175
1308
  });
1176
- trackUsage("didNotBulkUnpublishEntries");
1309
+ trackUsage("didNotBulkDeleteEntries");
1177
1310
  throw err;
1178
1311
  }
1179
1312
  },
1180
- [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1313
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1181
1314
  );
1182
- const [createDocument] = useCreateDocumentMutation();
1183
- const create = React.useCallback(
1184
- async ({ model, params }, data, trackerProperty) => {
1315
+ const [discardDocument] = useDiscardDocumentMutation();
1316
+ const discard = React.useCallback(
1317
+ async ({ collectionType, model, documentId, params }) => {
1185
1318
  try {
1186
- const res = await createDocument({
1319
+ const res = await discardDocument({
1320
+ collectionType,
1187
1321
  model,
1188
- data,
1322
+ documentId,
1189
1323
  params
1190
1324
  });
1191
1325
  if ("error" in res) {
1192
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1193
- trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1326
+ toggleNotification({
1327
+ type: "danger",
1328
+ message: formatAPIError(res.error)
1329
+ });
1194
1330
  return { error: res.error };
1195
1331
  }
1196
- trackUsage("didCreateEntry", trackerProperty);
1197
1332
  toggleNotification({
1198
1333
  type: "success",
1199
1334
  message: formatMessage({
1200
- id: getTranslation("success.record.save"),
1201
- defaultMessage: "Saved document"
1335
+ id: "content-manager.success.record.discard",
1336
+ defaultMessage: "Changes discarded"
1202
1337
  })
1203
1338
  });
1204
1339
  return res.data;
@@ -1207,19 +1342,234 @@ const useDocumentActions = () => {
1207
1342
  type: "danger",
1208
1343
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1209
1344
  });
1210
- trackUsage("didNotCreateEntry", { error: err, ...trackerProperty });
1211
1345
  throw err;
1212
1346
  }
1213
1347
  },
1214
- [createDocument, formatAPIError, formatMessage, toggleNotification, trackUsage]
1348
+ [discardDocument, formatAPIError, formatMessage, toggleNotification]
1215
1349
  );
1216
- const [autoCloneDocument] = useAutoCloneDocumentMutation();
1217
- const autoClone = React.useCallback(
1218
- async ({ model, sourceId }) => {
1350
+ const [publishDocument] = usePublishDocumentMutation();
1351
+ const publish = React.useCallback(
1352
+ async ({ collectionType, model, documentId, params }, data) => {
1219
1353
  try {
1220
- const res = await autoCloneDocument({
1354
+ trackUsage("willPublishEntry");
1355
+ const res = await publishDocument({
1356
+ collectionType,
1221
1357
  model,
1222
- sourceId
1358
+ documentId,
1359
+ data,
1360
+ params
1361
+ });
1362
+ if ("error" in res) {
1363
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1364
+ return { error: res.error };
1365
+ }
1366
+ trackUsage("didPublishEntry");
1367
+ toggleNotification({
1368
+ type: "success",
1369
+ message: formatMessage({
1370
+ id: getTranslation("success.record.publish"),
1371
+ defaultMessage: "Published document"
1372
+ })
1373
+ });
1374
+ return res.data;
1375
+ } catch (err) {
1376
+ toggleNotification({
1377
+ type: "danger",
1378
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1379
+ });
1380
+ throw err;
1381
+ }
1382
+ },
1383
+ [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1384
+ );
1385
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1386
+ const publishMany = React.useCallback(
1387
+ async ({ model, documentIds, params }) => {
1388
+ try {
1389
+ const res = await publishManyDocuments({
1390
+ model,
1391
+ documentIds,
1392
+ params
1393
+ });
1394
+ if ("error" in res) {
1395
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1396
+ return { error: res.error };
1397
+ }
1398
+ toggleNotification({
1399
+ type: "success",
1400
+ message: formatMessage({
1401
+ id: getTranslation("success.record.publish"),
1402
+ defaultMessage: "Published document"
1403
+ })
1404
+ });
1405
+ return res.data;
1406
+ } catch (err) {
1407
+ toggleNotification({
1408
+ type: "danger",
1409
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1410
+ });
1411
+ throw err;
1412
+ }
1413
+ },
1414
+ [
1415
+ // trackUsage,
1416
+ publishManyDocuments,
1417
+ toggleNotification,
1418
+ formatMessage,
1419
+ formatAPIError
1420
+ ]
1421
+ );
1422
+ const [updateDocument] = useUpdateDocumentMutation();
1423
+ const update = React.useCallback(
1424
+ async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1425
+ try {
1426
+ trackUsage("willEditEntry", trackerProperty);
1427
+ const res = await updateDocument({
1428
+ collectionType,
1429
+ model,
1430
+ documentId,
1431
+ data,
1432
+ params
1433
+ });
1434
+ if ("error" in res) {
1435
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1436
+ trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1437
+ return { error: res.error };
1438
+ }
1439
+ trackUsage("didEditEntry", trackerProperty);
1440
+ toggleNotification({
1441
+ type: "success",
1442
+ message: formatMessage({
1443
+ id: getTranslation("success.record.save"),
1444
+ defaultMessage: "Saved document"
1445
+ })
1446
+ });
1447
+ return res.data;
1448
+ } catch (err) {
1449
+ trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1450
+ toggleNotification({
1451
+ type: "danger",
1452
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1453
+ });
1454
+ throw err;
1455
+ }
1456
+ },
1457
+ [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1458
+ );
1459
+ const [unpublishDocument] = useUnpublishDocumentMutation();
1460
+ const unpublish = React.useCallback(
1461
+ async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1462
+ try {
1463
+ trackUsage("willUnpublishEntry");
1464
+ const res = await unpublishDocument({
1465
+ collectionType,
1466
+ model,
1467
+ documentId,
1468
+ params,
1469
+ data: {
1470
+ discardDraft
1471
+ }
1472
+ });
1473
+ if ("error" in res) {
1474
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1475
+ return { error: res.error };
1476
+ }
1477
+ trackUsage("didUnpublishEntry");
1478
+ toggleNotification({
1479
+ type: "success",
1480
+ message: formatMessage({
1481
+ id: getTranslation("success.record.unpublish"),
1482
+ defaultMessage: "Unpublished document"
1483
+ })
1484
+ });
1485
+ return res.data;
1486
+ } catch (err) {
1487
+ toggleNotification({
1488
+ type: "danger",
1489
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1490
+ });
1491
+ throw err;
1492
+ }
1493
+ },
1494
+ [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1495
+ );
1496
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1497
+ const unpublishMany = React.useCallback(
1498
+ async ({ model, documentIds, params }) => {
1499
+ try {
1500
+ trackUsage("willBulkUnpublishEntries");
1501
+ const res = await unpublishManyDocuments({
1502
+ model,
1503
+ documentIds,
1504
+ params
1505
+ });
1506
+ if ("error" in res) {
1507
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1508
+ return { error: res.error };
1509
+ }
1510
+ trackUsage("didBulkUnpublishEntries");
1511
+ toggleNotification({
1512
+ type: "success",
1513
+ title: formatMessage({
1514
+ id: getTranslation("success.records.unpublish"),
1515
+ defaultMessage: "Successfully unpublished."
1516
+ }),
1517
+ message: ""
1518
+ });
1519
+ return res.data;
1520
+ } catch (err) {
1521
+ toggleNotification({
1522
+ type: "danger",
1523
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1524
+ });
1525
+ trackUsage("didNotBulkUnpublishEntries");
1526
+ throw err;
1527
+ }
1528
+ },
1529
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1530
+ );
1531
+ const [createDocument] = useCreateDocumentMutation();
1532
+ const create = React.useCallback(
1533
+ async ({ model, params }, data, trackerProperty) => {
1534
+ try {
1535
+ const res = await createDocument({
1536
+ model,
1537
+ data,
1538
+ params
1539
+ });
1540
+ if ("error" in res) {
1541
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1542
+ trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1543
+ return { error: res.error };
1544
+ }
1545
+ trackUsage("didCreateEntry", trackerProperty);
1546
+ toggleNotification({
1547
+ type: "success",
1548
+ message: formatMessage({
1549
+ id: getTranslation("success.record.save"),
1550
+ defaultMessage: "Saved document"
1551
+ })
1552
+ });
1553
+ setCurrentStep("contentManager.success");
1554
+ return res.data;
1555
+ } catch (err) {
1556
+ toggleNotification({
1557
+ type: "danger",
1558
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1559
+ });
1560
+ trackUsage("didNotCreateEntry", { error: err, ...trackerProperty });
1561
+ throw err;
1562
+ }
1563
+ },
1564
+ [createDocument, formatAPIError, formatMessage, toggleNotification, trackUsage]
1565
+ );
1566
+ const [autoCloneDocument] = useAutoCloneDocumentMutation();
1567
+ const autoClone = React.useCallback(
1568
+ async ({ model, sourceId }) => {
1569
+ try {
1570
+ const res = await autoCloneDocument({
1571
+ model,
1572
+ sourceId
1223
1573
  });
1224
1574
  if ("error" in res) {
1225
1575
  return { error: res.error };
@@ -1303,7 +1653,7 @@ const useDocumentActions = () => {
1303
1653
  };
1304
1654
  };
1305
1655
  const ProtectedHistoryPage = lazy(
1306
- () => import("./History-utls71em.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1656
+ () => import("./History-BDZrgfZ3.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1307
1657
  );
1308
1658
  const routes$1 = [
1309
1659
  {
@@ -1316,31 +1666,31 @@ const routes$1 = [
1316
1666
  }
1317
1667
  ];
1318
1668
  const ProtectedEditViewPage = lazy(
1319
- () => import("./EditViewPage-zFjJK0s8.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1669
+ () => import("./EditViewPage-HYljoEY7.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1320
1670
  );
1321
1671
  const ProtectedListViewPage = lazy(
1322
- () => import("./ListViewPage-CdKd-PS_.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1672
+ () => import("./ListViewPage-CsX7tWx-.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1323
1673
  );
1324
1674
  const ProtectedListConfiguration = lazy(
1325
- () => import("./ListConfigurationPage-CuMXWWqb.mjs").then((mod) => ({
1675
+ () => import("./ListConfigurationPage-BZ3ScUna.mjs").then((mod) => ({
1326
1676
  default: mod.ProtectedListConfiguration
1327
1677
  }))
1328
1678
  );
1329
1679
  const ProtectedEditConfigurationPage = lazy(
1330
- () => import("./EditConfigurationPage-I2kKh9dx.mjs").then((mod) => ({
1680
+ () => import("./EditConfigurationPage-CZofxSLy.mjs").then((mod) => ({
1331
1681
  default: mod.ProtectedEditConfigurationPage
1332
1682
  }))
1333
1683
  );
1334
1684
  const ProtectedComponentConfigurationPage = lazy(
1335
- () => import("./ComponentConfigurationPage-CnL10QYC.mjs").then((mod) => ({
1685
+ () => import("./ComponentConfigurationPage-DJ5voqEK.mjs").then((mod) => ({
1336
1686
  default: mod.ProtectedComponentConfigurationPage
1337
1687
  }))
1338
1688
  );
1339
1689
  const NoPermissions = lazy(
1340
- () => import("./NoPermissionsPage-DlWi4BAH.mjs").then((mod) => ({ default: mod.NoPermissions }))
1690
+ () => import("./NoPermissionsPage-S4Re3FwO.mjs").then((mod) => ({ default: mod.NoPermissions }))
1341
1691
  );
1342
1692
  const NoContentType = lazy(
1343
- () => import("./NoContentTypePage-DkToTT7u.mjs").then((mod) => ({ default: mod.NoContentType }))
1693
+ () => import("./NoContentTypePage-LClTUPWs.mjs").then((mod) => ({ default: mod.NoContentType }))
1344
1694
  );
1345
1695
  const CollectionTypePages = () => {
1346
1696
  const { collectionType } = useParams();
@@ -2465,490 +2815,191 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2465
2815
  position: "header"
2466
2816
  };
2467
2817
  };
2468
- ConfigureTheViewAction.type = "configure-the-view";
2469
- const EditTheModelAction = ({ model }) => {
2470
- const navigate = useNavigate();
2471
- const { formatMessage } = useIntl();
2472
- return {
2473
- label: formatMessage({
2474
- id: "content-manager.link-to-ctb",
2475
- defaultMessage: "Edit the model"
2476
- }),
2477
- icon: /* @__PURE__ */ jsx(Pencil, {}),
2478
- onClick: () => {
2479
- navigate(`/plugins/content-type-builder/content-types/${model}`);
2480
- },
2481
- position: "header"
2482
- };
2483
- };
2484
- EditTheModelAction.type = "edit-the-model";
2485
- const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2486
- const navigate = useNavigate();
2487
- const { formatMessage } = useIntl();
2488
- const listViewPathMatch = useMatch(LIST_PATH);
2489
- const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2490
- const { delete: deleteAction } = useDocumentActions();
2491
- const { toggleNotification } = useNotification();
2492
- const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2493
- return {
2494
- disabled: !canDelete || !document,
2495
- label: formatMessage({
2496
- id: "content-manager.actions.delete.label",
2497
- defaultMessage: "Delete document"
2498
- }),
2499
- icon: /* @__PURE__ */ jsx(Trash, {}),
2500
- dialog: {
2501
- type: "dialog",
2502
- title: formatMessage({
2503
- id: "app.components.ConfirmDialog.title",
2504
- defaultMessage: "Confirmation"
2505
- }),
2506
- content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2507
- /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2508
- /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2509
- id: "content-manager.actions.delete.dialog.body",
2510
- defaultMessage: "Are you sure?"
2511
- }) })
2512
- ] }),
2513
- onConfirm: async () => {
2514
- if (!listViewPathMatch) {
2515
- setSubmitting(true);
2516
- }
2517
- try {
2518
- if (!documentId && collectionType !== SINGLE_TYPES) {
2519
- console.error(
2520
- "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2521
- );
2522
- toggleNotification({
2523
- message: formatMessage({
2524
- id: "content-manager.actions.delete.error",
2525
- defaultMessage: "An error occurred while trying to delete the document."
2526
- }),
2527
- type: "danger"
2528
- });
2529
- return;
2530
- }
2531
- const res = await deleteAction({
2532
- documentId,
2533
- model,
2534
- collectionType,
2535
- params: {
2536
- locale: "*"
2537
- }
2538
- });
2539
- if (!("error" in res)) {
2540
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2541
- }
2542
- } finally {
2543
- if (!listViewPathMatch) {
2544
- setSubmitting(false);
2545
- }
2546
- }
2547
- }
2548
- },
2549
- variant: "danger",
2550
- position: ["header", "table-row"]
2551
- };
2552
- };
2553
- DeleteAction$1.type = "delete";
2554
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2555
- const Panels = () => {
2556
- const isCloning = useMatch(CLONE_PATH) !== null;
2557
- const [
2558
- {
2559
- query: { status }
2560
- }
2561
- ] = useQueryParams({
2562
- status: "draft"
2563
- });
2564
- const { model, id, document, meta, collectionType } = useDoc();
2565
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2566
- const props = {
2567
- activeTab: status,
2568
- model,
2569
- documentId: id,
2570
- document: isCloning ? void 0 : document,
2571
- meta: isCloning ? void 0 : meta,
2572
- collectionType
2573
- };
2574
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2575
- DescriptionComponentRenderer,
2576
- {
2577
- props,
2578
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2579
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2580
- }
2581
- ) });
2582
- };
2583
- const ActionsPanel = () => {
2584
- const { formatMessage } = useIntl();
2585
- return {
2586
- title: formatMessage({
2587
- id: "content-manager.containers.edit.panels.default.title",
2588
- defaultMessage: "Entry"
2589
- }),
2590
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2591
- };
2592
- };
2593
- ActionsPanel.type = "actions";
2594
- const ActionsPanelContent = () => {
2595
- const isCloning = useMatch(CLONE_PATH) !== null;
2596
- const [
2597
- {
2598
- query: { status = "draft" }
2599
- }
2600
- ] = useQueryParams();
2601
- const { model, id, document, meta, collectionType } = useDoc();
2602
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2603
- const props = {
2604
- activeTab: status,
2605
- model,
2606
- documentId: id,
2607
- document: isCloning ? void 0 : document,
2608
- meta: isCloning ? void 0 : meta,
2609
- collectionType
2610
- };
2611
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2612
- /* @__PURE__ */ jsx(
2613
- DescriptionComponentRenderer,
2614
- {
2615
- props,
2616
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2617
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2618
- }
2619
- ),
2620
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2621
- ] });
2622
- };
2623
- const Panel = React.forwardRef(({ children, title }, ref) => {
2624
- return /* @__PURE__ */ jsxs(
2625
- Flex,
2626
- {
2627
- ref,
2628
- tag: "aside",
2629
- "aria-labelledby": "additional-information",
2630
- background: "neutral0",
2631
- borderColor: "neutral150",
2632
- hasRadius: true,
2633
- paddingBottom: 4,
2634
- paddingLeft: 4,
2635
- paddingRight: 4,
2636
- paddingTop: 4,
2637
- shadow: "tableShadow",
2638
- gap: 3,
2639
- direction: "column",
2640
- justifyContent: "stretch",
2641
- alignItems: "flex-start",
2642
- children: [
2643
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2644
- children
2645
- ]
2646
- }
2647
- );
2648
- });
2649
- const HOOKS = {
2650
- /**
2651
- * Hook that allows to mutate the displayed headers of the list view table
2652
- * @constant
2653
- * @type {string}
2654
- */
2655
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2656
- /**
2657
- * Hook that allows to mutate the CM's collection types links pre-set filters
2658
- * @constant
2659
- * @type {string}
2660
- */
2661
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2662
- /**
2663
- * Hook that allows to mutate the CM's edit view layout
2664
- * @constant
2665
- * @type {string}
2666
- */
2667
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2668
- /**
2669
- * Hook that allows to mutate the CM's single types links pre-set filters
2670
- * @constant
2671
- * @type {string}
2672
- */
2673
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2674
- };
2675
- const contentTypesApi = contentManagerApi.injectEndpoints({
2676
- endpoints: (builder) => ({
2677
- getContentTypeConfiguration: builder.query({
2678
- query: (uid) => ({
2679
- url: `/content-manager/content-types/${uid}/configuration`,
2680
- method: "GET"
2681
- }),
2682
- transformResponse: (response) => response.data,
2683
- providesTags: (_result, _error, uid) => [
2684
- { type: "ContentTypesConfiguration", id: uid },
2685
- { type: "ContentTypeSettings", id: "LIST" }
2686
- ]
2687
- }),
2688
- getAllContentTypeSettings: builder.query({
2689
- query: () => "/content-manager/content-types-settings",
2690
- transformResponse: (response) => response.data,
2691
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2692
- }),
2693
- updateContentTypeConfiguration: builder.mutation({
2694
- query: ({ uid, ...body }) => ({
2695
- url: `/content-manager/content-types/${uid}/configuration`,
2696
- method: "PUT",
2697
- data: body
2698
- }),
2699
- transformResponse: (response) => response.data,
2700
- invalidatesTags: (_result, _error, { uid }) => [
2701
- { type: "ContentTypesConfiguration", id: uid },
2702
- { type: "ContentTypeSettings", id: "LIST" },
2703
- // Is this necessary?
2704
- { type: "InitialData" }
2705
- ]
2706
- })
2707
- })
2708
- });
2709
- const {
2710
- useGetContentTypeConfigurationQuery,
2711
- useGetAllContentTypeSettingsQuery,
2712
- useUpdateContentTypeConfigurationMutation
2713
- } = contentTypesApi;
2714
- const checkIfAttributeIsDisplayable = (attribute) => {
2715
- const { type } = attribute;
2716
- if (type === "relation") {
2717
- return !attribute.relation.toLowerCase().includes("morph");
2718
- }
2719
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2720
- };
2721
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2722
- if (!mainFieldName) {
2723
- return void 0;
2724
- }
2725
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2726
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2727
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2728
- );
2729
- return {
2730
- name: mainFieldName,
2731
- type: mainFieldType ?? "string"
2732
- };
2733
- };
2734
- const DEFAULT_SETTINGS = {
2735
- bulkable: false,
2736
- filterable: false,
2737
- searchable: false,
2738
- pagination: false,
2739
- defaultSortBy: "",
2740
- defaultSortOrder: "asc",
2741
- mainField: "id",
2742
- pageSize: 10
2743
- };
2744
- const useDocumentLayout = (model) => {
2745
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2746
- const [{ query }] = useQueryParams();
2747
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2748
- const { toggleNotification } = useNotification();
2749
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2750
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2751
- const {
2752
- data,
2753
- isLoading: isLoadingConfigs,
2754
- error,
2755
- isFetching: isFetchingConfigs
2756
- } = useGetContentTypeConfigurationQuery(model);
2757
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2758
- React.useEffect(() => {
2759
- if (error) {
2760
- toggleNotification({
2761
- type: "danger",
2762
- message: formatAPIError(error)
2763
- });
2764
- }
2765
- }, [error, formatAPIError, toggleNotification]);
2766
- const editLayout = React.useMemo(
2767
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2768
- layout: [],
2769
- components: {},
2770
- metadatas: {},
2771
- options: {},
2772
- settings: DEFAULT_SETTINGS
2773
- },
2774
- [data, isLoading, schemas, schema, components]
2775
- );
2776
- const listLayout = React.useMemo(() => {
2777
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2778
- layout: [],
2779
- metadatas: {},
2780
- options: {},
2781
- settings: DEFAULT_SETTINGS
2782
- };
2783
- }, [data, isLoading, schemas, schema, components]);
2784
- const { layout: edit } = React.useMemo(
2785
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2786
- layout: editLayout,
2787
- query
2788
- }),
2789
- [editLayout, query, runHookWaterfall]
2790
- );
2791
- return {
2792
- error,
2793
- isLoading,
2794
- edit,
2795
- list: listLayout
2796
- };
2797
- };
2798
- const useDocLayout = () => {
2799
- const { model } = useDoc();
2800
- return useDocumentLayout(model);
2801
- };
2802
- const formatEditLayout = (data, {
2803
- schemas,
2804
- schema,
2805
- components
2806
- }) => {
2807
- let currentPanelIndex = 0;
2808
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2809
- data.contentType.layouts.edit,
2810
- schema?.attributes,
2811
- data.contentType.metadatas,
2812
- { configurations: data.components, schemas: components },
2813
- schemas
2814
- ).reduce((panels, row) => {
2815
- if (row.some((field) => field.type === "dynamiczone")) {
2816
- panels.push([row]);
2817
- currentPanelIndex += 2;
2818
- } else {
2819
- if (!panels[currentPanelIndex]) {
2820
- panels.push([]);
2821
- }
2822
- panels[currentPanelIndex].push(row);
2823
- }
2824
- return panels;
2825
- }, []);
2826
- const componentEditAttributes = Object.entries(data.components).reduce(
2827
- (acc, [uid, configuration]) => {
2828
- acc[uid] = {
2829
- layout: convertEditLayoutToFieldLayouts(
2830
- configuration.layouts.edit,
2831
- components[uid].attributes,
2832
- configuration.metadatas,
2833
- { configurations: data.components, schemas: components }
2834
- ),
2835
- settings: {
2836
- ...configuration.settings,
2837
- icon: components[uid].info.icon,
2838
- displayName: components[uid].info.displayName
2839
- }
2840
- };
2841
- return acc;
2842
- },
2843
- {}
2844
- );
2845
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2846
- (acc, [attribute, metadata]) => {
2847
- return {
2848
- ...acc,
2849
- [attribute]: metadata.edit
2850
- };
2851
- },
2852
- {}
2853
- );
2818
+ ConfigureTheViewAction.type = "configure-the-view";
2819
+ const EditTheModelAction = ({ model }) => {
2820
+ const navigate = useNavigate();
2821
+ const { formatMessage } = useIntl();
2854
2822
  return {
2855
- layout: panelledEditAttributes,
2856
- components: componentEditAttributes,
2857
- metadatas: editMetadatas,
2858
- settings: {
2859
- ...data.contentType.settings,
2860
- displayName: schema?.info.displayName
2823
+ label: formatMessage({
2824
+ id: "content-manager.link-to-ctb",
2825
+ defaultMessage: "Edit the model"
2826
+ }),
2827
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2828
+ onClick: () => {
2829
+ navigate(`/plugins/content-type-builder/content-types/${model}`);
2861
2830
  },
2862
- options: {
2863
- ...schema?.options,
2864
- ...schema?.pluginOptions,
2865
- ...data.contentType.options
2866
- }
2831
+ position: "header"
2867
2832
  };
2868
2833
  };
2869
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2870
- return rows.map(
2871
- (row) => row.map((field) => {
2872
- const attribute = attributes[field.name];
2873
- if (!attribute) {
2874
- return null;
2834
+ EditTheModelAction.type = "edit-the-model";
2835
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2836
+ const navigate = useNavigate();
2837
+ const { formatMessage } = useIntl();
2838
+ const listViewPathMatch = useMatch(LIST_PATH);
2839
+ const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2840
+ const { delete: deleteAction } = useDocumentActions();
2841
+ const { toggleNotification } = useNotification();
2842
+ const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2843
+ const isLocalized = document?.locale != null;
2844
+ return {
2845
+ disabled: !canDelete || !document,
2846
+ label: formatMessage(
2847
+ {
2848
+ id: "content-manager.actions.delete.label",
2849
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2850
+ },
2851
+ { isLocalized }
2852
+ ),
2853
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2854
+ dialog: {
2855
+ type: "dialog",
2856
+ title: formatMessage({
2857
+ id: "app.components.ConfirmDialog.title",
2858
+ defaultMessage: "Confirmation"
2859
+ }),
2860
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2861
+ /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2862
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2863
+ id: "content-manager.actions.delete.dialog.body",
2864
+ defaultMessage: "Are you sure?"
2865
+ }) })
2866
+ ] }),
2867
+ onConfirm: async () => {
2868
+ if (!listViewPathMatch) {
2869
+ setSubmitting(true);
2870
+ }
2871
+ try {
2872
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2873
+ console.error(
2874
+ "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2875
+ );
2876
+ toggleNotification({
2877
+ message: formatMessage({
2878
+ id: "content-manager.actions.delete.error",
2879
+ defaultMessage: "An error occurred while trying to delete the document."
2880
+ }),
2881
+ type: "danger"
2882
+ });
2883
+ return;
2884
+ }
2885
+ const res = await deleteAction({
2886
+ documentId,
2887
+ model,
2888
+ collectionType,
2889
+ params: {
2890
+ locale: "*"
2891
+ }
2892
+ });
2893
+ if (!("error" in res)) {
2894
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2895
+ }
2896
+ } finally {
2897
+ if (!listViewPathMatch) {
2898
+ setSubmitting(false);
2899
+ }
2900
+ }
2875
2901
  }
2876
- const { edit: metadata } = metadatas[field.name];
2877
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2878
- return {
2879
- attribute,
2880
- disabled: !metadata.editable,
2881
- hint: metadata.description,
2882
- label: metadata.label ?? "",
2883
- name: field.name,
2884
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2885
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2886
- schemas,
2887
- components: components?.schemas ?? {}
2888
- }),
2889
- placeholder: metadata.placeholder ?? "",
2890
- required: attribute.required ?? false,
2891
- size: field.size,
2892
- unique: "unique" in attribute ? attribute.unique : false,
2893
- visible: metadata.visible ?? true,
2894
- type: attribute.type
2895
- };
2896
- }).filter((field) => field !== null)
2897
- );
2898
- };
2899
- const formatListLayout = (data, {
2900
- schemas,
2901
- schema,
2902
- components
2903
- }) => {
2904
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2905
- (acc, [attribute, metadata]) => {
2906
- return {
2907
- ...acc,
2908
- [attribute]: metadata.list
2909
- };
2910
2902
  },
2911
- {}
2912
- );
2913
- const listAttributes = convertListLayoutToFieldLayouts(
2914
- data.contentType.layouts.list,
2915
- schema?.attributes,
2916
- listMetadatas,
2917
- { configurations: data.components, schemas: components },
2918
- schemas
2919
- );
2920
- return {
2921
- layout: listAttributes,
2922
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2923
- metadatas: listMetadatas,
2924
- options: {
2925
- ...schema?.options,
2926
- ...schema?.pluginOptions,
2927
- ...data.contentType.options
2903
+ variant: "danger",
2904
+ position: ["header", "table-row"]
2905
+ };
2906
+ };
2907
+ DeleteAction$1.type = "delete";
2908
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2909
+ const Panels = () => {
2910
+ const isCloning = useMatch(CLONE_PATH) !== null;
2911
+ const [
2912
+ {
2913
+ query: { status }
2914
+ }
2915
+ ] = useQueryParams({
2916
+ status: "draft"
2917
+ });
2918
+ const { model, id, document, meta, collectionType } = useDoc();
2919
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
2920
+ const props = {
2921
+ activeTab: status,
2922
+ model,
2923
+ documentId: id,
2924
+ document: isCloning ? void 0 : document,
2925
+ meta: isCloning ? void 0 : meta,
2926
+ collectionType
2927
+ };
2928
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2929
+ DescriptionComponentRenderer,
2930
+ {
2931
+ props,
2932
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2933
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2928
2934
  }
2935
+ ) });
2936
+ };
2937
+ const ActionsPanel = () => {
2938
+ const { formatMessage } = useIntl();
2939
+ return {
2940
+ title: formatMessage({
2941
+ id: "content-manager.containers.edit.panels.default.title",
2942
+ defaultMessage: "Entry"
2943
+ }),
2944
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2929
2945
  };
2930
2946
  };
2931
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2932
- return columns.map((name) => {
2933
- const attribute = attributes[name];
2934
- if (!attribute) {
2935
- return null;
2947
+ ActionsPanel.type = "actions";
2948
+ const ActionsPanelContent = () => {
2949
+ const isCloning = useMatch(CLONE_PATH) !== null;
2950
+ const [
2951
+ {
2952
+ query: { status = "draft" }
2936
2953
  }
2937
- const metadata = metadatas[name];
2938
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2939
- return {
2940
- attribute,
2941
- label: metadata.label ?? "",
2942
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2943
- schemas,
2944
- components: components?.schemas ?? {}
2945
- }),
2946
- name,
2947
- searchable: metadata.searchable ?? true,
2948
- sortable: metadata.sortable ?? true
2949
- };
2950
- }).filter((field) => field !== null);
2954
+ ] = useQueryParams();
2955
+ const { model, id, document, meta, collectionType } = useDoc();
2956
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2957
+ const props = {
2958
+ activeTab: status,
2959
+ model,
2960
+ documentId: id,
2961
+ document: isCloning ? void 0 : document,
2962
+ meta: isCloning ? void 0 : meta,
2963
+ collectionType
2964
+ };
2965
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2966
+ /* @__PURE__ */ jsx(
2967
+ DescriptionComponentRenderer,
2968
+ {
2969
+ props,
2970
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
2971
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2972
+ }
2973
+ ),
2974
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2975
+ ] });
2951
2976
  };
2977
+ const Panel = React.forwardRef(({ children, title }, ref) => {
2978
+ return /* @__PURE__ */ jsxs(
2979
+ Flex,
2980
+ {
2981
+ ref,
2982
+ tag: "aside",
2983
+ "aria-labelledby": "additional-information",
2984
+ background: "neutral0",
2985
+ borderColor: "neutral150",
2986
+ hasRadius: true,
2987
+ paddingBottom: 4,
2988
+ paddingLeft: 4,
2989
+ paddingRight: 4,
2990
+ paddingTop: 4,
2991
+ shadow: "tableShadow",
2992
+ gap: 3,
2993
+ direction: "column",
2994
+ justifyContent: "stretch",
2995
+ alignItems: "flex-start",
2996
+ children: [
2997
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2998
+ children
2999
+ ]
3000
+ }
3001
+ );
3002
+ });
2952
3003
  const ConfirmBulkActionDialog = ({
2953
3004
  onToggleDialog,
2954
3005
  isOpen = false,
@@ -3945,7 +3996,7 @@ const index = {
3945
3996
  app.router.addRoute({
3946
3997
  path: "content-manager/*",
3947
3998
  lazy: async () => {
3948
- const { Layout } = await import("./layout-DX_52HSH.mjs");
3999
+ const { Layout } = await import("./layout-ClP-DC72.mjs");
3949
4000
  return {
3950
4001
  Component: Layout
3951
4002
  };
@@ -3962,7 +4013,7 @@ const index = {
3962
4013
  async registerTrads({ locales }) {
3963
4014
  const importedTrads = await Promise.all(
3964
4015
  locales.map((locale) => {
3965
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-CPTj6CjC.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
4016
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-C8YBvRrK.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3966
4017
  return {
3967
4018
  data: prefixPluginTranslations(data, PLUGIN_ID),
3968
4019
  locale
@@ -3990,7 +4041,8 @@ export {
3990
4041
  InjectionZone as I,
3991
4042
  useDocument as J,
3992
4043
  index as K,
3993
- useDocumentActions as L,
4044
+ useContentManagerContext as L,
4045
+ useDocumentActions as M,
3994
4046
  Panels as P,
3995
4047
  RelativeTime as R,
3996
4048
  SINGLE_TYPES as S,
@@ -4022,4 +4074,4 @@ export {
4022
4074
  capitalise as y,
4023
4075
  useUpdateContentTypeConfigurationMutation as z
4024
4076
  };
4025
- //# sourceMappingURL=index-BHfS6_D5.mjs.map
4077
+ //# sourceMappingURL=index-BmUAydCA.mjs.map