diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 14084c9d..601099be 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -1,5 +1,4 @@ import { Request } from "express"; -import ProjectModel from "../models/project.js"; import { getLogMessage, isEmpty, safePromise } from "../utils/index.js"; import { BadRequestError, @@ -8,8 +7,6 @@ import { import { HTTP_TEXTS, HTTP_CODES, - POPULATE_CONTENT_MAPPER, - POPULATE_FIELD_MAPPING, PROJECT_STATUS, STEPPER_STEPS, } from "../constants/index.js"; @@ -457,14 +454,7 @@ const resetToInitialMapping = async (req: Request) => { }; const resetAllContentTypesMapping = async (projectId: string) => { const srcFunc = "resetAllContentTypesMapping"; - // const projectId = req?.params?.projectId; - - // const projectDetails: any = await ProjectModel.findOne({ - // _id: projectId, - // }).populate({ - // path: POPULATE_CONTENT_MAPPER, - // populate: { path: POPULATE_FIELD_MAPPING }, - // }); + await ProjectModelLowdb.read(); const projectDetails = ProjectModelLowdb.chain .get("projects") @@ -481,15 +471,6 @@ const resetAllContentTypesMapping = async (projectId: string) => { ); throw new BadRequestError(HTTP_TEXTS.CONTENTMAPPER_NOT_FOUND); } - await ContentTypesMapperModelLowdb.read(); - const data = contentMapperId.map((id: any) => { - const getFeildMappingData = ContentTypesMapperModelLowdb.chain - .get("ContentTypesMappers") - .find({ id: id }) - .value(); - return getFeildMappingData; - }); - if (isEmpty(projectDetails)) { logger.error( getLogMessage( @@ -499,48 +480,57 @@ const resetAllContentTypesMapping = async (projectId: string) => { ); throw new BadRequestError(HTTP_TEXTS.PROJECT_NOT_FOUND); } + await ContentTypesMapperModelLowdb.read(); + const cData = contentMapperId.map((cId: any) => { + const contentTypeData = ContentTypesMapperModelLowdb.chain + .get("ContentTypesMappers") + .find({ id: cId }) + .value(); + return contentTypeData; + }); try { - // const contentTypes = projectDetails?.content_mapper; - const contentTypes = data; - const contentTypesbulkWriteOperations: any = await Promise.all( - contentTypes?.map(async (contentType: any) => { - if (!isEmpty(contentType?.fieldMapping)) { + const contentTypes = cData; + for (const contentType of contentTypes) { + if (!isEmpty(contentType.fieldMapping)) { + for (const field of contentType.fieldMapping) { await FieldMapperModel.read(); - (contentType?.fieldMapping || []).forEach((field: any) => { - const fieldIndex = FieldMapperModel.data.field_mapper.findIndex( - (f: any) => f?.id === field?.id - ); - if (fieldIndex > -1) { - FieldMapperModel.update((data: any) => { - data.field_mapper[fieldIndex] = { - ...field, - contentstackField: "", - contentstackFieldUid: "", - ContentstackFieldType: field.backupFieldType, - }; - }); - } + const fieldData = FieldMapperModel.chain + .get("field_mapper") + .find({ id: field }) + .value(); + const fieldIndex = FieldMapperModel.chain + .get("field_mapper") + .findIndex({ id: field }) + .value(); + + if (fieldIndex > -1) { + await FieldMapperModel.update((fData: any) => { + fData.field_mapper[fieldIndex] = { + ...fieldData, + contentstackField: "", + contentstackFieldUid: "", + ContentstackFieldType: fieldData.backupFieldType, + }; + }); + } + } + } + await ContentTypesMapperModelLowdb.read(); + if (!isEmpty(contentType?.id)) { + const cIndex = ContentTypesMapperModelLowdb.chain + .get("ContentTypesMappers") + .findIndex({ id: contentType?.id }) + .value(); + if (cIndex > -1) { + await ContentTypesMapperModelLowdb.update((data: any) => { + data.ContentTypesMappers[cIndex].contentstackTitle = ""; + data.ContentTypesMappers[cIndex].contentstackUid = ""; }); } - return { - updateOne: { - filter: { _id: contentType._id }, - update: { - $set: { - contentstackTitle: "", - contentstackUid: "", - }, - }, - }, - }; - }) - ); + } + } - await ContentTypesMapperModelLowdb.read(); - ContentTypesMapperModelLowdb.update((data: any) => { - data.ContentTypesMappers.push(contentTypesbulkWriteOperations); - }); return projectDetails; } catch (error: any) { logger.error( @@ -559,13 +549,11 @@ const resetAllContentTypesMapping = async (projectId: string) => { }; const removeMapping = async (projectId: string) => { const srcFunc = "removeMapping"; - - const projectDetails: any = await ProjectModel.findOne({ - _id: projectId, - }).populate({ - path: POPULATE_CONTENT_MAPPER, - populate: { path: POPULATE_FIELD_MAPPING }, - }); + await ProjectModelLowdb.read(); + const projectDetails = ProjectModelLowdb.chain + .get("projects") + .find({ id: projectId }) + .value(); if (isEmpty(projectDetails)) { logger.error( @@ -576,40 +564,59 @@ const removeMapping = async (projectId: string) => { ); throw new BadRequestError(HTTP_TEXTS.PROJECT_NOT_FOUND); } + await ContentTypesMapperModelLowdb.read(); + const cData = projectDetails?.content_mapper.map((cId: any) => { + const contentTypeData = ContentTypesMapperModelLowdb.chain + .get("ContentTypesMappers") + .find({ id: cId }) + .value(); + return contentTypeData; + }); try { - const contentTypes = projectDetails?.content_mapper; - + const contentTypes = cData; //TODO: remove fieldMapping ids in ContentTypesMapperModel for each content types - const contentTypesbulkWriteOperations: any = await Promise.all( - contentTypes?.map(async (contentType: any) => { - if (!isEmpty(contentType?.fieldMapping)) { + + for (const contentType of contentTypes) { + if (!isEmpty(contentType.fieldMapping)) { + for (const field of contentType.fieldMapping) { await FieldMapperModel.read(); - (contentType?.fieldMapping || []).forEach((field: any) => { - const fieldIndex = FieldMapperModel.data.field_mapper.findIndex( - (f: any) => f?.id === field?.id - ); - if (fieldIndex > -1) { - FieldMapperModel.update((data: any) => { - delete data.field_mapper[fieldIndex]; - }); - } + const fieldIndex = FieldMapperModel.chain + .get("field_mapper") + .findIndex({ id: field }) + .value(); + if (fieldIndex > -1) { + await FieldMapperModel.update((fData: any) => { + delete fData.field_mapper[fieldIndex]; + }); + } + } + } + await ContentTypesMapperModelLowdb.read(); + if (!isEmpty(contentType?.id)) { + const cIndex = ContentTypesMapperModelLowdb.chain + .get("ContentTypesMappers") + .findIndex({ id: contentType?.id }) + .value(); + if (cIndex > -1) { + await ContentTypesMapperModelLowdb.update((data: any) => { + delete data.ContentTypesMappers[cIndex]; }); } - return { - deleteOne: { - filter: { _id: contentType._id }, - }, - }; - }) - ); + } + } - await ContentTypesMapperModelLowdb.read(); - ContentTypesMapperModelLowdb.update((data: any) => { - data.ContentTypesMappers.push(contentTypesbulkWriteOperations); - }); - projectDetails.content_mapper = []; - await projectDetails?.save(); + await ProjectModelLowdb.read(); + const projectIndex = ProjectModelLowdb.chain + .get("projects") + .findIndex({ id: projectId }) + .value(); + + if (projectIndex > -1) { + ProjectModelLowdb.update((data: any) => { + data.projects[projectIndex].content_mapper = []; + }); + } return projectDetails; } catch (error: any) { logger.error( @@ -626,6 +633,7 @@ const removeMapping = async (projectId: string) => { ); } }; + export const contentMapperService = { putTestData, getContentTypes, diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index 3086c7bd..5e8499d6 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -55,6 +55,7 @@ export interface FieldMapType { otherCmsType: string; uid: string; _id: string; + _invalid?: boolean; } export interface ItemStatus { @@ -88,3 +89,9 @@ export interface ContentTypeList { title: string; schema: []; } + +export interface optionsType { + label?: string; + value?: string; + isDisabled?: boolean; +} diff --git a/ui/src/components/ContentMapper/index.scss b/ui/src/components/ContentMapper/index.scss index 37bf73d0..45bdb543 100644 --- a/ui/src/components/ContentMapper/index.scss +++ b/ui/src/components/ContentMapper/index.scss @@ -18,8 +18,7 @@ } .ct-list { list-style-type: none; - margin-right: 15px; - margin-top: 5px; + margin: 5px 15px 0; li { border: 1px solid transparent; cursor: pointer; @@ -27,9 +26,12 @@ line-height: normal; padding: $space-10 35px; &.active-ct { + align-items: center; background-color: $color-brand-white-base; border: 1px solid $color-brand-primary-base; color: $color-brand-primary-base; + display: flex; + justify-content: space-between; } } } @@ -44,6 +46,7 @@ } .cta-wrapper { border-top: 1px solid $color-base-gray-40; + flex: 1 0 auto; // bottom: 0; padding: $space-12 $space-24 $space-12 $space-12; // position: fixed; @@ -53,6 +56,9 @@ z-index: 1; position: relative; } +.table-container { + flex: 1 0 auto; +} .table-wrapper { .Table { min-height: inherit; @@ -65,10 +71,12 @@ padding: 12px; } .step-container { + display: flex; + flex-direction: column; margin-top: 0; - width: 100%; margin-left: 0px; margin-bottom: 20px; + width: 100%; } .saveButton { padding: 5px 30px; diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 7b76a645..44cf5605 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -9,11 +9,8 @@ import { Button, Search, Icon, - ModalHeader, - ModalFooter, Tooltip, Notification, - ModalBody, cbModal } from '@contentstack/venus-components'; import { jsonToHtml } from '@contentstack/json-rte-serializer'; @@ -47,9 +44,14 @@ import { Mapping, ExistingFieldType, ContentTypeList, - ContentTypesSchema + ContentTypesSchema, + optionsType } from './contentMapper.interface'; import { ItemStatusMapProp } from '@contentstack/venus-components/build/components/Table/types'; +import { ModalObj } from '../Modal/modal.interface'; + +// Components +import SchemaModal from '../SchemaModal'; // Styles import './index.scss'; @@ -83,7 +85,6 @@ const ContentMapper = () => { const { contentMappingData: { content_types_heading: contentTypesHeading, - contentstack_fields: contentstackFields, description, action_cta: actionCta, cta, @@ -111,6 +112,8 @@ const ContentMapper = () => { const [exstingField, setexsitingField] = useState({}); const [selectedOptions, setSelectedOptions] = useState([]); + const [active, setActive] = useState(null ?? 0); + /** ALL HOOKS Here */ const { projectId = '' } = useParams(); @@ -132,6 +135,12 @@ const ContentMapper = () => { fetchExistingContentTypes(); stackStatus(); + + tableData?.forEach((field) => { + if (field?.otherCmsField === 'title' || field?.otherCmsField === 'url') { + field._invalid = true; + } + }); }, []); // Method to fetch content types @@ -151,11 +160,12 @@ const ContentMapper = () => { ); if (contentTypeCount > 0) { - setIsEmptyStack(true); - } else { setIsEmptyStack(false); + } else { + setIsEmptyStack(true); } }; + // Method to search content types const handleSearch = async (search: string) => { setSearchText(search); @@ -202,7 +212,6 @@ const ContentMapper = () => { startIndex, stopIndex }: TableTypes) => { - console.log(''); fetchContentTypes(); }; @@ -245,13 +254,7 @@ const ContentMapper = () => { // Method to change the content type const openContentType = (e: React.MouseEvent, i: number) => { - document.querySelectorAll('.ct-list li').forEach((ctLi) => { - ctLi?.classList?.remove('active-ct'); - }); - if (e.target instanceof HTMLLIElement) { - e?.target?.classList?.add('active-ct'); - } - + setActive(i); setOtherCmsTitle(contentTypes?.[i]?.otherCmsTitle); setContentTypeUid(contentTypes?.[i]?.id); setCurrentIndex(i); @@ -296,47 +299,15 @@ const ContentMapper = () => { // setSelectedContentType(value); // }; - const Modalomponent = (props: any) => { - return ( - <> - - - {contentTypes && validateArray(contentTypes) && ( -
    - {contentTypes?.map((content: ContentType, index: number) => ( -
    -
  • - {content?.otherCmsTitle} -
  • - - - -
    - ))} -
- )} -
- - - - - - - - ); - }; - const handleOnClick = () => { + const handleOnClick = (title: string) => { return cbModal({ - component: (props: any) => ( - { - return; - }} + component: (props: ModalObj) => ( + { + // return; + // }} {...props} /> ), @@ -384,7 +355,7 @@ const ContentMapper = () => {
handleFieldChange(selectedOption, data?.uid)} + onChange={(selectedOption: FieldTypes) => handleFieldChange(selectedOption, data?.uid)} placeholder="Select Field" version={'v2'} maxWidth="290px" @@ -617,23 +589,31 @@ const ContentMapper = () => { }, { disableSortBy: true, - Header: contentstackFields.title, - id: 'contenstatck', - //id: contentstackFields.title.replace(/\W+/g, '_').toLowerCase(), - accessor: SelectAccessor + Header: `Contentstack: ${ + IsEmptyStack ? `Blog` : newMigrationData?.destination_stack?.selectedStack?.label + }`, + accessor: SelectAccessor, + id: 'contentstack_cms_field' } + // { + // disableSortBy: true, + // Header: contentstackFields.title, + // id: 'contenstatck', + // //id: contentstackFields.title.replace(/\W+/g, '_').toLowerCase(), + // accessor: SelectAccessor + // } ]; - if (!IsEmptyStack) { - columns?.splice(1, 0, { - disableSortBy: true, - Header: `Contentstack: Home`, - // accessor: 'ct_field', - accessor: SelectAccessorOfColumn, - id: 'contentstack_cms_field' - //default: false - }); - } + // if (!IsEmptyStack) { + // columns?.splice(1, 0, { + // disableSortBy: true, + // Header: `Contentstack: ${newMigrationData?.destination_stack?.selectedStack?.label}`, + // // accessor: 'ct_field', + // accessor: SelectAccessor, + // id: 'contentstack_cms_field' + // //default: false + // }); + // } const nextButtonLabel = currentIndex < contentTypes?.length - 1 ? contentTypes[currentIndex + 1]?.otherCmsTitle : ''; @@ -647,7 +627,7 @@ const ContentMapper = () => { return (
-
+
{/* Content Types List */}
@@ -671,10 +651,24 @@ const ContentMapper = () => { {contentTypes?.map((content: ContentType, index: number) => (
  • openContentType(e, index)} > - {content?.otherCmsTitle} + {content?.otherCmsTitle} + + {active == index && ( + + + handleOnClick(content?.otherCmsTitle)} + /> + + + )}
  • ))} @@ -804,9 +798,7 @@ const ContentMapper = () => { {cta?.title && (
    - +
    )}
    diff --git a/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss b/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss index 623fcecb..f09c93fc 100644 --- a/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss +++ b/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss @@ -12,8 +12,9 @@ } .step-component .action-component-body { - width: 100% !important; + display: flex; margin-left: 0px !important; + width: 100% !important; } .step-component .step-name-icon { @@ -58,9 +59,10 @@ width: auto; } #newMigration .PageLayout__body { + background-color: $color-base-white-10 !important; + display: flex; margin: 0; position: relative; + padding: 0; width: auto; - background-color: #f7f9fc !important; - padding-top: 0; } diff --git a/ui/src/components/SchemaModal/index.scss b/ui/src/components/SchemaModal/index.scss new file mode 100644 index 00000000..2d608fc6 --- /dev/null +++ b/ui/src/components/SchemaModal/index.scss @@ -0,0 +1,53 @@ +@import '../../scss/variables'; + +.entries-outline { + ul { + padding: 0.625rem; + padding-bottom: 0.3125rem; + padding-top: 0; + transition: opacity 0.2s linear; + li { + color: #475161; + cursor: pointer; + font-size: 1rem; + font-weight: 500; + padding: 0; + white-space: nowrap; + .iconsholder { + align-items: center; + display: flex; + justify-content: flex-start; + padding: 0; + &:hover { + .title { + color: $color-brand-primary-base; + } + .icons { + svg { + path { + stroke: $color-brand-primary-base; + } + } + } + } + } + .title { + color: #475161; + font-weight: 400; + opacity: 1; + text-transform: capitalize; + transition: opacity 0.5s linear, width 300ms linear; + width: 12.5rem; + } + .icons { + align-items: center; + display: inline-flex; + justify-content: flex-start; + padding: 0.625rem 0; + svg { + margin-right: 0.625rem; + } + } + } + } +} diff --git a/ui/src/components/SchemaModal/index.tsx b/ui/src/components/SchemaModal/index.tsx new file mode 100644 index 00000000..48ef46fb --- /dev/null +++ b/ui/src/components/SchemaModal/index.tsx @@ -0,0 +1,143 @@ +// Libraries +import { useState, useEffect } from 'react'; +import { + ModalBody, + ModalHeader, + ModalFooter, + Icon, + ButtonGroup, + Button +} from '@contentstack/venus-components'; + +// Interface +import { Icons, SchemaProps, schemaType } from './schemaModal.interface'; +import { FieldMapType } from '../ContentMapper/contentMapper.interface'; + +// Styles +import './index.scss'; + +const getTopLevelIcons = (field: FieldMapType) => { + const icons: Icons = { + title: 'StarSmall', + text: 'SingleLineTextSmall', + multitext: 'MultiLineTextSmall', + rte: 'RichTextEditorSmall', + jsonRte: 'SuperchargedRte', + markdown: 'MarkdownSmall', + select: 'SelectSmall', + number: 'NumberSmall', + boolean: 'BooleanSmall', + isodate: 'DateSmall', + file: 'FileSmall', + reference: 'ReferenceSmall', + group: 'GroupSmall', + global_field: 'GlobalSmall', + blocks: 'ModularBlocksSmall', + link: 'LinkSmall', + bullet: 'Bullet', + custom: 'CustomSmall', + tag: 'TagSmall', + experience_container: 'PersonalizationLogoGreySmall' + }; + + if (field?.ContentstackFieldType === 'Single Line Textbox') { + return icons['title']; + } + + if (field?.ContentstackFieldType === 'URL') { + return icons['text']; + } + + if (field?.ContentstackFieldType === 'tags') { + return icons['tag']; + } + + if (field?.ContentstackFieldType === 'Select' || field?.ContentstackFieldType === 'dropdown') { + return icons['select']; + } + + if (field?.ContentstackFieldType === 'Date') { + return icons['isodate']; + } + + if (field?.ContentstackFieldType === 'Multi Line Textbox') { + return icons['multitext']; + } + + if (field?.ContentstackFieldType === 'HTML Rich text Editor') { + return icons['rte']; + } + + if (field?.ContentstackFieldType === 'JSON Rich Text Editor') { + return icons['jsonRte']; + } + + if (field?.ContentstackFieldType === 'Link') { + return icons['link']; + } + + if (field?.ContentstackFieldType === 'Boolean') { + return icons['boolean']; + } + + if (field?.ContentstackFieldType === 'Reference') { + return icons['reference']; + } + + if (!field.ContentstackFieldType) { + return icons['blocks']; + } + + return icons[field?.ContentstackFieldType as keyof Icons]; +}; + +const TreeView = ({ schema = [] }: schemaType) => { + const [list, setList] = useState([]); + + useEffect(() => { + setList(schema); + }, [schema]); + + return ( +
    +
    +
    + {list?.length > 0 && ( +
      + {list?.map((item: FieldMapType) => ( +
    • +
      + + + + {item?.otherCmsField} +
      +
    • + ))} +
    + )} +
    +
    +
    + ); +}; +const SchemaModal = (props: SchemaProps) => { + return ( + <> + + + + + + + + + + + + ); +}; + +export default SchemaModal; diff --git a/ui/src/components/SchemaModal/schemaModal.interface.ts b/ui/src/components/SchemaModal/schemaModal.interface.ts new file mode 100644 index 00000000..69bebfdd --- /dev/null +++ b/ui/src/components/SchemaModal/schemaModal.interface.ts @@ -0,0 +1,33 @@ +import { FieldMapType } from '../ContentMapper/contentMapper.interface'; + +export interface Icons { + title?: string; + text?: string; + multitext?: string; + rte?: string; + jsonRte?: string; + markdown?: string; + select?: string; + number?: string; + boolean?: string; + isodate?: string; + file?: string; + reference?: string; + group?: string; + global_field?: string; + blocks?: string; + link?: string; + bullet?: string; + custom?: string; + tag?: string; + experience_container?: string; +} +export interface SchemaProps { + contentType?: string; + closeModal: () => void; + schemaData: FieldMapType[]; +} + +export interface schemaType { + schema: FieldMapType[]; +} diff --git a/ui/src/services/api/stacks.service.ts b/ui/src/services/api/stacks.service.ts index 53910907..3f704e0d 100644 --- a/ui/src/services/api/stacks.service.ts +++ b/ui/src/services/api/stacks.service.ts @@ -25,6 +25,8 @@ export const createStacksInOrg = async (orgId: string, data: any) => { }; export const getStackStatus = async (orgId: string, data: string) => { + console.log('.................', orgId, data); + try { return await postCall(`${API_VERSION}/org/${orgId}/stack_status`, data, options); } catch (error: any) {