Skip to content

1461 document types #1613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: 1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7983721
first document types set up
xIrusux Jun 12, 2025
e06a9ad
Merge branch '1.x' of github.com:pimcore/studio-ui-bundle into 1461-d…
xIrusux Jun 12, 2025
c27d064
adding table plus work on api calls
xIrusux Jun 12, 2025
74df231
Merge branch '1.x' of github.com:pimcore/studio-ui-bundle into 1461-d…
xIrusux Jun 16, 2025
8cbf35c
complete table
xIrusux Jun 16, 2025
df034d9
translations plus column sizes
xIrusux Jun 16, 2025
24837f1
format dateCell
xIrusux Jun 16, 2025
a5d2e69
add date cell
xIrusux Jun 17, 2025
ccf975e
use document config hook
xIrusux Jun 17, 2025
a4c10c9
complete doc config api calls and usage
xIrusux Jun 17, 2025
6268323
complete doc select via given config
xIrusux Jun 17, 2025
ac9f1f9
clean
xIrusux Jun 17, 2025
d35a251
errorHandling and staticGenerator checkbox fix
xIrusux Jun 17, 2025
144711a
rtk
xIrusux Jun 17, 2025
6b34796
refresh
xIrusux Jun 17, 2025
3f71740
fix rtk refreshing
xIrusux Jun 17, 2025
349cf8a
fix
xIrusux Jun 17, 2025
b353e1f
Apply latest automatic api client updates
xIrusux Jun 17, 2025
bcf1f0e
fix sonarqube
xIrusux Jun 18, 2025
49e3787
Merge branch '1461-document-types' of github.com:pimcore/studio-ui-bu…
xIrusux Jun 18, 2025
b9aeb31
fix sonarqube
xIrusux Jun 18, 2025
380659f
table styling fix
xIrusux Jun 18, 2025
0daeda9
rtk refetch changes
xIrusux Jun 18, 2025
c2c06d6
build fix
xIrusux Jun 18, 2025
8f42a11
fix rtk once and for all
xIrusux Jun 18, 2025
be2a009
the gift that keeps on giving
xIrusux Jun 18, 2025
baeb5d9
new icon
xIrusux Jun 18, 2025
29c70b5
numbers
xIrusux Jun 18, 2025
21919b5
clean
xIrusux Jun 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/build/api/docs.jsonopenapi.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions assets/js/src/core/app/api/pimcore/tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const tagNames = {
DOCUMENT: 'DOCUMENT',
DOCUMENT_DETAIL: 'DOCUMENT_DETAIL',
DOCUMENT_TREE: 'DOCUMENT_TREE',
DOCUMENT_TYPES: 'DOCUMENT_TYPES',
WORKFLOW: 'WORKFLOW',
VERSIONS: 'VERSION',
PROPERTIES: 'PROPERTIES',
Expand Down Expand Up @@ -74,6 +75,7 @@ export const providingTags = {
DATA_OBJECT_GRID_ID: (id: number) => [tagNames.DATA_OBJECT, { type: tagNames.DATA_OBJECT_GRID, id }],
DOCUMENT_DETAIL: () => [tagNames.DOCUMENT, tagNames.DOCUMENT_DETAIL],
DOCUMENT_DETAIL_ID: (id: number) => [tagNames.DOCUMENT, { type: tagNames.DOCUMENT_DETAIL, id }],
DOCUMENT_TYPES: () => [tagNames.DOCUMENT_TYPES],
DOCUMENT_TREE: () => [tagNames.DOCUMENT, tagNames.DOCUMENT_TREE],
DOCUMENT_TREE_ID: (id: number) => [tagNames.DOCUMENT, { type: tagNames.DOCUMENT_TREE, id }],
ELEMENT_DEPENDENCIES: (elementType: ElementType, id: number) => [getElementDetailTag(elementType, id), getElementSpecificTag(tagNames.DEPENDENCIES, elementType, id)],
Expand Down Expand Up @@ -116,6 +118,7 @@ export const invalidatingTags = {
DOCUMENT: () => [tagNames.DOCUMENT],
DOCUMENT_DETAIL: () => [tagNames.DOCUMENT_DETAIL],
DOCUMENT_DETAIL_ID: (id: number) => [{ type: tagNames.DOCUMENT_DETAIL, id }, elementUnspecificDataTag],
DOCUMENT_TYPES: () => [tagNames.DOCUMENT_TYPES],
DOCUMENT_TREE: () => [tagNames.DOCUMENT_TREE],
DOCUMENT_TREE_ID: (id: number) => [{ type: tagNames.DOCUMENT_TREE, id }],
ELEMENT_DEPENDENCIES: (elementType: ElementType, id: number) => [getElementSpecificTag(tagNames.DEPENDENCIES, elementType, id)],
Expand Down
3 changes: 3 additions & 0 deletions assets/js/src/core/assets/icons/document-types.inline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/js/src/core/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import '@Pimcore/modules/user'
import '@Pimcore/modules/tags'
import '@Pimcore/modules/predefined-properties'
import '@Pimcore/modules/notes-and-events'
import '@Pimcore/modules/document-types'
import '@Pimcore/modules/open-element'
import '@Pimcore/modules/wysiwyg'
import 'flexlayout-react/style/light.css'
Expand Down
1 change: 1 addition & 0 deletions assets/js/src/core/modules/auth/enums/user-permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
export enum UserPermission {
NotesAndEvents = 'notes_events',
Documents = 'documents',
DocumentTypes = 'document_types',
Objects = 'objects',
Assets = 'assets',
TagsConfiguration = 'tags_configuration',
Expand Down
130 changes: 130 additions & 0 deletions assets/js/src/core/modules/document-types/document-types-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import React, { useEffect, useState } from 'react'
import { t } from 'i18next'
import trackError, { ApiError } from '../app/error-handler'
import { useAppDispatch } from '@sdk/app'
import { useDocumentDocTypeListQuery } from '../document/document-api-slice-enhanced'
import { DocumentTypeRow, useDocumentType } from './hooks/use-document-type'
import { useDocumentConfig } from './hooks/use-document-config'
import { ContentLayout } from '@Pimcore/components/content-layout/content-layout'
import { Toolbar } from '@Pimcore/components/toolbar/toolbar'
import { Flex } from '@Pimcore/components/flex/flex'
import { Title } from '@Pimcore/components/title/title'
import { Content } from '@Pimcore/components/content/content'
import { Box, IconButton, IconTextButton } from '@sdk/components'
import { invalidatingTags } from '@Pimcore/app/api/pimcore/tags'
import { uuid } from '@sdk/utils'
import { isUndefined } from 'lodash'
import { Table } from './table/table'
import { api } from '@sdk/api/documents'


export const DocumentTypesContainer = (): React.JSX.Element => {
const dispatch = useAppDispatch()
const { createNewDocumentType, createLoading } = useDocumentType()
const config = useDocumentConfig()

const { data, isLoading: documentTypesLoading, isFetching: documentTypesFetching, isError, error } = useDocumentDocTypeListQuery({})

const [documentTypeRows, setDocumentTypeRows] = useState<DocumentTypeRow[]>([])

const documentTypes = data?.items ?? [];

const sortedRows = [...documentTypeRows].sort((a, b) => {
const dateA = a.creationDate ?? 0
const dateB = b.creationDate ?? 0
return dateB - dateA
})
useEffect(() => {
if (!isUndefined(documentTypes)) {
setDocumentTypeRows(
documentTypes.map(item => ({ ...item, rowId: uuid() }))
)
}
}, [documentTypes])

const onCreateDocumentType = async (): Promise<void> => {
const { success, data } = await createNewDocumentType()
if (success && data !== undefined) {
setDocumentTypeRows(prev =>
[
{ ...data, rowId: uuid() },
...prev
]
)
}
}

useEffect(() => {
if (isError) {
trackError(new ApiError(error))
}
}, [isError])

return (
<ContentLayout
renderToolbar={
<Toolbar theme="secondary">
<IconButton
disabled={ documentTypesFetching }
icon={ { value: 'refresh' } }
onClick={ () =>
dispatch(
api.util.invalidateTags(
invalidatingTags.DOCUMENT_TYPES()
)
)
}></IconButton>
</Toolbar>}
renderTopBar={
<Toolbar
justify='space-between'
margin={ {
x: 'mini',
y: 'none'
} }
theme='secondary'
>
<Flex gap={ 'small' }>
<Title>{t('widget.document-types')}</Title>
<IconTextButton
disabled={ documentTypesLoading ?? createLoading }
icon={ { value: 'new' } }
loading={ createLoading }
onClick={ onCreateDocumentType }
>{t('document-types.new')}</IconTextButton>
</Flex>
</Toolbar>
}>
<Content
loading={ documentTypesLoading || documentTypesFetching }
margin={ {
x: 'extra-small',
y: 'none'
} }
none={ isUndefined(documentTypes) ?? documentTypes.length === 0 }
>
<Box
margin={ {
x: 'extra-small',
y: 'none'
} }
>
<Table
documentTypeRows={ sortedRows }
setDocumentTypeRows={ setDocumentTypeRows }
config={config}
/> </Box>
</Content>
</ContentLayout>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import { DocType, DocTypeType, DocumentController, DocumentTemplate,} from '@Pimcore/modules/document/document-api-slice.gen'
import { useDocumentAvailableControllersListQuery,useDocumentDocTypeTypeListQuery, useDocumentAvailableTemplatesListQuery} from '@Pimcore/modules/document/document-api-slice-enhanced'
import trackError, { ApiError } from '../../app/error-handler'
import { isUndefined } from 'lodash'
import { useEffect } from 'react'


export type DocumentTypeRow = DocType & { rowId: string }

interface UseDocumentConfigReturn {
controllers: DocumentController[]
templates: DocumentTemplate[]
docTypes: DocTypeType[]
}

export const useDocumentConfig = (): UseDocumentConfigReturn => {
const {data: controllers, isError: isControllerError, error: controllerError } = useDocumentAvailableControllersListQuery()
const {data: templates, isError: isTemplatesError, error: templatesError } = useDocumentAvailableTemplatesListQuery()
const {data: docTypes, isError: isDocTypesError, error: docTypeError} = useDocumentDocTypeTypeListQuery()

useEffect(() => {
if (isControllerError) {
trackError(new ApiError(controllerError))
}
}, [isControllerError])

useEffect(() => {
if (isTemplatesError) {
trackError(new ApiError(templatesError))
}
}, [isTemplatesError])

useEffect(() => {
if (isDocTypesError) {
trackError(new ApiError(docTypeError))
}
}, [isDocTypesError])

return {
controllers: !isUndefined(controllers) ? controllers?.items : [],
templates: !isUndefined(templates) ? templates?.items : [],
docTypes:!isUndefined(docTypes) ? docTypes?.items : [],
}
}
101 changes: 101 additions & 0 deletions assets/js/src/core/modules/document-types/hooks/use-document-type.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import trackError, { GeneralError, ApiError } from '@Pimcore/modules/app/error-handler'
import { DocType, DocTypeUpdate, DocumentDocTypeAddApiArg, useDocumentDocTypeAddMutation, useDocumentDocTypeDeleteMutation, useDocumentDocTypeUpdateByIdMutation } from '@Pimcore/modules/document/document-api-slice.gen'
import { isUndefined } from 'lodash'


export type DocumentTypeRow = DocType & { rowId: string }

interface UseDocumentTypeReturn {
createNewDocumentType: () => Promise<{ success: boolean, data?: DocType }>
createLoading: boolean
deleteDocumentTypeById: (id: string) => Promise<{ success: boolean }>
deleteLoading: boolean
updateDocumentTypeById: (id: string, row: DocumentTypeRow) => Promise<{ success: boolean }>
updateLoading: boolean
}

export const useDocumentType = (): UseDocumentTypeReturn => {
const [createDocumentType, { isLoading: createLoading }] = useDocumentDocTypeAddMutation()
const [deleteDocumentType, { isLoading: deleteLoading }] = useDocumentDocTypeDeleteMutation()
const [updateDocumentType, { isLoading: updateLoading }] = useDocumentDocTypeUpdateByIdMutation()

const dummyDocumentType: DocumentDocTypeAddApiArg = {
docTypeAddParameters: {
name: "New Document Type",
type: "page"}
}
const createNewDocumentType = async (): Promise<{ success: boolean, data?: DocType }> => {
try {
const result = await createDocumentType(dummyDocumentType)

if (!isUndefined(result.error)) {
trackError(new ApiError(result.error))
}

if ('data' in result) {
return { success: true, data: result.data }
}
} catch {
trackError(new GeneralError('Was not able to create DocumentType'))
}
return { success: false }
}

const deleteDocumentTypeById = async (id: string): Promise<{ success: boolean }> => {
try {
const result = await deleteDocumentType({ id })

if (!isUndefined(result.error)) {
trackError(new ApiError(result.error))
}

return { success: 'data' in result }
} catch {
trackError(new GeneralError('Was not able to delete DocumentType'))
return { success: false }
}
}

const toApiDocumentType = (row: DocumentTypeRow): DocTypeUpdate => ({
name: row.name ?? '',
type: row.type ?? '',
group: row.group ?? '',
controller: row.controller ?? '',
template: row.template ?? '',
priority: row.priority ?? 0 ,
staticGeneratorEnabled: row.staticGeneratorEnabled ?? false
})

const updateDocumentTypeById = async (id: string, row: DocumentTypeRow): Promise<{ success: boolean }> => {
try {
const result = await updateDocumentType({ id, docTypeUpdateParameters: toApiDocumentType(row) })

if (!isUndefined(result.error)) {
trackError(new ApiError(result.error))
}
return { success: 'data' in result }
} catch {
trackError(new GeneralError('Was not able to update DocumentType'))
return { success: false }
}
}

return {
createNewDocumentType,
createLoading,
deleteDocumentTypeById,
deleteLoading,
updateDocumentTypeById,
updateLoading
}
}
51 changes: 51 additions & 0 deletions assets/js/src/core/modules/document-types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

import { type WidgetRegistry } from '@Pimcore/modules/widget-manager/services/widget-registry'
import { container } from '@Pimcore/app/depency-injection'
import { serviceIds } from '@Pimcore/app/config/services/service-ids'
import { moduleSystem } from '@Pimcore/app/module-system/module-system'
import { type MainNavRegistry } from '../app/base-layout/main-nav/services/main-nav-registry'
import { NavPermission } from '../perspectives/enums/nav-permission'
import { UserPermission } from '../auth/enums/user-permission'
import { DocumentTypesContainer } from './document-types-container'

moduleSystem.registerModule({
onInit: () => {
const mainNavRegistryService = container.get<MainNavRegistry>(serviceIds.mainNavRegistry)

mainNavRegistryService.registerMainNavItem({
path: 'Settings/Document Types',
label: 'navigation.document-types',
className: 'item-style-modifier',
permission: UserPermission.DocumentTypes,
perspectivePermission: NavPermission.DocumentTypes,
widgetConfig: {
name: 'Document Types',
id: 'document-types',
component: 'document-types',
config: {
translationKey: 'widget.document-types',
icon: {
type: 'name',
value: 'document-types'
}
}
}
})

const widgetRegistryService = container.get<WidgetRegistry>(serviceIds.widgetManager)

widgetRegistryService.registerWidget({
name: 'document-types',
component: DocumentTypesContainer
})
}
})
Loading
Loading