From d115a48e49c452dfc3bedfc80e2cba1a646319b5 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Thu, 9 May 2024 19:03:30 +0530 Subject: [PATCH 1/2] [CMG-103] - UI for Mapping with group field --- ui/src/cmsData/login.json | 2 +- ui/src/components/AccountPage/index.tsx | 5 +- .../ContentMapper/contentMapper.interface.ts | 1 + ui/src/components/ContentMapper/index.tsx | 12 +- ui/src/components/SchemaModal/index.scss | 81 ++++++++- ui/src/components/SchemaModal/index.tsx | 166 +++++++++++++++--- 6 files changed, 235 insertions(+), 32 deletions(-) diff --git a/ui/src/cmsData/login.json b/ui/src/cmsData/login.json index afbe99fa..0c6bd9df 100644 --- a/ui/src/cmsData/login.json +++ b/ui/src/cmsData/login.json @@ -3,7 +3,7 @@ "locale": "en-us", "uid": "blt058427c4131df78a", "_in_progress": false, - "copyrightText": "© 2023-2024 Contentstack Inc. All rights reserved.", + "copyrightText": "Contentstack Inc. All rights reserved.", "created_at": "2024-02-22T11:20:53.435Z", "created_by": "bltb317ebe35429ebe6", "heading": "Stacks Not Suites", diff --git a/ui/src/components/AccountPage/index.tsx b/ui/src/components/AccountPage/index.tsx index a5a4d447..4c902fd3 100644 --- a/ui/src/components/AccountPage/index.tsx +++ b/ui/src/components/AccountPage/index.tsx @@ -10,6 +10,9 @@ import './index.scss'; const AccountPage = (props: AccountObj): JSX.Element => { const { heading, subtitle, copyrightText } = props.data; + const currentYear = new Date().getFullYear(); + const previousYear = currentYear - 1 + return ( // eslint-disable-next-line react/no-unknown-property
@@ -33,7 +36,7 @@ const AccountPage = (props: AccountObj): JSX.Element => {
{props.children}
-

{copyrightText}

+

{`© ${previousYear}-${currentYear} ${copyrightText}`}

); diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index be0a6824..77287cd1 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -47,6 +47,7 @@ export interface ContentType { export interface FieldMapType { ContentstackFieldType: string; + child?: FieldMapType[] | undefined; backupFieldType: string; contentstackField: string; contentstackFieldUid: string; diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 4435f6fd..ffd9b51a 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -140,6 +140,8 @@ const ContentMapper = () => { const [searchContentType, setSearchContentType] = useState(''); + const [selectedFields, setSelectedFields] = useState([]); + /** ALL HOOKS Here */ const { projectId = '' } = useParams(); const navigate = useNavigate(); @@ -387,6 +389,7 @@ const ContentMapper = () => { interface UidMap { [key: string]: boolean; } + const rowIds = tableData.reduce((acc, item) => { acc[item?.id] = true; return acc; @@ -474,7 +477,7 @@ const ContentMapper = () => { maxWidth="290px" isClearable={false} options={option} - // isDisabled={data?.otherCmsField === 'title' || data?.otherCmsField === 'url'} + isDisabled={data?.ContentstackFieldType === "group"} /> { selectedContentType?.otherCmsUid && OtherContentType?.label ) { + setcontentTypeMapped((prevSelected) => ({ ...prevSelected, [otherCmsTitle]: OtherContentType?.label @@ -867,10 +871,11 @@ const ContentMapper = () => { { ), showExportCta: true }} - rowDisableProp={{ key: '_invalid', value: true }} /> diff --git a/ui/src/components/SchemaModal/index.scss b/ui/src/components/SchemaModal/index.scss index 2d608fc6..27d53d8e 100644 --- a/ui/src/components/SchemaModal/index.scss +++ b/ui/src/components/SchemaModal/index.scss @@ -1,16 +1,20 @@ @import '../../scss/variables'; +.schema { + min-height: 290px; +} .entries-outline { + margin-left: 0.8rem; ul { padding: 0.625rem; padding-bottom: 0.3125rem; padding-top: 0; transition: opacity 0.2s linear; li { - color: #475161; + color: $color-font-base; cursor: pointer; - font-size: 1rem; - font-weight: 500; + font-size: $size-font-large; + font-weight: $font-weight-medium; padding: 0; white-space: nowrap; .iconsholder { @@ -27,16 +31,56 @@ path { stroke: $color-brand-primary-base; } + &.chevron { + path { + fill: $color-brand-primary-base; + stroke: $color-brand-primary-base; + } + } } } } + .icons { + * { + pointer-events: none; + stroke: $color-font-active; + } + &.nested { + margin-left: -0.9375rem; + } + } + &.active { + .icons { + svg { + path { + stroke: $color-brand-primary-base; + } + &.chevron { + path { + fill: $color-brand-primary-base; + stroke: $color-brand-primary-base; + } + } + } + } + & > .title { + color: $color-brand-primary-base; + font-weight: $font-weight-semi-bold; + } + } } .title { - color: #475161; - font-weight: 400; + color: $color-font-base; + font-size: $size-font-large; + font-weight: $font-weight-regular; + line-height: $line-height-reset!important; opacity: 1; + overflow: hidden; + padding: 0.625rem 0; + text-overflow: ellipsis; text-transform: capitalize; transition: opacity 0.5s linear, width 300ms linear; + white-space: nowrap; width: 12.5rem; } .icons { @@ -45,9 +89,34 @@ justify-content: flex-start; padding: 0.625rem 0; svg { - margin-right: 0.625rem; + margin-right: 0.375rem; + &.field-icon { + max-width: 12px; + } } } + .chevron { + display: inline-block; + transition: all 0.3s linear; + &.close { + transform: rotate(-90deg); + } + } + & > ul { + padding-left: 0.125rem; + & > li { + & > ul { + padding-left: 1.5625rem; + } + } + } + } + &.close { + height: 0 !important; + opacity: 0 !important; + overflow: hidden; + padding: 0 0.625rem; + transition: opacity 0.8s linear; } } } diff --git a/ui/src/components/SchemaModal/index.tsx b/ui/src/components/SchemaModal/index.tsx index 84335857..0905c32f 100644 --- a/ui/src/components/SchemaModal/index.tsx +++ b/ui/src/components/SchemaModal/index.tsx @@ -9,6 +9,7 @@ import { FieldMapType } from '../ContentMapper/contentMapper.interface'; // Styles import './index.scss'; +// Function for get icons const getTopLevelIcons = (field: FieldMapType) => { const icons: Icons = { title: 'StarSmall', @@ -61,7 +62,7 @@ const getTopLevelIcons = (field: FieldMapType) => { return icons['rte']; } - if (field?.ContentstackFieldType === 'JSON Rich Text Editor') { + if (field?.ContentstackFieldType === 'JSON Rich Text Editor' || field?.ContentstackFieldType === 'json') { return icons['jsonRte']; } @@ -85,31 +86,156 @@ const getTopLevelIcons = (field: FieldMapType) => { }; const TreeView = ({ schema = [] }: schemaType) => { - const [list, setList] = useState([]); + const [nestedList, setNestedList] = useState([]); useEffect(() => { - setList(schema); + let groupId = '' + const data: FieldMapType[] = [] + schema?.forEach((field) => { + if (field?.ContentstackFieldType === "group") { + groupId = field.uid + data?.push({...field, child: []}) + } + else{ + if(field?.uid?.startsWith(groupId+'.')){ + const obj = data[data?.length - 1] + if(Object.prototype.hasOwnProperty.call(obj, 'child')){ + obj?.child?.push(field) + } + else{ + obj.child = [field] + } + } + else{ + data.push({...field, child: []}) + } + } + }); + setNestedList(data); }, [schema]); + // Check if schema is nested + const hasNestedValue = (field: FieldMapType) => field && field?.child && field?.child?.length > 0; + + // Remove Group name from its child + const getChildFieldName = (text?: string, groupName?: string) => { + if (text?.startsWith(groupName+' > ')) { + return text?.replace(groupName+' > ', '') + } + }; + + const handleClick = (event: React.MouseEvent) => { + if (document?.querySelector('.iconsholder.active')) { + document?.querySelector('.iconsholder.active') + ?.classList.remove('active'); + } + if (event?.target instanceof HTMLElement) { + if (event?.target?.classList.contains('icons')) { + if (event?.target?.parentElement?.parentElement?.querySelector('ul')) { + event?.target?.parentElement?.parentElement + ?.querySelector('ul') + ?.classList.toggle('close'); + } + + if (event?.target?.querySelector('.chevron')) { + event?.target?.querySelector('.chevron')?.classList.toggle('close'); + } + } + + event?.target?.parentElement?.classList.add('active'); + } + }; + + const generateNestedOutline = (item: FieldMapType, index: number) => { + return ( +
    0 ? '' : 'close'} + > + {item?.child?.map((field: FieldMapType, nestedIndex: number) => { + let fieldname = ''; + if (field?.uid) { + fieldname = field?.uid?.replace(/\.+/g, '_'); + } + return ( +
  • +
    ) => { + e.preventDefault(); + e.stopPropagation(); + handleClick(e); + }} + className={`iconsholder`} + > + + {hasNestedValue(field) && ( + + )} + + + + {getChildFieldName(field?.otherCmsField, item?.otherCmsField)} + +
    + + {hasNestedValue(field) && + generateNestedOutline(field, nestedIndex)} +
  • + ) + })} +
+ ); + }; + return (
-
-
- {list?.length > 0 && ( -
    - {list?.map((item: FieldMapType) => ( -
  • -
    - - - - {item?.otherCmsField} -
    -
  • - ))} -
- )} -
+
+ {nestedList?.length > 0 && ( +
    + {nestedList?.map((item: FieldMapType, index: number) => { + let outlineName = ""; + if (item.uid) { + outlineName = item?.uid?.replace(/\.+/g, "_"); + } + const hasNested = hasNestedValue(item); + + return ( +
  • +
    ) => { + e.preventDefault(); + e.stopPropagation(); + handleClick(e); + }} + > + { + document + ?.querySelector('.PageLayout__leftSidebar') + ?.classList.add('hovered'); + }} + > + {hasNested && ( + + )} + + + {item?.otherCmsField} +
    + {hasNested && generateNestedOutline(item, index)} +
  • + )})} +
+ )}
); From 1a6e4fb5d1e0ccfd2a4f1a68ac1fb5deeb7917bc Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Fri, 10 May 2024 13:44:14 +0530 Subject: [PATCH 2/2] Code refactored: resolved PR comments --- ui/src/components/AccountPage/index.tsx | 4 ++-- ui/src/components/SchemaModal/index.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/src/components/AccountPage/index.tsx b/ui/src/components/AccountPage/index.tsx index 4c902fd3..5cb8a746 100644 --- a/ui/src/components/AccountPage/index.tsx +++ b/ui/src/components/AccountPage/index.tsx @@ -11,7 +11,7 @@ const AccountPage = (props: AccountObj): JSX.Element => { const { heading, subtitle, copyrightText } = props.data; const currentYear = new Date().getFullYear(); - const previousYear = currentYear - 1 + const previousYear = currentYear - 1; return ( // eslint-disable-next-line react/no-unknown-property @@ -35,7 +35,7 @@ const AccountPage = (props: AccountObj): JSX.Element => {
-
{props.children}
+
{props?.children}

{`© ${previousYear}-${currentYear} ${copyrightText}`}

diff --git a/ui/src/components/SchemaModal/index.tsx b/ui/src/components/SchemaModal/index.tsx index 0905c32f..bfc28be9 100644 --- a/ui/src/components/SchemaModal/index.tsx +++ b/ui/src/components/SchemaModal/index.tsx @@ -78,7 +78,7 @@ const getTopLevelIcons = (field: FieldMapType) => { return icons['reference']; } - if (!field.ContentstackFieldType) { + if (!field?.ContentstackFieldType) { return icons['blocks']; } @@ -93,7 +93,7 @@ const TreeView = ({ schema = [] }: schemaType) => { const data: FieldMapType[] = [] schema?.forEach((field) => { if (field?.ContentstackFieldType === "group") { - groupId = field.uid + groupId = field?.uid data?.push({...field, child: []}) } else{ @@ -197,7 +197,7 @@ const TreeView = ({ schema = [] }: schemaType) => {
    {nestedList?.map((item: FieldMapType, index: number) => { let outlineName = ""; - if (item.uid) { + if (item?.uid) { outlineName = item?.uid?.replace(/\.+/g, "_"); } const hasNested = hasNestedValue(item);