@strapi/content-manager 0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c → 0.0.0-experimental.f74ae50eea1ce95176f088dba837e95b60fa2a4d

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