Skip to content

Commit 9d5613f

Browse files
authored
Fix: Automatically create initial content item during model creation (#1940)
* fix: auto create initial content item for templateset model type * fix: hardcode parentZUID to 0 * task: use existing ContentItem type * task: revert type changes
1 parent b6e0eaa commit 9d5613f

File tree

4 files changed

+160
-32
lines changed

4 files changed

+160
-32
lines changed

src/apps/schema/src/app/components/CreateModelDialogue.tsx

+59-7
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,23 @@ import { useEffect, useReducer, useState } from "react";
2323
import CloseRoundedIcon from "@mui/icons-material/CloseRounded";
2424
import MenuBookRoundedIcon from "@mui/icons-material/MenuBookRounded";
2525
import InfoRoundedIcon from "@mui/icons-material/InfoRounded";
26+
import { isEmpty } from "lodash";
27+
import { useSelector } from "react-redux";
28+
2629
import {
2730
useCreateContentModelMutation,
2831
useGetContentModelsQuery,
32+
useCreateContentItemMutation,
2933
} from "../../../../../shell/services/instance";
30-
import { ContentModel } from "../../../../../shell/services/types";
34+
import { ContentModel, User } from "../../../../../shell/services/types";
3135
import { notify } from "../../../../../shell/store/notifications";
3236
import { useDispatch } from "react-redux";
3337
import { LoadingButton } from "@mui/lab";
3438
import { useHistory } from "react-router";
3539
import { modelIconMap } from "../utils";
3640
import { withCursorPosition } from "../../../../../shell/components/withCursorPosition";
41+
import { formatPathPart } from "../../../../../utility/formatPathPart";
42+
import { AppState } from "../../../../../shell/store/types";
3743

3844
interface Props {
3945
onClose: () => void;
@@ -93,15 +99,61 @@ export const CreateModelDialogue = ({ onClose, modelType = "" }: Props) => {
9399
);
94100

95101
const { data: models } = useGetContentModelsQuery();
96-
const [createModel, { isLoading, isSuccess, error, data }] =
97-
useCreateContentModelMutation();
102+
const [
103+
createModel,
104+
{
105+
isLoading: isCreatingModel,
106+
isSuccess: isModelCreated,
107+
error: createModelError,
108+
data: createModelData,
109+
},
110+
] = useCreateContentModelMutation();
111+
const [
112+
createContentItem,
113+
{
114+
isLoading: isCreatingContentItem,
115+
isSuccess: isContentItemCreated,
116+
error: createContentItemError,
117+
},
118+
] = useCreateContentItemMutation();
119+
const user: User = useSelector((state: AppState) => state.user);
120+
121+
const error = createModelError || createContentItemError;
122+
123+
useEffect(() => {
124+
if (isModelCreated && !isEmpty(createModelData?.data)) {
125+
// Create initial content item
126+
if (model.type !== "templateset") {
127+
history.push(`/schema/${createModelData.data.ZUID}`);
128+
onClose();
129+
} else {
130+
createContentItem({
131+
modelZUID: createModelData.data.ZUID,
132+
body: {
133+
web: {
134+
pathPart: formatPathPart(model.label),
135+
canonicalTagMode: 1,
136+
metaLinkText: model.label,
137+
metaTitle: model.label,
138+
parentZUID: "0",
139+
},
140+
meta: {
141+
contentModelZUID: createModelData.data.ZUID,
142+
createdByUserZUID: user.ZUID,
143+
},
144+
},
145+
});
146+
}
147+
}
148+
}, [isModelCreated, createModelData]);
98149

99150
useEffect(() => {
100-
if (isSuccess && data) {
101-
history.push(`/schema/${data.data.ZUID}`);
151+
// Only navigate to schema page once model and initial content is created for templateset
152+
if (isContentItemCreated && createModelData) {
153+
history.push(`/schema/${createModelData.data.ZUID}`);
102154
onClose();
103155
}
104-
}, [isSuccess]);
156+
}, [isContentItemCreated, createModelData]);
105157

106158
useEffect(() => {
107159
if (error) {
@@ -389,7 +441,7 @@ export const CreateModelDialogue = ({ onClose, modelType = "" }: Props) => {
389441
<LoadingButton
390442
variant="contained"
391443
disabled={!model.name || !model.label}
392-
loading={!!isLoading}
444+
loading={!!isCreatingModel || !!isCreatingContentItem}
393445
onClick={() =>
394446
createModel({
395447
...model,

src/apps/schema/src/app/components/DuplicateModelDialogue.tsx

+87-25
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,23 @@ import {
1818
import { alpha } from "@mui/material/styles";
1919
import { useEffect, useReducer, useState } from "react";
2020
import CloseRoundedIcon from "@mui/icons-material/CloseRounded";
21+
import { useSelector } from "react-redux";
22+
2123
import {
2224
useBulkCreateContentModelFieldMutation,
2325
useCreateContentModelMutation,
2426
useGetContentModelFieldsQuery,
2527
useGetContentModelsQuery,
28+
useCreateContentItemMutation,
2629
} from "../../../../../shell/services/instance";
27-
import { ContentModel } from "../../../../../shell/services/types";
30+
import { ContentModel, User } from "../../../../../shell/services/types";
2831
import { notify } from "../../../../../shell/store/notifications";
2932
import { useDispatch } from "react-redux";
3033
import { LoadingButton } from "@mui/lab";
3134
import { useHistory } from "react-router";
3235
import { modelIconMap, modelNameMap } from "../utils";
36+
import { formatPathPart } from "../../../../../utility/formatPathPart";
37+
import { AppState } from "../../../../../shell/store/types";
3338

3439
interface Props {
3540
onClose: () => void;
@@ -80,40 +85,49 @@ export const DuplicateModelDialogue = ({ onClose, model }: Props) => {
8085
error: createFieldsError,
8186
},
8287
] = useBulkCreateContentModelFieldMutation();
88+
const [
89+
createContentItem,
90+
{
91+
isLoading: isCreatingContentItem,
92+
isSuccess: isContentItemCreated,
93+
error: createContentItemError,
94+
},
95+
] = useCreateContentItemMutation();
96+
const user: User = useSelector((state: AppState) => state.user);
8397

84-
const error = createModelError || createFieldsError;
98+
const error = createModelError || createFieldsError || createContentItemError;
8599

86100
useEffect(() => {
87101
if (createModelIsSuccess && createModelData) {
88-
// If no fields to duplicate just redirect to the new model
89-
if (fields?.length) {
90-
const newFields = fields
91-
.filter((field) => !field?.deletedAt)
92-
.map((field) => {
93-
const { ZUID, settings, ...rest } = field;
94-
return {
95-
...rest,
96-
settings: {
97-
...settings,
98-
list: settings?.list || false,
99-
},
100-
};
101-
});
102-
createFields({
103-
modelZUID: createModelData.data.ZUID,
104-
fields: newFields,
105-
});
102+
if (newModel.type === "templateset") {
103+
// Create initial content item for templateset
104+
createInitialTemplatesetContent();
106105
} else {
107-
history.push(`/schema/${createModelData.data.ZUID}`);
108-
onClose();
106+
// For other model types, immediately just check if there are fields to duplicate
107+
if (fields?.length) {
108+
duplicateFields();
109+
} else {
110+
navigateToModelSchema();
111+
}
109112
}
110113
}
111114
}, [createModelIsSuccess]);
112115

116+
useEffect(() => {
117+
if (isContentItemCreated) {
118+
// Flow only applies to templateset model types
119+
// Duplicate fields if there any
120+
if (fields?.length) {
121+
duplicateFields();
122+
} else {
123+
navigateToModelSchema();
124+
}
125+
}
126+
}, [isContentItemCreated]);
127+
113128
useEffect(() => {
114129
if (createFieldsIsSuccess) {
115-
history.push(`/schema/${createModelData.data.ZUID}`);
116-
onClose();
130+
navigateToModelSchema();
117131
}
118132
}, [createFieldsIsSuccess]);
119133

@@ -129,6 +143,50 @@ export const DuplicateModelDialogue = ({ onClose, model }: Props) => {
129143
}
130144
}, [error]);
131145

146+
const navigateToModelSchema = () => {
147+
history.push(`/schema/${createModelData?.data.ZUID}`);
148+
onClose();
149+
};
150+
151+
const createInitialTemplatesetContent = () => {
152+
createContentItem({
153+
modelZUID: createModelData.data.ZUID,
154+
body: {
155+
web: {
156+
pathPart: formatPathPart(newModel.label),
157+
canonicalTagMode: 1,
158+
metaLinkText: newModel.label,
159+
metaTitle: newModel.label,
160+
parentZUID: "0",
161+
},
162+
meta: {
163+
contentModelZUID: createModelData.data.ZUID,
164+
createdByUserZUID: user.ZUID,
165+
},
166+
},
167+
});
168+
};
169+
170+
const duplicateFields = () => {
171+
const newFields = fields
172+
.filter((field) => !field?.deletedAt)
173+
.map((field) => {
174+
const { ZUID, settings, ...rest } = field;
175+
return {
176+
...rest,
177+
settings: {
178+
...settings,
179+
list: settings?.list || false,
180+
},
181+
};
182+
});
183+
184+
createFields({
185+
modelZUID: createModelData.data.ZUID,
186+
fields: newFields,
187+
});
188+
};
189+
132190
return (
133191
<Dialog
134192
open
@@ -268,7 +326,11 @@ export const DuplicateModelDialogue = ({ onClose, model }: Props) => {
268326
<LoadingButton
269327
variant="contained"
270328
disabled={!newModel.name || !newModel.label}
271-
loading={!!createModelIsLoading || !!createFieldsIsLoading}
329+
loading={
330+
!!createModelIsLoading ||
331+
!!createFieldsIsLoading ||
332+
!!isCreatingContentItem
333+
}
272334
onClick={() =>
273335
createModel({
274336
...newModel,

src/shell/services/instance.ts

+13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
Publishing,
1212
LegacyHeader,
1313
WebView,
14+
Web,
15+
Meta,
1416
} from "./types";
1517
import { batchApiRequests } from "../../utility/batchApiRequests";
1618

@@ -322,6 +324,16 @@ export const instanceApi = createApi({
322324
}),
323325
invalidatesTags: ["InstanceSettings"],
324326
}),
327+
createContentItem: builder.mutation<
328+
any,
329+
{ modelZUID: string; body: { web: Partial<Web>; meta: Partial<Meta> } }
330+
>({
331+
query: ({ modelZUID, body }) => ({
332+
url: `content/models/${modelZUID}/items`,
333+
method: "POST",
334+
body,
335+
}),
336+
}),
325337
}),
326338
});
327339

@@ -352,4 +364,5 @@ export const {
352364
useGetLegacyHeadTagsQuery,
353365
useGetInstanceSettingsQuery,
354366
useUpdateInstanceSettingMutation,
367+
useCreateContentItemMutation,
355368
} = instanceApi;

src/shell/services/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export interface Meta {
114114
langID: number;
115115
createdAt: string;
116116
updatedAt: string;
117+
createdByUserZUID: string;
117118
}
118119
export interface Data {
119120
content: string;

0 commit comments

Comments
 (0)