diff --git a/apps/web/src/components/user/profile-description-editor.tsx b/apps/web/src/components/user/profile-description-editor.tsx index dde2644f71..e39dda4ebb 100644 --- a/apps/web/src/components/user/profile-description-editor.tsx +++ b/apps/web/src/components/user/profile-description-editor.tsx @@ -16,7 +16,7 @@ export function ProfileDescriptionEditor({ const handleSave = async (data: unknown) => { const success = await setDescription({ - description: (data as { description: string }).description, + description: (data as { content: string }).content, }) if (!success) { // eslint-disable-next-line no-console @@ -25,14 +25,11 @@ export function ProfileDescriptionEditor({ } return revalidatePath(`/user/profile/${username}`) } - const initialState = convertUserByDescription(rawDescription) return ( - <> -
- -
- +
+ +
) } diff --git a/apps/web/src/mutations/use-set-entity-mutation/types.ts b/apps/web/src/mutations/use-set-entity-mutation/types.ts index e77633aea8..c30ef72e04 100644 --- a/apps/web/src/mutations/use-set-entity-mutation/types.ts +++ b/apps/web/src/mutations/use-set-entity-mutation/types.ts @@ -1,18 +1,17 @@ -import type { - AbstractSerializedState, - TaxonomySerializedState, -} from '@/serlo-editor-integration/convert-editor-response-to-state' +import type { SerializedAbstractTemplatePluginDocument } from '@/serlo-editor-integration/convert-editor-response-to-state' -export type SetEntityMutationData = AbstractSerializedState & { +export type SetEntityMutationData = SerializedAbstractTemplatePluginDocument & { changes?: string } -export type TaxonomyCreateOrUpdateMutationData = Pick< - TaxonomySerializedState, - 'term' | 'description' -> & { +export interface TaxonomyCreateOrUpdateMutationData { __typename?: 'TaxonomyTerm' + term: { + name: string + } + description: string parent?: number + content: string } export interface SetEntityMutationRunnerData { diff --git a/apps/web/src/mutations/use-set-entity-mutation/use-set-entity-mutation.ts b/apps/web/src/mutations/use-set-entity-mutation/use-set-entity-mutation.ts index beda274da8..698e024909 100644 --- a/apps/web/src/mutations/use-set-entity-mutation/use-set-entity-mutation.ts +++ b/apps/web/src/mutations/use-set-entity-mutation/use-set-entity-mutation.ts @@ -59,7 +59,6 @@ export function useSetEntityMutation() { return false } const additionalInput = getAdditionalInputData(mutationStrings, data) - input = { entityId, ...genericInput, @@ -148,7 +147,13 @@ function getAdditionalInputData( mutationStrings: LoggedInData['strings']['mutations'], data: SetEntityMutationData ) { - const { title, url, content, description } = data + if ( + data.__typename === UuidType.Exercise || + data.__typename === UuidType.ExerciseGroup + ) { + return {} + } + const { title, url, content } = data switch (data.__typename) { case UuidType.Course: case UuidType.Article: @@ -157,16 +162,14 @@ function getAdditionalInputData( return { title: getRequiredString(mutationStrings, 'title', title), } - case UuidType.Exercise: case UuidType.ExerciseGroup: return {} case UuidType.Video: return { title: getRequiredString(mutationStrings, 'title', title), - // url is stored in content for some reason - url: getRequiredString(mutationStrings, 'url', content), - content: getRequiredString(mutationStrings, 'content', description), + url: getRequiredString(mutationStrings, 'url', url), + content: getRequiredString(mutationStrings, 'content', content), } case UuidType.Applet: return { diff --git a/apps/web/src/mutations/use-taxonomy-create-or-update-mutation.ts b/apps/web/src/mutations/use-taxonomy-create-or-update-mutation.ts index 898e197af2..de65d1c8a4 100644 --- a/apps/web/src/mutations/use-taxonomy-create-or-update-mutation.ts +++ b/apps/web/src/mutations/use-taxonomy-create-or-update-mutation.ts @@ -55,8 +55,8 @@ export function useTaxonomyCreateOrUpdateMutation() { name: getRequiredString(mutationStrings, 'name', data.term.name), description: getRequiredString( mutationStrings, - 'description', - data.description + 'content', + data.content ), } diff --git a/apps/web/src/pages/taxonomy/term/create/[parent_id]/[id].tsx b/apps/web/src/pages/taxonomy/term/create/[parent_id]/[id].tsx index e0f25e5cd9..a9bae48bc3 100644 --- a/apps/web/src/pages/taxonomy/term/create/[parent_id]/[id].tsx +++ b/apps/web/src/pages/taxonomy/term/create/[parent_id]/[id].tsx @@ -1,4 +1,8 @@ -import { createEmptyDocument, TemplatePluginType } from '@editor/package' +import { + createEmptyDocument, + EditorPluginType, + TemplatePluginType, +} from '@editor/package' import { GetServerSideProps } from 'next' import { FrontendClientBase } from '@/components/frontend-client-base/frontend-client-base' @@ -30,7 +34,7 @@ export default renderedPageNoHooks(({ parent }) => { plugin: TemplatePluginType.Taxonomy, state: { term: { name: '' }, - description: '{"plugin":"rows"}', + content: { plugin: EditorPluginType.Rows }, }, }, }} diff --git a/apps/web/src/serlo-editor-integration/convert-editor-response-to-state.ts b/apps/web/src/serlo-editor-integration/convert-editor-response-to-state.ts index ee3ed963d4..c71bbf9da4 100644 --- a/apps/web/src/serlo-editor-integration/convert-editor-response-to-state.ts +++ b/apps/web/src/serlo-editor-integration/convert-editor-response-to-state.ts @@ -62,9 +62,7 @@ export function convertEditorResponseToState( message: `error while converting: ${JSON.stringify(stack)}`, }) - return { - error: 'failure', - } + return { error: 'failure' } } function convertAbstractEntity( @@ -78,21 +76,6 @@ export function convertEditorResponseToState( content ) - if (uuid.__typename === UuidType.Video) { - return { - ...editorMetadata, - document: { - plugin: TemplatePluginType.Video, - state: { - ...entityFields, - content: url ? url : templateContent, - description: templateContent, - ...(url ? { url } : {}), - }, - }, - } - } - return { ...editorMetadata, document: { @@ -113,8 +96,9 @@ export function convertEditorResponseToState( ): StorageFormat { stack.push({ id: uuid.id, type: entityType }) - const { editorMetadata, entityDescription } = unwrapEntityDescription( - uuid.description + const { editorMetadata, templateContent } = unwrapEditorContent( + UuidType.TaxonomyTerm, + uuid.description ?? undefined ) return { @@ -128,27 +112,13 @@ export function convertEditorResponseToState( term: { name: uuid.name, }, - description: entityDescription, + content: templateContent ?? { plugin: EditorPluginType.Rows }, }, }, } } } -function unwrapEntityDescription(description: string | null | undefined) { - const convertedDescription = parseEditorData(description ?? undefined) - - const editorMetadata = convertedDescription - ? R.omit(['document'], convertedDescription) - : R.omit(['document'], createEmptyDocument('serlo-org')) - - const entityDescription = serializeStaticDocument( - convertedDescription?.document - ) - - return { editorMetadata, entityDescription } -} - export function unwrapEditorContent( entityType: MainUuidType['__typename'], content?: string @@ -163,73 +133,48 @@ export function unwrapEditorContent( | AnyEditorDocument | undefined - let templateContent if ( entityType !== 'Article' || editorContent?.plugin === EditorPluginType.Article ) { - templateContent = serializeStaticDocument(editorContent) - } else { - // currently still needed. See https://serlo.slack.com/archives/CEB781NCU/p1695977868948869 - templateContent = serializeStaticDocument({ - plugin: EditorPluginType.Article, - state: { - introduction: { plugin: EditorPluginType.ArticleIntroduction }, - content: editorContent, - exercises: [], - exerciseFolder: { id: '', title: '' }, - relatedContent: { - articles: [], - courses: [], - videos: [], - }, - sources: [], - }, - }) + return { editorMetadata, templateContent: editorContent } } - return { editorMetadata, templateContent } + // currently still needed. See https://serlo.slack.com/archives/CEB781NCU/p1695977868948869 + const articlePluginDocument = { + plugin: EditorPluginType.Article, + state: { + introduction: { plugin: EditorPluginType.ArticleIntroduction }, + content: editorContent, + exercises: [], + exerciseFolder: { id: '', title: '' }, + relatedContent: { articles: [], courses: [], videos: [] }, + sources: [], + }, + } + return { editorMetadata, templateContent: articlePluginDocument } } -export function convertUserByDescription(description?: string | null) { - const { editorMetadata, entityDescription } = - unwrapEntityDescription(description) +export function convertUserByDescription(content?: string | null) { + const { editorMetadata, templateContent } = unwrapEditorContent( + UuidType.User, + content ?? undefined + ) return { ...editorMetadata, document: { plugin: TemplatePluginType.User, - state: { - description: entityDescription, - }, + state: { content: templateContent }, }, } } -export interface AbstractSerializedState { +export interface SerializedAbstractTemplatePluginDocument { __typename?: UuidType[number] - title?: string content: SerializedStaticState - reasoning?: SerializedStaticState - description: SerializedStaticState + title?: string url?: string - cohesive?: string -} - -export interface TaxonomySerializedState { - __typename?: UuidType.TaxonomyTerm - term: { - name: string - } - description: SerializedStaticState - taxonomy: number - parent: number - position: number -} - -export interface UserSerializedState { - __typename?: UuidType.User - description: SerializedStaticState } export type ConvertResponseError = @@ -245,16 +190,6 @@ export function isError( return !!(result as ConvertResponseError).error } -function serializeStaticDocument(content?: AnyEditorDocument): string { - if (typeof content === 'string') return content - return JSON.stringify( - content ?? { - plugin: EditorPluginType.Rows, - state: [{ plugin: EditorPluginType.Text, state: undefined }], - } - ) -} - function parseEditorData( content: SerializedStaticState ): StorageFormat | undefined { diff --git a/apps/web/src/serlo-editor-integration/convert-editor-state-to-set-entity-mutation-data.ts b/apps/web/src/serlo-editor-integration/convert-editor-state-to-set-entity-mutation-data.ts index 830739e87f..cd3b48bec5 100644 --- a/apps/web/src/serlo-editor-integration/convert-editor-state-to-set-entity-mutation-data.ts +++ b/apps/web/src/serlo-editor-integration/convert-editor-state-to-set-entity-mutation-data.ts @@ -1,33 +1,19 @@ -import { TemplatePluginType, type StorageFormat } from '@editor/package' +import { type StorageFormat } from '@editor/package' -import type { AbstractSerializedState } from './convert-editor-response-to-state' +import type { SerializedAbstractTemplatePluginDocument } from './convert-editor-response-to-state' import type { SetEntityMutationData } from '@/mutations/use-set-entity-mutation/types' export function convertEditorStateToSetEntityMutationData( editorState: StorageFormat ): SetEntityMutationData { const editorDocumentState = editorState.document - .state as AbstractSerializedState - - if ( - editorState.document.plugin === TemplatePluginType.Taxonomy || - editorState.document.plugin === TemplatePluginType.Video || - editorState.document.plugin === TemplatePluginType.User - ) { - return { - ...editorDocumentState, - description: JSON.stringify({ - ...editorState, - document: JSON.parse(editorDocumentState.description || '') as unknown, - }), - } - } + .state as SerializedAbstractTemplatePluginDocument return { ...editorDocumentState, content: JSON.stringify({ ...editorState, - document: JSON.parse(editorDocumentState.content || '') as unknown, + document: editorDocumentState.content, }), } } diff --git a/apps/web/src/serlo-editor-integration/use-handle-save.ts b/apps/web/src/serlo-editor-integration/use-handle-save.ts index 4bbd55b665..4279c97a3f 100644 --- a/apps/web/src/serlo-editor-integration/use-handle-save.ts +++ b/apps/web/src/serlo-editor-integration/use-handle-save.ts @@ -1,11 +1,11 @@ import { useEffect, useState } from 'react' -import { type AbstractSerializedState } from './convert-editor-response-to-state' +import { type SerializedAbstractTemplatePluginDocument } from './convert-editor-response-to-state' import type { SerloEditorProps } from './serlo-editor' export function useHandleSave( visible: boolean, - editorDocumentState: AbstractSerializedState, + editorDocumentState: SerializedAbstractTemplatePluginDocument, onSave: SerloEditorProps['onSave'] ) { const [pending, setPending] = useState(false) diff --git a/packages/editor/src/plugins/serlo-template-plugins/applet.tsx b/packages/editor/src/plugins/serlo-template-plugins/applet.tsx index 1b39670a8b..64a97e7e5c 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/applet.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/applet.tsx @@ -1,4 +1,5 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, @@ -6,12 +7,12 @@ import { } from '@editor/plugin' import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent, serializedChild } from './common/common' +import { serializedChild } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const appletTypeState = object({ title: string(), - content: editorContent(), + content: child({ plugin: EditorPluginType.Rows }), url: serializedChild(EditorPluginType.Geogebra), }) diff --git a/packages/editor/src/plugins/serlo-template-plugins/article.tsx b/packages/editor/src/plugins/serlo-template-plugins/article.tsx index cb069ce034..a8948f9944 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/article.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/article.tsx @@ -1,4 +1,5 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, @@ -6,12 +7,11 @@ import { } from '@editor/plugin' import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const articleTypeState = object({ title: string(), - content: editorContent(EditorPluginType.Article), + content: child({ plugin: EditorPluginType.Article }), }) export type ArticleTypePluginState = typeof articleTypeState diff --git a/packages/editor/src/plugins/serlo-template-plugins/common/common.tsx b/packages/editor/src/plugins/serlo-template-plugins/common/common.tsx index b1aa7dfebe..ac7c16bcf8 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/common/common.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/common/common.tsx @@ -4,30 +4,6 @@ import { StateTypeReturnType, child, } from '@editor/plugin' -import { EditorPluginType } from '@editor/types/editor-plugin-type' - -export function editorContent( - plugin: string = EditorPluginType.Rows -): StateType< - string, - StateTypeValueType>, - StateTypeReturnType> -> { - const originalChild = child({ plugin }) - return { - ...originalChild, - toStaticState(...args: Parameters) { - return JSON.stringify(originalChild.toStaticState(...args)) - }, - toStoreState( - serialized: string, - helpers: Parameters[1] - ) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - return originalChild.toStoreState(JSON.parse(serialized), helpers) - }, - } -} /** jup it's basically a string – and only used by type-applet */ export function serializedChild( diff --git a/packages/editor/src/plugins/serlo-template-plugins/course.tsx b/packages/editor/src/plugins/serlo-template-plugins/course.tsx index b15bf4751b..bc4d007256 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/course.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/course.tsx @@ -1,4 +1,5 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, @@ -7,12 +8,11 @@ import { import { CourseHeader } from '@editor/plugins/course/renderer/course-header' import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const courseTypeState = object({ title: string(), - content: editorContent(EditorPluginType.Course), + content: child({ plugin: EditorPluginType.Course }), }) export type CourseTypePluginState = typeof courseTypeState diff --git a/packages/editor/src/plugins/serlo-template-plugins/event.tsx b/packages/editor/src/plugins/serlo-template-plugins/event.tsx index a15fc280c0..ad3b106c57 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/event.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/event.tsx @@ -1,16 +1,17 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, string, } from '@editor/plugin' +import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const eventTypeState = object({ title: string(), - content: editorContent(), + content: child({ plugin: EditorPluginType.Rows }), }) export type EventTypePluginState = typeof eventTypeState diff --git a/packages/editor/src/plugins/serlo-template-plugins/exercise-group/text-exercise-group.tsx b/packages/editor/src/plugins/serlo-template-plugins/exercise-group/text-exercise-group.tsx index 429ed2a03e..077575b5d1 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/exercise-group/text-exercise-group.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/exercise-group/text-exercise-group.tsx @@ -1,4 +1,5 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, @@ -7,12 +8,10 @@ import { import { selectStaticDocument, useStore } from '@editor/store' import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from '../common/common' - // text-exercises also include interactive exercises, we keep the naming to avoid db-migration export const textExerciseGroupTypeState = object({ - content: editorContent(EditorPluginType.ExerciseGroup), + content: child({ plugin: EditorPluginType.ExerciseGroup }), }) export type TextExerciseGroupTypePluginState = typeof textExerciseGroupTypeState diff --git a/packages/editor/src/plugins/serlo-template-plugins/page.tsx b/packages/editor/src/plugins/serlo-template-plugins/page.tsx index 80db4e6ff2..71ed4b60f7 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/page.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/page.tsx @@ -1,11 +1,17 @@ -import { EditorPlugin, EditorPluginProps, object, string } from '@editor/plugin' +import { + child, + EditorPlugin, + EditorPluginProps, + object, + string, +} from '@editor/plugin' +import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const pageTypeState = object({ title: string(), - content: editorContent(), + content: child({ plugin: EditorPluginType.Rows }), }) export type PageTypePluginState = typeof pageTypeState diff --git a/packages/editor/src/plugins/serlo-template-plugins/taxonomy.tsx b/packages/editor/src/plugins/serlo-template-plugins/taxonomy.tsx index dbe6d7018a..842d320263 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/taxonomy.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/taxonomy.tsx @@ -4,9 +4,10 @@ import { object, string, number, + child, } from '@editor/plugin' +import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const taxonomyTypeState = object({ @@ -15,7 +16,7 @@ export const taxonomyTypeState = object({ }), parent: number(), position: number(), - description: editorContent(), + content: child({ plugin: EditorPluginType.Rows }), }) export type TaxonomyTypePluginState = typeof taxonomyTypeState @@ -27,7 +28,7 @@ export const taxonomyTypePlugin: EditorPlugin = { } function TaxonomyTypeEditor(props: EditorPluginProps) { - const { term, description } = props.state + const { term, content } = props.state return ( <> @@ -35,7 +36,7 @@ function TaxonomyTypeEditor(props: EditorPluginProps) { - {description.render()} + {content.render()} ) } diff --git a/packages/editor/src/plugins/serlo-template-plugins/text-exercise.tsx b/packages/editor/src/plugins/serlo-template-plugins/text-exercise.tsx index 56195202fb..9ff468e24a 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/text-exercise.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/text-exercise.tsx @@ -1,4 +1,5 @@ import { + child, object, type EditorPlugin, type EditorPluginProps, @@ -7,10 +8,8 @@ import { import { selectStaticDocument, useStore } from '@editor/store' import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' - export const textExerciseTypeState = object({ - content: editorContent(EditorPluginType.Exercise), + content: child({ plugin: EditorPluginType.Exercise }), }) export type TextExerciseTypePluginState = typeof textExerciseTypeState diff --git a/packages/editor/src/plugins/serlo-template-plugins/user.tsx b/packages/editor/src/plugins/serlo-template-plugins/user.tsx index 44bb75f812..3cc1e4ddce 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/user.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/user.tsx @@ -1,12 +1,14 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, } from '@editor/plugin' +import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' - -export const userTypeState = object({ description: editorContent() }) +export const userTypeState = object({ + content: child({ plugin: EditorPluginType.Rows }), +}) export type UserTypePluginState = typeof userTypeState @@ -17,5 +19,5 @@ export const userTypePlugin: EditorPlugin = { } function UserTypeEditor({ state }: EditorPluginProps) { - return <>{state.description.render()} + return state.content.render() } diff --git a/packages/editor/src/plugins/serlo-template-plugins/video.tsx b/packages/editor/src/plugins/serlo-template-plugins/video.tsx index e4260ac505..09f49692a6 100644 --- a/packages/editor/src/plugins/serlo-template-plugins/video.tsx +++ b/packages/editor/src/plugins/serlo-template-plugins/video.tsx @@ -1,4 +1,5 @@ import { + child, type EditorPlugin, type EditorPluginProps, object, @@ -6,14 +7,14 @@ import { upload, } from '@editor/plugin' import { videoPlugin } from '@editor/plugins/video' +import { EditorPluginType } from '@editor/types/editor-plugin-type' -import { editorContent } from './common/common' import { EntityTitleInput } from './common/entity-title-input' export const videoTypeState = object({ - content: upload(''), + url: upload(''), title: string(), - description: editorContent(), + content: child({ plugin: EditorPluginType.Rows }), }) export type VideoTypePluginState = typeof videoTypeState @@ -25,18 +26,15 @@ export const videoTypePlugin: EditorPlugin = { } function VideoTypeEditor(props: EditorPluginProps) { - const { title, content, description } = props.state + const { title, url, content } = props.state return ( <>
- - {description.render()} + + {content.render()}
)