Skip to content

Commit

Permalink
feat: advanced field groups
Browse files Browse the repository at this point in the history
  • Loading branch information
hashtagnulla committed May 28, 2024
1 parent 2d65bfa commit 7804602
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 117 deletions.
101 changes: 77 additions & 24 deletions packages/sn-controls-react/src/viewcontrols/browse-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import React, { createElement, ReactElement, useEffect, useState } from 'react'
import { FieldLocalization } from '../fieldcontrols/localization'
import { isFullWidthField } from '../helpers'
import { reactControlMapper } from '../react-control-mapper'
import { AdvancedFieldGroup, DEFAULT_GROUP_KEY } from './edit-view'

/**
* Interface for BrowseView properties
Expand Down Expand Up @@ -72,8 +73,8 @@ export const BrowseView: React.FC<BrowseViewProps> = (props) => {
const controlMapper = props.controlMapper || reactControlMapper(props.repository)
const [schema, setSchema] = useState(controlMapper.getFullSchemaForContentType(props.content.Type, 'browse'))
const classes = useStyles(props)
const [advancedFields, setAdvancedFields] = useState<string[]>([])
const [showAdvancedFields, setShowAdvancedFields] = useState<boolean>(false)
const [advancedFields, setAdvancedFields] = useState<AdvancedFieldGroup[]>([])
const [advancedFieldStateGroup, setAdvancedFieldStateGroup] = useState<Array<{ key: string; isOpened: boolean }>>([])
const repository = useRepository()

useEffect(() => {
Expand All @@ -85,11 +86,38 @@ export const BrowseView: React.FC<BrowseViewProps> = (props) => {

useEffect(() => {
if (schema) {
const filteredFields = schema.fieldMappings
.filter((s) => s.fieldSettings.VisibleBrowse === FieldVisibility.Advanced)
.map((s) => s.fieldSettings.Name)
const groups: AdvancedFieldGroup[] = [
{
key: DEFAULT_GROUP_KEY,
fields: [],
},
]

setAdvancedFields(filteredFields)
schema.fieldMappings.forEach((e) => {
if (e.fieldSettings.VisibleBrowse === FieldVisibility.Advanced) {
const category = e.fieldSettings.Customization?.Categories?.split(' ')[0]
if (category) {
const group = groups.find((g) => g.key === category)
if (group) {
group.fields.push(e)
} else {
groups.push({
key: category,
fields: [e],
})
}
} else {
groups.find((g) => g.key === DEFAULT_GROUP_KEY)?.fields.push(e)
}
}
})

setAdvancedFieldStateGroup(
groups.map((g) => {
return { key: g.key, isOpened: false }
}),
)
setAdvancedFields(groups)
}
}, [schema])

Expand Down Expand Up @@ -125,6 +153,12 @@ export const BrowseView: React.FC<BrowseViewProps> = (props) => {
)
}

const toggleAdvancedFieldGroup = (key: string) => {
setAdvancedFieldStateGroup((prevItems) =>
prevItems.map((item) => (item.key === key ? { ...item, isOpened: !item.isOpened } : item)),
)
}

return (
<>
{props.renderTitle ? (
Expand All @@ -136,28 +170,47 @@ export const BrowseView: React.FC<BrowseViewProps> = (props) => {
)}
<Grid container={true} spacing={2} className={classes.grid}>
{schema.fieldMappings
.filter((i) => !advancedFields.includes(i.fieldSettings.Name))
.filter(
(i) =>
!advancedFields
.flatMap((g) => g.fields)
.map((g) => g.fieldSettings.Name)
.includes(i.fieldSettings.Name),
)
.sort((item1, item2) => (item2.fieldSettings.FieldIndex || 0) - (item1.fieldSettings.FieldIndex || 0))
.map((field) => renderField(field))}

{advancedFields.length > 0 && (
<Box data-test="advanced-field-container">
<Box className={classes.divider} />
<Box className={classes.advancedFieldContainer}>
<Box className={classes.advancedFieldBox}>
<span>{props.localization?.advancedFields ?? 'Advanced fields'}</span>
<IconButton onClick={() => setShowAdvancedFields(!showAdvancedFields)}>
{showAdvancedFields ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
</IconButton>
<Box className={classes.advancedFieldContainer} data-test="advanced-field-container">
{advancedFields.map((group, index) =>
group.fields.length > 0 ? (
<Box key={index} data-test="group-container">
<Box className={classes.divider} />
<Box data-test="group-header">
<Box className={classes.advancedFieldBox}>
<span data-test="advanced-field-group-title">{`${
props.localization?.advancedFields ?? 'Advanced fields'
}${group.key === DEFAULT_GROUP_KEY ? '' : ` - ${group.key}`}`}</span>
<IconButton onClick={() => toggleAdvancedFieldGroup(group.key)}>
{advancedFieldStateGroup.find((g) => g.key === group.key)?.isOpened ? (
<KeyboardArrowUp />
) : (
<KeyboardArrowDown />
)}
</IconButton>
</Box>
</Box>
{advancedFieldStateGroup.find((g) => g.key === group.key)?.isOpened &&
group.fields
.sort(
(item1, item2) => (item2.fieldSettings.FieldIndex || 0) - (item1.fieldSettings.FieldIndex || 0),
)
.map((field) => renderField(field))}
</Box>
</Box>
{showAdvancedFields &&
schema.fieldMappings
.filter((i) => advancedFields.includes(i.fieldSettings.Name))
.sort((item1, item2) => (item2.fieldSettings.FieldIndex || 0) - (item1.fieldSettings.FieldIndex || 0))
.map((field) => renderField(field))}
</Box>
)}
) : (
<></>
),
)}
</Box>
</Grid>

<div className={classes.actionButtonWrapper}>
Expand Down
112 changes: 86 additions & 26 deletions packages/sn-controls-react/src/viewcontrols/edit-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ const useStyles = makeStyles((theme: Theme) => {
})
})

export interface AdvancedFieldGroup {
key: string
fields: Array<{ fieldSettings: FieldSetting; actionName: ActionName; controlType: any }>
}

export const DEFAULT_GROUP_KEY = 'DEFAULT_GROUP_KEY'

type EditViewClassKey = Partial<ReturnType<typeof useStyles>>

/**
Expand All @@ -92,8 +99,8 @@ export const EditView: React.FC<EditViewProps> = (props) => {
const actionName = props.actionName || 'edit'
const controlMapper = props.controlMapper || reactControlMapper(props.repository)
const [schema, setSchema] = useState(controlMapper.getFullSchemaForContentType(props.contentTypeName, actionName))
const [advancedFields, setAdvancedFields] = useState<string[]>([])
const [showAdvancedFields, setShowAdvancedFields] = useState<boolean>(false)
const [advancedFields, setAdvancedFields] = useState<AdvancedFieldGroup[]>([])
const [advancedFieldStateGroup, setAdvancedFieldStateGroup] = useState<Array<{ key: string; isOpened: boolean }>>([])
const contentRef = useRef({})
const [content, setContent] = useState(contentRef.current)
contentRef.current = content
Expand Down Expand Up @@ -122,13 +129,41 @@ export const EditView: React.FC<EditViewProps> = (props) => {

useEffect(() => {
if (actionName && schema) {
const filteredFields = schema.fieldMappings
.filter((s) =>
actionName === 'edit' ? s.fieldSettings.VisibleEdit : s.fieldSettings.VisibleNew === FieldVisibility.Advanced,
)
.map((s) => s.fieldSettings.Name)
const groups: AdvancedFieldGroup[] = [
{
key: DEFAULT_GROUP_KEY,
fields: [],
},
]

schema.fieldMappings.forEach((e) => {
if (
(actionName === 'edit' && e.fieldSettings.VisibleEdit === FieldVisibility.Advanced) ||
(actionName === 'new' && e.fieldSettings.VisibleNew === FieldVisibility.Advanced)
) {
const category = e.fieldSettings.Customization?.Categories?.split(' ')[0]
if (category) {
const group = groups.find((g) => g.key === category)
if (group) {
group.fields.push(e)
} else {
groups.push({
key: category,
fields: [e],
})
}
} else {
groups.find((g) => g.key === DEFAULT_GROUP_KEY)?.fields.push(e)
}
}
})

setAdvancedFields(filteredFields)
setAdvancedFieldStateGroup(
groups.map((g) => {
return { key: g.key, isOpened: false }
}),
)
setAdvancedFields(groups)
}
}, [actionName, schema])

Expand Down Expand Up @@ -178,6 +213,12 @@ export const EditView: React.FC<EditViewProps> = (props) => {
)
}

const toggleAdvancedFieldGroup = (key: string) => {
setAdvancedFieldStateGroup((prevItems) =>
prevItems.map((item) => (item.key === key ? { ...item, isOpened: !item.isOpened } : item)),
)
}

return (
<>
{props.showTitle &&
Expand All @@ -196,28 +237,47 @@ export const EditView: React.FC<EditViewProps> = (props) => {
spacing={2}
className={classes.grid}>
{schema.fieldMappings
.filter((i) => !advancedFields.includes(i.fieldSettings.Name))
.filter(
(i) =>
!advancedFields
.flatMap((g) => g.fields)
.map((g) => g.fieldSettings.Name)
.includes(i.fieldSettings.Name),
)
.sort((item1, item2) => (item2.fieldSettings.FieldIndex || 0) - (item1.fieldSettings.FieldIndex || 0))
.map((field) => renderField(field))}

{advancedFields.length > 0 && (
<Box data-test="advanced-field-container">
<Box className={classes.divider} />
<Box className={classes.advancedFieldContainer}>
<Box className={classes.advancedFieldBox}>
<span>{props.localization?.advancedFields ?? 'Advanced fields'}</span>
<IconButton onClick={() => setShowAdvancedFields(!showAdvancedFields)}>
{showAdvancedFields ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
</IconButton>
<Box className={classes.advancedFieldContainer}>
{advancedFields.map((group, index) =>
group.fields.length > 0 ? (
<Box key={index} data-test="group-container">
<Box className={classes.divider} />
<Box data-test="group-header">
<Box className={classes.advancedFieldBox}>
<span data-test="advanced-field-group-title">{`${
props.localization?.advancedFields ?? 'Advanced fields'
}${group.key === DEFAULT_GROUP_KEY ? '' : ` - ${group.key}`}`}</span>
<IconButton onClick={() => toggleAdvancedFieldGroup(group.key)}>
{advancedFieldStateGroup.find((g) => g.key === group.key)?.isOpened ? (
<KeyboardArrowUp />
) : (
<KeyboardArrowDown />
)}
</IconButton>
</Box>
</Box>
{advancedFieldStateGroup.find((g) => g.key === group.key)?.isOpened &&
group.fields
.sort(
(item1, item2) => (item2.fieldSettings.FieldIndex || 0) - (item1.fieldSettings.FieldIndex || 0),
)
.map((field) => renderField(field))}
</Box>
</Box>
{showAdvancedFields &&
schema.fieldMappings
.filter((i) => advancedFields.includes(i.fieldSettings.Name))
.sort((item1, item2) => (item2.fieldSettings.FieldIndex || 0) - (item1.fieldSettings.FieldIndex || 0))
.map((field) => renderField(field))}
</Box>
)}
) : (
<></>
),
)}
</Box>
</Grid>
<div className={classes.actionButtonWrapper}>
<MediaQuery minDeviceWidth={700}>
Expand Down
32 changes: 32 additions & 0 deletions packages/sn-controls-react/test/__mocks__/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,38 @@ export const schema = [
VisibleEdit: FieldSettings.FieldVisibility.Advanced,
VisibleNew: FieldSettings.FieldVisibility.Advanced,
} as FieldSettings.DateTimeFieldSetting,
{
Type: 'DateTimeFieldSetting',
DateTimeMode: FieldSettings.DateTimeMode.DateAndTime,
Name: 'Advanced3',
FieldClassName: 'SenseNet.ContentRepository.Fields.DateTimeField',
DisplayName: 'Advanced field #3',
Description: 'Content was last modified on this date.',
ReadOnly: false,
Compulsory: false,
VisibleBrowse: FieldSettings.FieldVisibility.Advanced,
VisibleEdit: FieldSettings.FieldVisibility.Advanced,
VisibleNew: FieldSettings.FieldVisibility.Advanced,
Customization: {
Categories: 'Group1',
},
} as FieldSettings.DateTimeFieldSetting,
{
Type: 'DateTimeFieldSetting',
DateTimeMode: FieldSettings.DateTimeMode.DateAndTime,
Name: 'Advanced4',
FieldClassName: 'SenseNet.ContentRepository.Fields.DateTimeField',
DisplayName: 'Advanced field #4',
Description: 'Content was last modified on this date.',
ReadOnly: false,
Compulsory: false,
VisibleBrowse: FieldSettings.FieldVisibility.Advanced,
VisibleEdit: FieldSettings.FieldVisibility.Advanced,
VisibleNew: FieldSettings.FieldVisibility.Advanced,
Customization: {
Categories: 'Group2',
},
} as FieldSettings.DateTimeFieldSetting,
],
},
]
Loading

0 comments on commit 7804602

Please sign in to comment.