diff --git a/backend/src/provision/dto/create-provision.dto.ts b/backend/src/provision/dto/create-provision.dto.ts index 294f4630..1b9e0ae8 100644 --- a/backend/src/provision/dto/create-provision.dto.ts +++ b/backend/src/provision/dto/create-provision.dto.ts @@ -4,11 +4,10 @@ import { ProvisionDto } from './provision.dto'; export class CreateProvisionDto extends PickType(ProvisionDto, [ 'dtid', 'type', - // 'provision_group', - // 'provision_group_text', - // 'max', 'provision_name', 'free_text', + 'list_items', + 'list_enabled', 'help_text', 'category', 'sequence_value', diff --git a/backend/src/provision/dto/provision.dto.ts b/backend/src/provision/dto/provision.dto.ts index 0756ccbb..fcac0ce7 100644 --- a/backend/src/provision/dto/provision.dto.ts +++ b/backend/src/provision/dto/provision.dto.ts @@ -1,11 +1,10 @@ export class ProvisionDto { dtid?: number; type?: string; - // provision_group?: number; - // provision_group_text?: string; - // max?: number; provision_name?: string; free_text?: string; + list_items?: string[]; + list_enabled?: boolean; help_text?: string; category?: string; sequence_value?: number; diff --git a/backend/src/provision/dto/update-provision.dto.ts b/backend/src/provision/dto/update-provision.dto.ts index 3d5b9b24..b412bbb2 100644 --- a/backend/src/provision/dto/update-provision.dto.ts +++ b/backend/src/provision/dto/update-provision.dto.ts @@ -4,11 +4,10 @@ import { ProvisionDto } from './provision.dto'; export class UpdateProvisionDto extends PickType(ProvisionDto, [ 'dtid', 'type', - // 'provision_group', - // 'provision_group_text', - // 'max', 'provision_name', 'free_text', + 'list_items', + 'list_enabled', 'help_text', 'category', 'sequence_value', diff --git a/backend/src/provision/entities/provision.entity.ts b/backend/src/provision/entities/provision.entity.ts index ec78f87c..1849e942 100644 --- a/backend/src/provision/entities/provision.entity.ts +++ b/backend/src/provision/entities/provision.entity.ts @@ -14,6 +14,12 @@ export class Provision { @Column({ nullable: true }) free_text: string; + @Column({ type: 'text', array: true, default: '{}' }) + list_items: string[]; + + @Column({ nullable: true }) + list_enabled: boolean; + @Column({ nullable: true }) help_text: string; @@ -59,6 +65,8 @@ export class Provision { constructor( provision_name?: string, free_text?: string, + list_items?: string[], + list_enabled?: boolean, category?: string, active_flag?: boolean, create_userid?: string, @@ -66,6 +74,8 @@ export class Provision { ) { this.provision_name = provision_name || ''; this.free_text = free_text || ''; + this.list_items = list_items || []; + this.list_enabled = list_enabled || false; this.category = category || ''; this.active_flag = active_flag || true; this.create_userid = create_userid || ''; diff --git a/backend/src/provision/provision.controller.ts b/backend/src/provision/provision.controller.ts index 06b5180d..33dc8bd1 100644 --- a/backend/src/provision/provision.controller.ts +++ b/backend/src/provision/provision.controller.ts @@ -60,6 +60,8 @@ export class ProvisionController { id: number; provision: string; free_text: string; + list_items: string[]; + list_enabled: boolean; help_text: string; category: string; }, diff --git a/backend/src/provision/provision.service.ts b/backend/src/provision/provision.service.ts index 6cfc7136..9a0af85f 100644 --- a/backend/src/provision/provision.service.ts +++ b/backend/src/provision/provision.service.ts @@ -48,6 +48,8 @@ export class ProvisionService { const existingProvision: Provision = await this.provisionRepository.findOneBy({ id }); existingProvision.provision_name = provision.provision_name; existingProvision.free_text = provision.free_text; + existingProvision.list_items = provision.list_items; + existingProvision.list_enabled = provision.list_enabled; existingProvision.help_text = provision.help_text; existingProvision.category = provision.category; existingProvision.update_userid = provision.update_userid; @@ -272,6 +274,8 @@ export class ProvisionService { type: docTypeProvision.type, provision_name: docTypeProvision.provision.provision_name, free_text: docTypeProvision.provision.free_text, + list_items: docTypeProvision.provision.list_items, + list_enabled: docTypeProvision.provision.list_enabled, help_text: docTypeProvision.provision.help_text, category: docTypeProvision.provision.category, active_flag: docTypeProvision.provision.active_flag, diff --git a/backend/src/report/report.service.ts b/backend/src/report/report.service.ts index 11279804..ca933f15 100644 --- a/backend/src/report/report.service.ts +++ b/backend/src/report/report.service.ts @@ -137,8 +137,10 @@ export class ReportService { } return a.provision_group - b.provision_group; }); - let provisions: { [key: string]: { provision_name: string; free_text: string }[] } = {}; - provisionJson.forEach(({ provision_name, provision_group, free_text }) => { + let provisions: { + [key: string]: { provision_name: string; free_text: string; list: { item: string }[] }[]; + } = {}; + provisionJson.forEach(({ provision_name, provision_group, free_text, list_items, list_enabled }) => { if (free_text.includes('«')) { // regex which converts «DB_TENURE_TYPE» to {d.DB_Tenure_Type}, also works for VAR_ free_text = free_text.replace(/«([^»]+)»/g, function (match, innerText) { @@ -161,11 +163,41 @@ export class ReportService { free_text = free_text.replace(/db_name_tenant:convcrlf\(\)}/gi, 'DB_NAME_TENANT:convCRLF()}'); } + // do same conversions for list items + let list = list_items.map((item) => { + if (item.includes('«')) { + // regex which converts «DB_TENURE_TYPE» to {d.DB_Tenure_Type}, also works for VAR_ + item = item.replace(/«([^»]+)»/g, function (match, innerText) { + innerText = convertToSpecialCamelCase(innerText); + return '{d.' + innerText + '}'; + }); + } else if (item.includes('<<')) { + // regex which converts <> to {d.DB_Tenure_Type}, also works for VAR_ + item = item.replace(/<<([^>>]+)>>/g, function (match, innerText) { + innerText = convertToSpecialCamelCase(innerText); + return '{d.' + innerText + '}'; + }); + } + + if (item.toLowerCase().includes('db_name_tenant}')) { + item = item.replace(/db_name_tenant}/gi, 'DB_NAME_TENANT:convCRLF()}'); + } else if (item.toLowerCase().includes('db_name_tenant:convcrlf()}')) { + item = item.replace(/db_name_tenant:convcrlf\(\)}/gi, 'DB_NAME_TENANT:convCRLF()}'); + } + return { item }; + }); + const key = `SECTION_${provision_group}`; if (!provisions[key]) { provisions[key] = []; } - provisions[key].push({ provision_name, free_text }); + + // for now, only pass free_text or list, not both + if (list_enabled) { + provisions[key].push({ provision_name, free_text: null, list }); + } else { + provisions[key].push({ provision_name, free_text, list: [] }); + } }); // get the TTLS DB_ variables diff --git a/backend/src/types.ts b/backend/src/types.ts index 2e465a22..f46782e7 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -27,6 +27,8 @@ export type ProvisionJSON = { provision_name: string; provision_group: number; free_text: string; + list_items: string[]; + list_enabled: boolean; provision_id: number; sequence_value: number; doc_type_provision_id: number; @@ -59,6 +61,8 @@ export type ManageDocTypeProvision = { type: string; provision_name: string; free_text: string; + list_items: string[]; + list_enabled: boolean; help_text: string; category: string; active_flag: boolean; diff --git a/frontend/src/app/components/modal/manage-provisions/AddProvisionModal.tsx b/frontend/src/app/components/modal/manage-provisions/AddProvisionModal.tsx index c2c7d599..9b677044 100644 --- a/frontend/src/app/components/modal/manage-provisions/AddProvisionModal.tsx +++ b/frontend/src/app/components/modal/manage-provisions/AddProvisionModal.tsx @@ -1,18 +1,21 @@ import { useState } from 'react'; import { ProvisionUpload } from '../../../types/types'; import { Button, Col, Form, Modal, Spinner } from 'react-bootstrap'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'; interface AddProvisionModalProps { show: boolean; - addProvisionHandler: (provision: ProvisionUpload) => void; + addProvisionHandler: (provision: ProvisionUpload) => Promise; onHide: () => void; - refreshTables: () => void; } -const AddProvisionModal: React.FC = ({ show, addProvisionHandler, onHide, refreshTables }) => { +const AddProvisionModal: React.FC = ({ show, addProvisionHandler, onHide }) => { const [loading, setLoading] = useState(false); const [provisionName, setProvisionName] = useState(''); const [freeText, setFreeText] = useState(''); + const [listItems, setListItems] = useState(['']); + const [listEnabled, setListEnabled] = useState(false); const [helpText, setHelpText] = useState(''); const [category, setCategory] = useState(''); @@ -32,19 +35,41 @@ const AddProvisionModal: React.FC = ({ show, addProvisio setCategory(e.target.value); }; - const handleSaveButton = () => { + const handleListEnabledChange = (e: React.ChangeEvent) => { + setListEnabled(e.target.checked); + }; + + const handleListItemChange = (e: React.ChangeEvent, index: number) => { + const newListItems = [...listItems]; + newListItems[index] = e.target.value; + setListItems(newListItems); + }; + + const handleAddListItem = () => { + setListItems([...listItems, '']); + }; + + const handleRemoveListItem = (index: number) => { + const newListItems = [...listItems]; + newListItems.splice(index, 1); + setListItems(newListItems); + }; + + const handleSaveButton = async () => { try { setLoading(true); const provisionUpload: ProvisionUpload = { provision_name: provisionName, free_text: freeText, + list_items: listEnabled ? listItems : [], + list_enabled: listEnabled, help_text: helpText, category: category, }; - addProvisionHandler(provisionUpload); + + await addProvisionHandler(provisionUpload); onHide(); - refreshTables(); } catch (err) { console.log('Error adding provision'); console.log(err); @@ -81,15 +106,50 @@ const AddProvisionModal: React.FC = ({ show, addProvisio - - - Free Text - - - - + + + {listEnabled ? ( + + + List Items + + {listItems.map((item, index) => ( +
+ + handleListItemChange(e, index)} + /> + + + + +
+ ))} +
+ +
+
+ ) : ( + + + Free Text + + + + + + )} + Help Text diff --git a/frontend/src/app/components/modal/manage-provisions/forms/EditProvisionModalForm.tsx b/frontend/src/app/components/modal/manage-provisions/forms/EditProvisionModalForm.tsx index 06cd2d2c..2c07963b 100644 --- a/frontend/src/app/components/modal/manage-provisions/forms/EditProvisionModalForm.tsx +++ b/frontend/src/app/components/modal/manage-provisions/forms/EditProvisionModalForm.tsx @@ -2,6 +2,8 @@ import { useEffect, useState } from 'react'; import { Provision, ProvisionUpload, Variable } from '../../../../types/types'; import { Button, Col, Form, Modal, Spinner } from 'react-bootstrap'; import ManageVariablesTable from '../../../table/manage-provisions/ManageVariablesTable'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'; interface EditProvisionModalFormProps { provision: Provision | undefined; @@ -26,6 +28,8 @@ const EditProvisionModalForm: React.FC = ({ }) => { const [provisionName, setProvisionName] = useState(''); const [freeText, setFreeText] = useState(''); + const [listItems, setListItems] = useState(['']); + const [listEnabled, setListEnabled] = useState(false); const [helpText, setHelpText] = useState(''); const [category, setCategory] = useState(''); @@ -34,6 +38,8 @@ const EditProvisionModalForm: React.FC = ({ if (provision) { setProvisionName(provision.provision_name); setFreeText(provision.free_text); + setListItems(provision.list_items); + setListEnabled(provision.list_enabled); setHelpText(provision.help_text); setCategory(provision.category); } @@ -58,14 +64,37 @@ const EditProvisionModalForm: React.FC = ({ setCategory(e.target.value); }; + const handleListEnabledChange = (e: React.ChangeEvent) => { + setListEnabled(e.target.checked); + }; + + const handleListItemChange = (e: React.ChangeEvent, index: number) => { + const newListItems = [...listItems]; + newListItems[index] = e.target.value; + setListItems(newListItems); + }; + + const handleAddListItem = () => { + setListItems([...listItems, '']); + }; + + const handleRemoveListItem = (index: number) => { + const newListItems = [...listItems]; + newListItems.splice(index, 1); + setListItems(newListItems); + }; + const handleSaveButton = () => { if (provision) { const provisionUpload: ProvisionUpload = { provision_name: provisionName, free_text: freeText, + list_items: listItems, + list_enabled: listEnabled, help_text: helpText, category: category, }; + console.log(provisionUpload); updateProvisionHandler(provisionUpload, provision.id); } }; @@ -103,21 +132,50 @@ const EditProvisionModalForm: React.FC = ({ - - - Free Text - - - - + + + {listEnabled ? ( + + + List Items + + {listItems.map((item, index) => ( +
+ + handleListItemChange(e, index)} + /> + + + + +
+ ))} +
+ +
+
+ ) : ( + + + Free Text + + + + + + )} + Help Text diff --git a/frontend/src/app/components/table/manage-provisions/ManageProvisionsTable.tsx b/frontend/src/app/components/table/manage-provisions/ManageProvisionsTable.tsx index 5dab34c9..5388f0ed 100644 --- a/frontend/src/app/components/table/manage-provisions/ManageProvisionsTable.tsx +++ b/frontend/src/app/components/table/manage-provisions/ManageProvisionsTable.tsx @@ -27,7 +27,6 @@ const ManageProvisionsTable: React.FC = ({ if (provisions) { const sortedData = basicSort(provisions); setAllProvisions(sortedData); - console.log(provisions[0]); } if (variables) { setAllVariables(variables); diff --git a/frontend/src/app/content/pages/LandingPage.tsx b/frontend/src/app/content/pages/LandingPage.tsx index af78866b..986349dd 100644 --- a/frontend/src/app/content/pages/LandingPage.tsx +++ b/frontend/src/app/content/pages/LandingPage.tsx @@ -334,6 +334,8 @@ const LandingPage: FC = () => { doc_type_provision_id: provision.id, provision_name: provision.provision_name, free_text: provision.free_text, + list_items: provision.list_items, + list_enabled: provision.list_enabled, }; }); const selectedVariables: Variable[] = variables.filter((variable) => selectedVariableIds.includes(variable.id)); diff --git a/frontend/src/app/content/pages/ManageProvisionsPage.tsx b/frontend/src/app/content/pages/ManageProvisionsPage.tsx index be9374e0..56c0d566 100644 --- a/frontend/src/app/content/pages/ManageProvisionsPage.tsx +++ b/frontend/src/app/content/pages/ManageProvisionsPage.tsx @@ -70,10 +70,12 @@ const ManageProvisionsPage: FC = () => { const updateProvisionHandler = async (provisionUpload: ProvisionUpload, provisionId: number) => { await updateProvision({ ...provisionUpload, id: provisionId }); + refreshTables(); }; const addProvisionHandler = async (provisionUpload: ProvisionUpload) => { await addProvision(provisionUpload); + refreshTables(); }; const removeProvisionHandler = async (id: number) => { await removeProvision(id); @@ -136,7 +138,6 @@ const ManageProvisionsPage: FC = () => { show={showAddProvisionModal} onHide={() => setShowAddProvisionModal(false)} addProvisionHandler={addProvisionHandler} - refreshTables={refreshTables} />