From 295314883ead2a7f76ae177405bcbedd6372d868 Mon Sep 17 00:00:00 2001 From: AishDani Date: Fri, 10 May 2024 13:54:42 +0530 Subject: [PATCH 1/3] feat:integrated advanced propertise with backend --- ui/src/components/AdvancePropertise/index.tsx | 61 +++++- .../components/Common/AddStack/addStack.tsx | 7 +- .../ContentMapper/contentMapper.interface.ts | 10 +- ui/src/components/ContentMapper/index.tsx | 200 +++++++++++++++--- .../DestinationStack/Actions/LoadStacks.tsx | 11 +- .../Summary/StacksSummary.tsx | 5 +- ui/src/components/DestinationStack/index.tsx | 6 +- .../components/MigrationExecution/index.tsx | 2 +- ui/src/context/app/app.interface.ts | 11 +- ui/src/services/api/service.interface.ts | 1 + 10 files changed, 256 insertions(+), 58 deletions(-) diff --git a/ui/src/components/AdvancePropertise/index.tsx b/ui/src/components/AdvancePropertise/index.tsx index 87dd78ec7..92bf7b2b1 100644 --- a/ui/src/components/AdvancePropertise/index.tsx +++ b/ui/src/components/AdvancePropertise/index.tsx @@ -3,21 +3,57 @@ import { ModalHeader, FieldLabel, TextInput, - ToggleSwitch + ToggleSwitch, + Tooltip } from '@contentstack/venus-components'; import './index.scss'; +import { useState } from 'react'; export interface SchemaProps { fieldtype: string; value: any; rowId: string; + updateFieldSettings:(rowId:string, value:any, checkBoxChanged:boolean)=> void; + isLocalised:boolean; closeModal: () => void; + data:any } -const AdvancePropertise = (props: SchemaProps) => { +const AdvancePropertise = (props: SchemaProps) => { + + + const [toggleStates, setToggleStates] = useState({ + validationRegex: props?.value?.ValidationRegex, + mandatory: props?.value?.Mandatory, + multiple: props?.value?.Multiple, + unique: props?.value?.Unique, + nonLocalizable: props?.value?.NonLocalizable + }); + + const handleToggleChange = (field: string, value: boolean, checkBoxChanged: boolean) => { + + setToggleStates(prevStates => ({ + ...prevStates, + [field]: value + })); + + props?.updateFieldSettings(props?.rowId, {[field?.charAt(0)?.toUpperCase() + field?.slice(1)]: value}, checkBoxChanged); +}; + + const handleOnChange = ( field: string, event: any, checkBoxChanged: boolean) => { + setToggleStates(prevStates => ({ + ...prevStates, + [field]: event?.target?.value + })); + + props?.updateFieldSettings(props?.rowId, {[field?.charAt(0)?.toUpperCase() + field?.slice(1)]: event?.target?.value}, checkBoxChanged); + + } + + return ( <> - + Validation (Regex) @@ -25,8 +61,10 @@ const AdvancePropertise = (props: SchemaProps) => { handleOnChange("validationRegex",e, true)} /> Options @@ -36,26 +74,35 @@ const AdvancePropertise = (props: SchemaProps) => { label="Mandatory" labelColor="primary" labelPosition="right" - checked={props?.value?.mandatory} + checked={toggleStates?.mandatory} + onChange={(e:any) => handleToggleChange("mandatory" , e?.target?.checked, true)} /> handleToggleChange("multiple" ,e?.target?.checked, true)} /> handleToggleChange("unique" , e?.target?.checked,true)} /> + handleToggleChange("nonLocalizable" , e?.target?.checked,true)} /> + +

If enabled, editing this field is restricted in localized entries. The field will use the value of the master-language entry in all localized entries. diff --git a/ui/src/components/Common/AddStack/addStack.tsx b/ui/src/components/Common/AddStack/addStack.tsx index d45581423..9d948f472 100644 --- a/ui/src/components/Common/AddStack/addStack.tsx +++ b/ui/src/components/Common/AddStack/addStack.tsx @@ -44,7 +44,7 @@ const AddStack = (props: any): JSX.Element => { const [addStackCMSData, setAddStackCMSData] = useState(defaultAddStackCMSData); const onSubmit = async (formData: any) => { setIsProcessing(true); - const resp = await props.onSubmit({ + const resp = await props?.onSubmit({ name: formData?.name || props?.defaultValues?.name, description: formData?.description || props?.defaultValues?.description, locale: formData?.locale?.value || props?.defaultValues?.locale @@ -55,7 +55,7 @@ const AddStack = (props: any): JSX.Element => { notificationContent: { text: 'Stack created successfully' }, type: 'success' }); - props.closeModal(); + props?.closeModal(); } else { Notification({ notificationContent: { text: 'Failed to create the stack' }, type: 'error' }); } @@ -88,7 +88,8 @@ const AddStack = (props: any): JSX.Element => { uid: key, label: response?.data?.locales[key], value: key, - locale: key, + master_locale: key, + locales:[], created_at: key })) : []; diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index be0a68242..e5474e03f 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -9,6 +9,13 @@ interface mapDataType { contentTypes: ContentType[]; projectId: string; } +interface Advanced { + ValidationRegex: string, + mandatory:boolean, + multiple:boolean, + unique:boolean, + nonLocalizable:boolean +} export interface ContentMapperType { content_types_heading?: string; cta: CTA; @@ -24,7 +31,7 @@ export interface ContentstackFields { export interface FieldTypes { label: string; - value: string; + value: any; } export interface TableTypes { sortBy: any; @@ -56,6 +63,7 @@ export interface FieldMapType { uid: string; id: string; _invalid?: boolean; + advanced:Advanced } export interface ItemStatus { diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 4435f6fd4..e54b6a4aa 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -12,7 +12,10 @@ import { Tooltip, Notification, cbModal, - InstructionText + InstructionText, + ModalHeader, + ModalBody, + ModalFooter } from '@contentstack/venus-components'; import { jsonToHtml } from '@contentstack/json-rte-serializer'; import HTMLReactParser from 'html-react-parser'; @@ -84,7 +87,11 @@ const Fields: Mapping = { interface ContentTypeMap { [key: string]: string; } - +interface ModalProps { + e:React.MouseEvent; + newIndex:number; + closeModal: () => void; +} const ContentMapper = () => { /** ALL CONTEXT HERE */ const { @@ -135,6 +142,16 @@ const ContentMapper = () => { const [otherCmsUid, setotherCmsUid] = useState(contentTypes[0]?.otherCmsUid); const [isContentTypeMapped, setisContentTypeMapped] = useState(false); const [isContentTypeSaved, setisContentTypeSaved] = useState(false); + const [advancePropertise, setadvancePropertise] = useState({ + validationRegex:'', + Mandatory: false, + Multiple: false, + Unique: false, + NonLocalizable: false + }); + const [isLocalised, setisLocalised] = useState(newMigrationData?.destination_stack?.selectedStack?.locales?.length > 1 ? true : false); + + const [active, setActive] = useState(null ?? 0); @@ -323,28 +340,88 @@ const ContentMapper = () => { //function to handle previous content type navigation const handlePrevClick = (e: React.MouseEvent) => { const newIndex = currentIndex > 0 ? currentIndex - 1 : 0; - setCurrentIndex(newIndex); - openContentType(e, newIndex); - document.querySelectorAll('.ct-list li').forEach((ctLi, ind) => { - if (newIndex === ind) { - ctLi?.classList?.add('active-ct'); - } - }); - }; + if(isDropDownChanged){ + handleSaveContentTypeModal(e, newIndex) - // function to handle next content type navigation - const handleNextClick = (e: React.MouseEvent) => { - if (currentIndex < contentTypes?.length - 1) { - const newIndex = currentIndex + 1; + }else{ setCurrentIndex(newIndex); openContentType(e, newIndex); document.querySelectorAll('.ct-list li').forEach((ctLi, ind) => { if (newIndex === ind) { ctLi?.classList?.add('active-ct'); } - }); + }) + + } + }; + + // function to handle next content type navigation + const handleNextClick = (e: React.MouseEvent) => { + if (currentIndex < contentTypes?.length - 1) { + const newIndex = currentIndex + 1; + + if(isDropDownChanged){ + handleSaveContentTypeModal(e, newIndex) + + }else{ + setCurrentIndex(newIndex); + openContentType(e, newIndex); + document.querySelectorAll('.ct-list li').forEach((ctLi, ind) => { + if (newIndex === ind) { + ctLi?.classList?.add('active-ct'); + } + }) + + } + } }; + const SaveContentType = (props:ModalProps) => { + + return ( + <> + + +

Hey there! You have unsaved changes on this page.

+
+ + + + + + + + + ); + } + const handleSaveContentTypeModal = (e:any, newIndex:number) => { + return cbModal({ + component: (props: ModalObj) => ( + + ), + modalProps: { + shouldCloseOnOverlayClick: true + } + }); + } // Function to get exisiting content types list const fetchExistingContentTypes = async () => { @@ -353,7 +430,26 @@ const ContentMapper = () => { setContentTypesList(data?.contentTypes); } }; + + const updateFieldSettings = (rowId:string, updatedSettings:any, checkBoxChanged:boolean) => { + setisDropDownCHanged(checkBoxChanged); + //setadvancePropertise(...updatedSettings); + + const newTableData = tableData?.map(row => { + if (row?.uid === rowId) { + setadvancePropertise({...row?.advanced, ...updatedSettings}); + + return { ...row, advanced: { ...row?.advanced, ...updatedSettings } }; + } + return row; + }); + + + setTableData(newTableData); + }; + + const handleOnClick = (title: string) => { return cbModal({ component: (props: ModalObj) => ( @@ -412,15 +508,20 @@ const ContentMapper = () => { const handleAdvancedSetting = ( fieldtype: string, - fieldvalue: ExistingFieldType, - rowId: string + fieldvalue: any, + rowId: string, + data: any ) => { + return cbModal({ component: (props: ModalObj) => ( ), @@ -435,7 +536,7 @@ const ContentMapper = () => { const data = { name: newMigrationData?.destination_stack?.selectedStack?.label, description: 'test migration stack', - master_locale: newMigrationData?.destination_stack?.selectedStack?.locale + master_locale: newMigrationData?.destination_stack?.selectedStack?.master_locale }; const res = await createTestStack( newMigrationData?.destination_stack?.selectedOrg?.value, @@ -477,24 +578,35 @@ const ContentMapper = () => { // isDisabled={data?.otherCmsField === 'title' || data?.otherCmsField === 'url'} /> - - handleAdvancedSetting(data?.ContentstackFieldType, exstingField, data?.uid) - } - /> + + + handleAdvancedSetting(data?.ContentstackFieldType, data?.advanced, data?.uid, data) + } + /> + + + ); }; - const handleFieldChange = (selectedValue: FieldTypes, rowIndex: string) => { + const handleFieldChange = (selectedValue: FieldTypes, rowIndex: string) => { setisDropDownCHanged(true); setexsitingField((prevOptions) => ({ ...prevOptions, [rowIndex]: { label: selectedValue?.label, value: selectedValue?.value } })); + setadvancePropertise({ + validationRegex: selectedValue?.value?.format, + Mandatory: selectedValue?.value?.mandatory, + Multiple: selectedValue?.value?.multiple, + Unique: selectedValue?.value?.unique, + NonLocalizable: selectedValue?.value?.non_localizable + }); if (isDropDownChanged && isContentTypeSaved) { setSelectedOptions((prevSelected) => { @@ -505,11 +617,23 @@ const ContentMapper = () => { const updatedRows = tableData.map((row) => { if (row?.uid === rowIndex) { - return { ...row, contentstackField: selectedValue?.label }; + + return { + ...row, + contentstackField: selectedValue?.label, + advanced:{ + validationRegex: selectedValue?.value?.format, + Mandatory: selectedValue?.value?.mandatory, + Multiple: selectedValue?.value?.multiple, + Unique: selectedValue?.value?.unique, + NonLocalizable: selectedValue?.value?.non_localizable + } + }; } return row; }); - setTableData(updatedRows); + + setTableData(updatedRows as FieldMapType[]); }; const SelectAccessorOfColumn = (data: FieldMapType) => { @@ -615,8 +739,7 @@ const ContentMapper = () => { const adjustedOptions = OptionsForRow.map((option: optionsType) => ({ ...option, isDisabled: selectedOptions?.includes(option?.label ?? '') - })); - + })); return (
@@ -634,8 +757,15 @@ const ContentMapper = () => { version="v2" icon="Setting" size="small" - onClick={() => - handleAdvancedSetting(data?.ContentstackFieldType, exstingField, data?.uid) + onClick={() =>{ + const value ={ + ValidationRegex: data?.advanced?.ValidationRegex, + Mandatory: data?.advanced?.mandatory, + Multiple: data?.advanced?.multiple, + Unique: data?.advanced?.unique, + NonLocalizable: data?.advanced?.nonLocalizable + } + handleAdvancedSetting(data?.ContentstackFieldType, advancePropertise, data?.uid, data)} } />
@@ -797,7 +927,7 @@ const ContentMapper = () => { const adjustedOption = options.map((option: any) => ({ ...option, isDisabled: contentTypeMapped && Object.values(contentTypeMapped).includes(option?.label) - })); + })); return (
diff --git a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx index 454910cac..661e866c5 100644 --- a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx +++ b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx @@ -38,7 +38,8 @@ const LoadStacks = (props: LoadFileFormatProps) => { label: 'Loading stacks...', value: 'loading', default: false, - locale: '', + master_locale:'', + locales:[], created_at: '' } ]; @@ -74,7 +75,8 @@ const LoadStacks = (props: LoadFileFormatProps) => { const newCreatedStack: IDropDown = { label: resp?.data?.stack?.name, value: resp?.data?.stack?.api_key, - locale: resp?.data?.stack?.master_locale, + master_locale: resp?.data?.stack?.master_locale, + locales: resp?.data?.stack?.locales, created_at: resp?.data?.stack?.created_at, uid: resp?.data?.stack?.api_key }; @@ -145,7 +147,8 @@ const LoadStacks = (props: LoadFileFormatProps) => { label: stack?.name, value: stack?.api_key, uid: stack?.api_key, - locale: stack?.master_locale, + master_locale: stack?.master_locale, + locales: stack?.locales, created_at: stack?.created_at })) : []; @@ -231,7 +234,7 @@ const LoadStacks = (props: LoadFileFormatProps) => {
- {selectedStack?.locale} + {selectedStack?.master_locale}
diff --git a/ui/src/components/DestinationStack/Summary/StacksSummary.tsx b/ui/src/components/DestinationStack/Summary/StacksSummary.tsx index 2728a0361..ebb20d70d 100644 --- a/ui/src/components/DestinationStack/Summary/StacksSummary.tsx +++ b/ui/src/components/DestinationStack/Summary/StacksSummary.tsx @@ -25,7 +25,8 @@ const StacksSummary = (props: StacksSummaryProps): JSX.Element => { label: 'Loading stacks...', value: 'loading', default: false, - locale: '', + master_locale: '', + locales:[], created_at: '' } ]; @@ -57,7 +58,7 @@ const StacksSummary = (props: StacksSummaryProps): JSX.Element => {
- {selectedStack?.locale} + {selectedStack?.master_locale}
diff --git a/ui/src/components/DestinationStack/index.tsx b/ui/src/components/DestinationStack/index.tsx index 720b86cb7..f08cae353 100644 --- a/ui/src/components/DestinationStack/index.tsx +++ b/ui/src/components/DestinationStack/index.tsx @@ -83,7 +83,8 @@ const DestinationStackComponent = ({ let selectedStackData: IDropDown = { value: destination_stack, label: '', - locale: '', + master_locale: '', + locales:[], created_at: '' }; @@ -103,7 +104,8 @@ const DestinationStackComponent = ({ selectedStackData = { label: stack?.name, value: stack?.api_key, - locale: stack?.master_locale, + master_locale: stack?.master_locale, + locales: stack?.locales, created_at: stack?.created_at }; } diff --git a/ui/src/components/MigrationExecution/index.tsx b/ui/src/components/MigrationExecution/index.tsx index 62fc10b0e..47a63e89a 100644 --- a/ui/src/components/MigrationExecution/index.tsx +++ b/ui/src/components/MigrationExecution/index.tsx @@ -52,7 +52,7 @@ const MigrationExecution = () => { return newMigrationData?.destination_stack?.selectedStack?.label; case 'Selected locale': - return newMigrationData?.destination_stack?.selectedStack?.locale; + return newMigrationData?.destination_stack?.selectedStack?.master_locale; } }; diff --git a/ui/src/context/app/app.interface.ts b/ui/src/context/app/app.interface.ts index 919d5ef7e..d17692ba0 100644 --- a/ui/src/context/app/app.interface.ts +++ b/ui/src/context/app/app.interface.ts @@ -136,7 +136,10 @@ interface FieldTypes { label: string; value: string; } - +interface locales { + code:string; + name:string +} export interface ILegacyCms { selectedCms: ICMSType; selectedFileFormat: ICardType; @@ -177,7 +180,8 @@ export interface IDropDown { label: string; value: string; default?: boolean; - locale: string; + master_locale: string; + locales:locales[]; created_at: string; } export interface ITestMigration { @@ -205,7 +209,8 @@ export const DEFAULT_DROPDOWN: IDropDown = { value: '', default: false, uid: '', - locale: '', + master_locale: '', + locales:[], created_at: '' }; diff --git a/ui/src/services/api/service.interface.ts b/ui/src/services/api/service.interface.ts index bb72271c1..3a3fa636f 100644 --- a/ui/src/services/api/service.interface.ts +++ b/ui/src/services/api/service.interface.ts @@ -12,6 +12,7 @@ export interface StackResponse { name: string; api_key: string; master_locale: string; + locales:[]; created_at: string; } From 02f5f326d10fdf6fabb6831b13e8a51ce4e368ae Mon Sep 17 00:00:00 2001 From: AishDani Date: Fri, 10 May 2024 14:17:18 +0530 Subject: [PATCH 2/3] refactor:resized modal size --- ui/src/components/ContentMapper/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index c84c4fedd..1f43a9f72 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -420,7 +420,8 @@ const ContentMapper = () => { /> ), modalProps: { - shouldCloseOnOverlayClick: true + shouldCloseOnOverlayClick: true, + size: 'small' } }); } From 0bad06d2d338bd6f57fff871147766e228f13f72 Mon Sep 17 00:00:00 2001 From: AishDani Date: Fri, 10 May 2024 16:41:09 +0530 Subject: [PATCH 3/3] refactor:changed library sequences --- ui/src/components/AdvancePropertise/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/components/AdvancePropertise/index.tsx b/ui/src/components/AdvancePropertise/index.tsx index 92bf7b2b1..6248e3e6b 100644 --- a/ui/src/components/AdvancePropertise/index.tsx +++ b/ui/src/components/AdvancePropertise/index.tsx @@ -1,3 +1,5 @@ +import { useState } from 'react'; + import { ModalBody, ModalHeader, @@ -8,7 +10,7 @@ import { } from '@contentstack/venus-components'; import './index.scss'; -import { useState } from 'react'; + export interface SchemaProps { fieldtype: string;