312 lines
12 KiB
JavaScript
312 lines
12 KiB
JavaScript
'use strict';
|
||
|
||
var React = require('react');
|
||
var strapiAdmin = require('@strapi/admin/strapi-admin');
|
||
var hooks = require('../constants/hooks.js');
|
||
var contentTypes = require('../services/contentTypes.js');
|
||
var attributes = require('../utils/attributes.js');
|
||
var useContentTypeSchema = require('./useContentTypeSchema.js');
|
||
var useDocument = require('./useDocument.js');
|
||
|
||
function _interopNamespaceDefault(e) {
|
||
var n = Object.create(null);
|
||
if (e) {
|
||
Object.keys(e).forEach(function (k) {
|
||
if (k !== 'default') {
|
||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||
Object.defineProperty(n, k, d.get ? d : {
|
||
enumerable: true,
|
||
get: function () { return e[k]; }
|
||
});
|
||
}
|
||
});
|
||
}
|
||
n.default = e;
|
||
return Object.freeze(n);
|
||
}
|
||
|
||
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
||
|
||
/* -------------------------------------------------------------------------------------------------
|
||
* useDocumentLayout
|
||
* -----------------------------------------------------------------------------------------------*/ const DEFAULT_SETTINGS = {
|
||
bulkable: false,
|
||
filterable: false,
|
||
searchable: false,
|
||
pagination: false,
|
||
defaultSortBy: '',
|
||
defaultSortOrder: 'asc',
|
||
mainField: 'id',
|
||
pageSize: 10
|
||
};
|
||
/**
|
||
* @alpha
|
||
* @description This hook is used to get the layouts for either the edit view or list view of a specific content-type
|
||
* including the layouts for the components used in the content-type. It also runs the mutation hook waterfall so the data
|
||
* is consistent wherever it is used. It's a light wrapper around the `useDocument` hook, but provides the `skip` option a document
|
||
* is not fetched, however, it does fetch the schemas & components if they do not already exist in the cache.
|
||
*
|
||
* If the fetch fails, it will display a notification to the user.
|
||
*
|
||
* @example
|
||
* ```tsx
|
||
* const { model } = useParams<{ model: string }>();
|
||
* const { edit: { schema: layout } } = useDocumentLayout(model);
|
||
*
|
||
* return layout.map(panel => panel.map(row => row.map(field => <Field.Root {...field} />)))
|
||
* ```
|
||
*
|
||
*/ const useDocumentLayout = (model)=>{
|
||
const { schema, components } = useDocument.useDocument({
|
||
model,
|
||
collectionType: ''
|
||
}, {
|
||
skip: true
|
||
});
|
||
const [{ query }] = strapiAdmin.useQueryParams();
|
||
const runHookWaterfall = strapiAdmin.useStrapiApp('useDocumentLayout', (state)=>state.runHookWaterfall);
|
||
const { toggleNotification } = strapiAdmin.useNotification();
|
||
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
||
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema.useContentTypeSchema();
|
||
const { data, isLoading: isLoadingConfigs, error, isFetching: isFetchingConfigs } = contentTypes.useGetContentTypeConfigurationQuery(model);
|
||
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
||
React__namespace.useEffect(()=>{
|
||
if (error) {
|
||
toggleNotification({
|
||
type: 'danger',
|
||
message: formatAPIError(error)
|
||
});
|
||
}
|
||
}, [
|
||
error,
|
||
formatAPIError,
|
||
toggleNotification
|
||
]);
|
||
const editLayout = React__namespace.useMemo(()=>data && !isLoading ? formatEditLayout(data, {
|
||
schemas,
|
||
schema,
|
||
components
|
||
}) : {
|
||
layout: [],
|
||
components: {},
|
||
metadatas: {},
|
||
options: {},
|
||
settings: DEFAULT_SETTINGS
|
||
}, [
|
||
data,
|
||
isLoading,
|
||
schemas,
|
||
schema,
|
||
components
|
||
]);
|
||
const listLayout = React__namespace.useMemo(()=>{
|
||
return data && !isLoading ? formatListLayout(data, {
|
||
schemas,
|
||
schema,
|
||
components
|
||
}) : {
|
||
layout: [],
|
||
metadatas: {},
|
||
options: {},
|
||
settings: DEFAULT_SETTINGS
|
||
};
|
||
}, [
|
||
data,
|
||
isLoading,
|
||
schemas,
|
||
schema,
|
||
components
|
||
]);
|
||
const { layout: edit } = React__namespace.useMemo(()=>runHookWaterfall(hooks.HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
||
layout: editLayout,
|
||
query
|
||
}), [
|
||
editLayout,
|
||
query,
|
||
runHookWaterfall
|
||
]);
|
||
return {
|
||
error,
|
||
isLoading,
|
||
edit,
|
||
list: listLayout
|
||
};
|
||
};
|
||
/* -------------------------------------------------------------------------------------------------
|
||
* useDocLayout
|
||
* -----------------------------------------------------------------------------------------------*/ /**
|
||
* @internal this hook uses the internal useDoc hook, as such it shouldn't be used outside of the
|
||
* content-manager because it won't work as intended.
|
||
*/ const useDocLayout = ()=>{
|
||
const { model } = useDocument.useDoc();
|
||
return useDocumentLayout(model);
|
||
};
|
||
/**
|
||
* @internal
|
||
* @description takes the configuration data, the schema & the components used in the schema and formats the edit view
|
||
* versions of the schema & components. This is then used to render the edit view of the content-type.
|
||
*/ const formatEditLayout = (data, { schemas, schema, components })=>{
|
||
let currentPanelIndex = 0;
|
||
/**
|
||
* The fields arranged by the panels, new panels are made for dynamic zones only.
|
||
*/ const panelledEditAttributes = convertEditLayoutToFieldLayouts(data.contentType.layouts.edit, schema?.attributes, data.contentType.metadatas, {
|
||
configurations: data.components,
|
||
schemas: components
|
||
}, schemas).reduce((panels, row)=>{
|
||
if (row.some((field)=>field.type === 'dynamiczone')) {
|
||
panels.push([
|
||
row
|
||
]);
|
||
currentPanelIndex += 2;
|
||
} else {
|
||
if (!panels[currentPanelIndex]) {
|
||
panels.push([
|
||
row
|
||
]);
|
||
} else {
|
||
panels[currentPanelIndex].push(row);
|
||
}
|
||
}
|
||
return panels;
|
||
}, []);
|
||
const componentEditAttributes = Object.entries(data.components).reduce((acc, [uid, configuration])=>{
|
||
acc[uid] = {
|
||
layout: convertEditLayoutToFieldLayouts(configuration.layouts.edit, components[uid].attributes, configuration.metadatas, {
|
||
configurations: data.components,
|
||
schemas: components
|
||
}),
|
||
settings: {
|
||
...configuration.settings,
|
||
icon: components[uid].info.icon,
|
||
displayName: components[uid].info.displayName
|
||
}
|
||
};
|
||
return acc;
|
||
}, {});
|
||
const editMetadatas = Object.entries(data.contentType.metadatas).reduce((acc, [attribute, metadata])=>{
|
||
return {
|
||
...acc,
|
||
[attribute]: metadata.edit
|
||
};
|
||
}, {});
|
||
return {
|
||
layout: panelledEditAttributes,
|
||
components: componentEditAttributes,
|
||
metadatas: editMetadatas,
|
||
settings: {
|
||
...data.contentType.settings,
|
||
displayName: schema?.info.displayName
|
||
},
|
||
options: {
|
||
...schema?.options,
|
||
...schema?.pluginOptions,
|
||
...data.contentType.options
|
||
}
|
||
};
|
||
};
|
||
/* -------------------------------------------------------------------------------------------------
|
||
* convertEditLayoutToFieldLayouts
|
||
* -----------------------------------------------------------------------------------------------*/ /**
|
||
* @internal
|
||
* @description takes the edit layout from either a content-type or a component
|
||
* and formats it into a generic object that can be used to correctly render
|
||
* the form fields.
|
||
*/ const convertEditLayoutToFieldLayouts = (rows, attributes$1 = {}, metadatas, components, schemas = [])=>{
|
||
return rows.map((row)=>row.map((field)=>{
|
||
const attribute = attributes$1[field.name];
|
||
if (!attribute) {
|
||
return null;
|
||
}
|
||
const { edit: metadata } = metadatas[field.name];
|
||
const settings = attribute.type === 'component' && components ? components.configurations[attribute.component].settings : {};
|
||
return {
|
||
attribute,
|
||
disabled: !metadata.editable,
|
||
hint: metadata.description,
|
||
label: metadata.label ?? '',
|
||
name: field.name,
|
||
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
||
mainField: attributes.getMainField(attribute, metadata.mainField || settings.mainField, {
|
||
schemas,
|
||
components: components?.schemas ?? {}
|
||
}),
|
||
placeholder: metadata.placeholder ?? '',
|
||
required: attribute.required ?? false,
|
||
size: field.size,
|
||
unique: 'unique' in attribute ? attribute.unique : false,
|
||
visible: metadata.visible ?? true,
|
||
type: attribute.type
|
||
};
|
||
}).filter((field)=>field !== null));
|
||
};
|
||
/* -------------------------------------------------------------------------------------------------
|
||
* formatListLayout
|
||
* -----------------------------------------------------------------------------------------------*/ /**
|
||
* @internal
|
||
* @description takes the complete configuration data, the schema & the components used in the schema and
|
||
* formats a list view layout for the content-type. This is much simpler than the edit view layout as there
|
||
* are less options to consider.
|
||
*/ const formatListLayout = (data, { schemas, schema, components })=>{
|
||
const listMetadatas = Object.entries(data.contentType.metadatas).reduce((acc, [attribute, metadata])=>{
|
||
return {
|
||
...acc,
|
||
[attribute]: metadata.list
|
||
};
|
||
}, {});
|
||
/**
|
||
* The fields arranged by the panels, new panels are made for dynamic zones only.
|
||
*/ const listAttributes = convertListLayoutToFieldLayouts(data.contentType.layouts.list, schema?.attributes, listMetadatas, {
|
||
configurations: data.components,
|
||
schemas: components
|
||
}, schemas);
|
||
return {
|
||
layout: listAttributes,
|
||
settings: {
|
||
...data.contentType.settings,
|
||
displayName: schema?.info.displayName
|
||
},
|
||
metadatas: listMetadatas,
|
||
options: {
|
||
...schema?.options,
|
||
...schema?.pluginOptions,
|
||
...data.contentType.options
|
||
}
|
||
};
|
||
};
|
||
/* -------------------------------------------------------------------------------------------------
|
||
* convertListLayoutToFieldLayouts
|
||
* -----------------------------------------------------------------------------------------------*/ /**
|
||
* @internal
|
||
* @description takes the columns from the list view configuration and formats them into a generic object
|
||
* combinining metadata and attribute data.
|
||
*
|
||
* @note We do use this to reformat the list of strings when updating the displayed headers for the list view.
|
||
*/ const convertListLayoutToFieldLayouts = (columns, attributes$1 = {}, metadatas, components, schemas = [])=>{
|
||
return columns.map((name)=>{
|
||
const attribute = attributes$1[name];
|
||
if (!attribute) {
|
||
return null;
|
||
}
|
||
const metadata = metadatas[name];
|
||
const settings = attribute.type === 'component' && components ? components.configurations[attribute.component].settings : {};
|
||
return {
|
||
attribute,
|
||
label: metadata.label ?? '',
|
||
mainField: attributes.getMainField(attribute, metadata.mainField || settings.mainField, {
|
||
schemas,
|
||
components: components?.schemas ?? {}
|
||
}),
|
||
name: name,
|
||
searchable: metadata.searchable ?? true,
|
||
sortable: metadata.sortable ?? true
|
||
};
|
||
}).filter((field)=>field !== null);
|
||
};
|
||
|
||
exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
|
||
exports.convertEditLayoutToFieldLayouts = convertEditLayoutToFieldLayouts;
|
||
exports.convertListLayoutToFieldLayouts = convertListLayoutToFieldLayouts;
|
||
exports.useDocLayout = useDocLayout;
|
||
exports.useDocumentLayout = useDocumentLayout;
|
||
//# sourceMappingURL=useDocumentLayout.js.map
|