From 55c51feb2745d71fd2e531d2ecc03930e9c073fd Mon Sep 17 00:00:00 2001 From: Michael Haufe Date: Mon, 10 Jun 2024 20:31:57 -0500 Subject: [PATCH] - Unified and abstracted DataTables as XDataTable component --- components/XDataTable.vue | 144 ++++++++++++++ modules/environment/ui/pages/Assumptions.vue | 107 ++--------- modules/environment/ui/pages/Components.vue | 105 ++--------- modules/environment/ui/pages/Constraints.vue | 110 +++-------- modules/environment/ui/pages/Effects.vue | 108 +++-------- modules/environment/ui/pages/Glossary.vue | 107 +++-------- modules/environment/ui/pages/Index.vue | 34 ++-- modules/environment/ui/pages/Invariants.vue | 108 +++-------- modules/goals/ui/pages/Index.vue | 34 ++-- modules/goals/ui/pages/Limitations.vue | 104 +++------- modules/goals/ui/pages/Obstacles.vue | 104 +++------- modules/goals/ui/pages/Outcomes.vue | 105 +++-------- modules/goals/ui/pages/Stakeholders.vue | 177 ++++-------------- modules/goals/ui/pages/UseCases.vue | 132 +++---------- .../ui/pages/solution/[solutionSlug].vue | 24 +-- modules/system/ui/pages/Index.vue | 21 ++- 16 files changed, 453 insertions(+), 1071 deletions(-) create mode 100644 components/XDataTable.vue diff --git a/components/XDataTable.vue b/components/XDataTable.vue new file mode 100644 index 00000000..6f34d6fc --- /dev/null +++ b/components/XDataTable.vue @@ -0,0 +1,144 @@ + + + + + \ No newline at end of file diff --git a/modules/environment/ui/pages/Assumptions.vue b/modules/environment/ui/pages/Assumptions.vue index 9d1ef4e7..69ae58ce 100644 --- a/modules/environment/ui/pages/Assumptions.vue +++ b/modules/environment/ui/pages/Assumptions.vue @@ -10,7 +10,7 @@ import UpdateAssumptionUseCase from '../../application/UpdateAssumptionUseCase'; import DeleteAssumptionUseCase from '../../application/DeleteAssumptionUseCase'; import type Assumption from '../../domain/Assumption'; import { FilterMatchMode } from 'primevue/api'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; const router = useRouter(), route = useRoute(), @@ -37,78 +37,35 @@ if (!solution) { type AssumptionViewModel = Pick; const assumptions = ref([]), - editingRows = ref([]), - dataTable = ref(); + emptyAssumption = { id: emptyUuid, name: '', statement: '' }; onMounted(async () => { assumptions.value = await getAssumptionsUseCase.execute(environment!.id) ?? [] }) -const filters = ref({ +const filters = ref>({ 'name': { value: null, matchMode: FilterMatchMode.CONTAINS }, 'statement': { value: null, matchMode: FilterMatchMode.CONTAINS }, }); -const createDisabled = ref(false) +const onCreate = async (data: AssumptionViewModel) => { + const newId = await createAssumptionUseCase.execute({ + parentId: environment!.id, + name: data.name, + statement: data.statement + }) -const addNewRow = () => { - assumptions.value.unshift({ id: emptyUuid, name: '', statement: '' }) - editingRows.value = [assumptions.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null -} - -const onRowEditSave = async (event: { newData: AssumptionViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const inputs = (originalEvent.target! as HTMLElement).closest('tr')!.querySelectorAll('input') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createAssumptionUseCase.execute({ - parentId: environment!.id, - name: newData.name, - statement: newData.statement - }) - - assumptions.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement - } - createDisabled.value = false - } else { - assumptions.value[index] = newData - await updateAssumptionUseCase.execute(newData) - } -} - -const onRowEditCancel = ({ data, index }: { data: AssumptionViewModel, index: number }) => { - if (data.id !== emptyUuid) - return - - assumptions.value.splice(index, 1) - createDisabled.value = false - dataTable.value!.d_sortField = 'name' + assumptions.value = await getAssumptionsUseCase.execute(environment!.id) ?? [] } -const onRowDelete = async (assumption: AssumptionViewModel) => { - if (!confirm(`Are you sure you want to delete ${assumption.name}?`)) - return - assumptions.value = assumptions.value.filter(o => o.id !== assumption.id) - await deleteAssumptionUseCase.execute(assumption.id) +const onDelete = async (id: Uuid) => { + await deleteAssumptionUseCase.execute(id) + assumptions.value = await getAssumptionsUseCase.execute(environment!.id) ?? [] } -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } +const onUpdate = async (data: AssumptionViewModel) => { + await updateAssumptionUseCase.execute(data) + assumptions.value = await getAssumptionsUseCase.execute(environment!.id) ?? [] } @@ -119,15 +76,8 @@ const onSort = (event: any) => { An example of an assumption would be: "Screen resolution will not change during the execution of the program".

- - - - + - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/environment/ui/pages/Components.vue b/modules/environment/ui/pages/Components.vue index 834419ee..d730ce93 100644 --- a/modules/environment/ui/pages/Components.vue +++ b/modules/environment/ui/pages/Components.vue @@ -1,6 +1,6 @@ @@ -117,15 +74,8 @@ const onSort = (event: any) => { Environment components are the EXTERNAL elements that the system interacts with. These external components expose interfaces that the system uses to communicate with.

- - - - + - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/environment/ui/pages/Constraints.vue b/modules/environment/ui/pages/Constraints.vue index 86364065..d54c0c47 100644 --- a/modules/environment/ui/pages/Constraints.vue +++ b/modules/environment/ui/pages/Constraints.vue @@ -4,7 +4,7 @@ import EnvironmentRepository from '../../data/EnvironmentRepository'; import GetSolutionBySlugUseCase from '~/modules/solution/application/GetSolutionBySlugUseCase'; import GetEnvironmentBySolutionIdUseCase from '../../application/GetEnvironmentBySolutionIdUseCase'; import { FilterMatchMode } from 'primevue/api'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; import ConstraintRepository from '../../data/ConstraintRepository'; import GetConstraintsUseCase from '../../application/GetConstraintsUseCase'; import CreateConstraintUseCase from '../../application/CreateConstraintUseCase'; @@ -38,9 +38,8 @@ if (!solution) { type ConstraintViewModel = Pick; const constraints = ref([]), - categories = ref(Object.values(ConstraintCategory)), - editingRows = ref([]), - dataTable = ref(); + emptyConstraint = { id: emptyUuid, name: '', statement: '', category: ConstraintCategory.BusinessRule }, + categories = ref(Object.values(ConstraintCategory)) onMounted(async () => { constraints.value = await getConstraintsUseCase.execute(environment!.id) ?? [] @@ -52,68 +51,25 @@ const filters = ref({ 'category': { value: null, matchMode: FilterMatchMode.EQUALS } }); -const createDisabled = ref(false) +const onCreate = async (data: ConstraintViewModel) => { + const newId = await createConstraintUseCase.execute({ + parentId: environment!.id, + name: data.name, + statement: data.statement, + category: data.category + }) -const addNewRow = () => { - constraints.value.unshift({ id: emptyUuid, name: '', statement: '', category: ConstraintCategory.BusinessRule }) - editingRows.value = [constraints.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null -} - -const onRowEditSave = async (event: { newData: ConstraintViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const inputs = (originalEvent.target! as HTMLElement).closest('tr')!.querySelectorAll('input') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createConstraintUseCase.execute({ - parentId: environment!.id, - name: newData.name, - statement: newData.statement, - category: newData.category - }) - - constraints.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement, - category: newData.category - } - createDisabled.value = false - } else { - constraints.value[index] = newData - await updateConstraintUseCase.execute(newData) - } -} - -const onRowEditCancel = ({ data, index }: { data: ConstraintViewModel, index: number }) => { - if (data.id !== emptyUuid) - return - - constraints.value.splice(index, 1) - createDisabled.value = false - dataTable.value!.d_sortField = 'name' + constraints.value = await getConstraintsUseCase.execute(environment!.id) ?? [] } -const onRowDelete = async (constraint: ConstraintViewModel) => { - if (!confirm(`Are you sure you want to delete ${constraint.name}?`)) - return - constraints.value = constraints.value.filter(o => o.id !== constraint.id) - await deleteConstraintUseCase.execute(constraint.id) +const onDelete = async (id: Uuid) => { + constraints.value = constraints.value.filter(o => o.id !== id) + await deleteConstraintUseCase.execute(id) } -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } +const onUpdate = async (data: ConstraintViewModel) => { + await updateConstraintUseCase.execute(data) + constraints.value = await getConstraintsUseCase.execute(environment!.id) ?? [] } @@ -122,15 +78,8 @@ const onSort = (event: any) => { Environmental constraints are the limitations and obligations that the environment imposes on the project and system.

- - - - + - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/environment/ui/pages/Effects.vue b/modules/environment/ui/pages/Effects.vue index c5040d64..13cf5143 100644 --- a/modules/environment/ui/pages/Effects.vue +++ b/modules/environment/ui/pages/Effects.vue @@ -1,7 +1,7 @@ @@ -118,15 +80,8 @@ const onSort = (event: any) => { An Effect is an environment property affected by a System. Example: "The running system will cause the temperature of the room to increase."

- - - - + - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/environment/ui/pages/Glossary.vue b/modules/environment/ui/pages/Glossary.vue index 0b7dc9a4..46db6377 100644 --- a/modules/environment/ui/pages/Glossary.vue +++ b/modules/environment/ui/pages/Glossary.vue @@ -10,7 +10,7 @@ import UpdateGlossaryTermUseCase from '../../application/UpdateGlossaryTermUseCa import DeleteGlossaryTermUseCase from '../../application/DeleteGlossaryTermUseCase'; import type GlossaryTerm from '../../domain/GlossaryTerm'; import { FilterMatchMode } from 'primevue/api'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; const router = useRouter(), route = useRoute(), @@ -37,8 +37,7 @@ if (!solution) { type GlossaryTermViewModel = Pick; const glossaryTerms = ref([]), - editingRows = ref([]), - dataTable = ref(); + emptyGlossaryTerm = { id: emptyUuid, name: '', statement: '' } onMounted(async () => { glossaryTerms.value = await getGlossaryTermsUseCase.execute(environment!.id) ?? [] @@ -49,66 +48,30 @@ const filters = ref({ 'statement': { value: null, matchMode: FilterMatchMode.CONTAINS }, }); -const createDisabled = ref(false) +const onCreate = async (data: GlossaryTermViewModel) => { + const newId = await createGlossaryTermUseCase.execute({ + parentId: environment!.id, + name: data.name, + statement: data.statement + }) -const addNewRow = () => { - glossaryTerms.value.unshift({ id: emptyUuid, name: '', statement: '' }) - editingRows.value = [glossaryTerms.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null -} - -const onRowEditSave = async (event: { newData: GlossaryTermViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const inputs = (originalEvent.target! as HTMLElement).closest('tr')!.querySelectorAll('input') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createGlossaryTermUseCase.execute({ - parentId: environment!.id, - name: newData.name, - statement: newData.statement - }) - - glossaryTerms.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement - } - createDisabled.value = false - } else { - glossaryTerms.value[index] = newData - await updateGlossaryTermUseCase.execute(newData) - } + glossaryTerms.value = await getGlossaryTermsUseCase.execute(environment!.id) ?? [] } -const onRowEditCancel = ({ data, index }: { data: GlossaryTermViewModel, index: number }) => { - if (data.id !== emptyUuid) - return +const onUpdate = async (data: GlossaryTermViewModel) => { + await updateGlossaryTermUseCase.execute({ + id: data.id, + name: data.name, + statement: data.statement + }) - glossaryTerms.value.splice(index, 1) - createDisabled.value = false - dataTable.value!.d_sortField = 'name' + glossaryTerms.value = await getGlossaryTermsUseCase.execute(environment!.id) ?? [] } -const onRowDelete = async (glossaryTerm: GlossaryTermViewModel) => { - if (!confirm(`Are you sure you want to delete ${glossaryTerm.name}?`)) - return - glossaryTerms.value = glossaryTerms.value.filter(o => o.id !== glossaryTerm.id) - await deleteGlossaryTermUseCase.execute(glossaryTerm.id) -} +const onDelete = async (id: Uuid) => { + await deleteGlossaryTermUseCase.execute(id) -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } + glossaryTerms.value = await getGlossaryTermsUseCase.execute(environment!.id) ?? [] } @@ -116,15 +79,8 @@ const onSort = (event: any) => {

A Glossary is a list of terms in a particular domain of knowledge with the definitions for those terms.

- - - - + - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/environment/ui/pages/Index.vue b/modules/environment/ui/pages/Index.vue index f8c55552..6541dd40 100644 --- a/modules/environment/ui/pages/Index.vue +++ b/modules/environment/ui/pages/Index.vue @@ -23,6 +23,15 @@ if (!solution) { if (!environment) await createEnvironmentUseCase.execute(solution.id); } + +const links = [ + { name: 'Assumptions', icon: 'pi-sun', label: 'Assumptions' }, + { name: 'Components', icon: 'pi-th-large', label: 'Components' }, + { name: 'Constraints', icon: 'pi-link', label: 'Constraints' }, + { name: 'Effects', icon: 'pi-bolt', label: 'Effects' }, + { name: 'Glossary', icon: 'pi-book', label: 'Glossary' }, + { name: 'Invariants', icon: 'pi-lock', label: 'Invariants' } +] - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/goals/ui/pages/Index.vue b/modules/goals/ui/pages/Index.vue index d4215d71..26595426 100644 --- a/modules/goals/ui/pages/Index.vue +++ b/modules/goals/ui/pages/Index.vue @@ -23,6 +23,15 @@ if (!solution) { if (!goals) await createGoalsUseCase.execute(solution.id); } + +const links = [ + { name: 'Rationale', icon: 'pi-book', label: 'Rationale' }, + { name: 'Outcomes', icon: 'pi-check-circle', label: 'Outcomes' }, + { name: 'Stakeholders', icon: 'pi-users', label: 'Stakeholders' }, + { name: 'Use Cases', icon: 'pi-briefcase', label: 'Use Cases' }, + { name: 'Obstacles', icon: ' pi-exclamation-triangle', label: 'Obstacles' }, + { name: 'Limitations', icon: 'pi-exclamation-circle', label: 'Limitations' } +] \ No newline at end of file diff --git a/modules/goals/ui/pages/Limitations.vue b/modules/goals/ui/pages/Limitations.vue index 4632e754..ad1cc9be 100644 --- a/modules/goals/ui/pages/Limitations.vue +++ b/modules/goals/ui/pages/Limitations.vue @@ -10,7 +10,7 @@ import GetLimitsUseCase from '../../application/GetLimitsUseCase'; import CreateLimitUseCase from '../../application/CreateLimitUseCase'; import UpdateLimitUseCase from '../../application/UpdateLimitUseCase'; import DeleteLimitUseCase from '../../application/DeleteLimitUseCase'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; import type Button from 'primevue/button'; const router = useRouter(), @@ -38,8 +38,7 @@ if (!solution) { type LimitViewModel = Pick; const limits = ref([]), - editingRows = ref([]), - dataTable = ref(); + emptyLimit: LimitViewModel = { id: emptyUuid, name: '', statement: '' }; onMounted(async () => { limits.value = await getLimitsUseCase.execute(goals!.id) ?? [] @@ -50,64 +49,30 @@ const filters = ref({ 'statement': { value: null, matchMode: FilterMatchMode.CONTAINS }, }); -const createDisabled = ref(false) +const onCreate = async (data: LimitViewModel) => { + const newId = await createLimitUseCase.execute({ + parentId: goals!.id, + name: data.name, + statement: data.statement + }) -const addNewRow = () => { - limits.value.unshift({ id: emptyUuid, name: '', statement: '' }) - editingRows.value = [limits.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null + limits.value = await getLimitsUseCase.execute(goals!.id) ?? [] } -const onRowEditSave = async (event: { newData: LimitViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const inputs = (originalEvent.target! as HTMLElement).closest('tr')!.querySelectorAll('input') +const onUpdate = async (data: LimitViewModel) => { + await updateLimitUseCase.execute({ + id: data.id, + name: data.name, + statement: data.statement + }) - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createLimitUseCase.execute({ - parentId: goals!.id, - name: newData.name, - statement: newData.statement - }) - limits.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement - } - createDisabled.value = false - } else { - limits.value[index] = newData - await updateLimitUseCase.execute(newData) - } + limits.value = await getLimitsUseCase.execute(goals!.id) ?? [] } -const onRowEditCancel = ({ data, index }: { data: LimitViewModel, index: number }) => { - if (data.id !== emptyUuid) - return +const onDelete = async (id: Uuid) => { + await deleteLimitUseCase.execute({ parentId: goals!.id, id }) - limits.value.splice(index, 1) - createDisabled.value = false -} - -const onRowDelete = async (limit: LimitViewModel) => { - if (!confirm(`Are you sure you want to delete ${limit.name}?`)) - return - limits.value = limits.value.filter(o => o.id !== limit.id) - await deleteLimitUseCase.execute({ parentId: goals!.id, id: limit.id }) -} - -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } + limits.value = await getLimitsUseCase.execute(goals!.id) ?? [] } - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/goals/ui/pages/Obstacles.vue b/modules/goals/ui/pages/Obstacles.vue index 030d036e..08b972f2 100644 --- a/modules/goals/ui/pages/Obstacles.vue +++ b/modules/goals/ui/pages/Obstacles.vue @@ -10,7 +10,7 @@ import GetObstaclesUseCase from '../../application/GetObstaclesUseCase'; import CreateObstacleUseCase from '../../application/CreateObstacleUseCase'; import UpdateObstacleUseCase from '../../application/UpdateObstacleUseCase'; import DeleteObstacleUseCase from '../../application/DeleteObstacleUseCase'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; const router = useRouter(), route = useRoute(), @@ -37,8 +37,7 @@ if (!solution) { type ObstacleViewModel = Pick; const obstacles = ref([]), - editingRows = ref([]), - dataTable = ref(); + emptyObstacle: ObstacleViewModel = { id: emptyUuid, name: '', statement: '' }; onMounted(async () => { obstacles.value = await getObstaclesUseCase.execute(goals!.id) ?? [] @@ -49,66 +48,32 @@ const filters = ref({ 'statement': { value: null, matchMode: FilterMatchMode.CONTAINS }, }); -const createDisabled = ref(false) +const onCreate = async (data: ObstacleViewModel) => { + const newId = await createObstacleUseCase.execute({ + parentId: goals!.id, + name: data.name, + statement: data.statement + }) -const addNewRow = () => { - obstacles.value.unshift({ id: emptyUuid, name: '', statement: '' }) - editingRows.value = [obstacles.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null + obstacles.value = await getObstaclesUseCase.execute(goals!.id) ?? [] } -const onRowEditSave = async (event: { newData: ObstacleViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const inputs = (originalEvent.target! as HTMLElement).closest('tr')!.querySelectorAll('input') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createObstacleUseCase.execute({ - parentId: goals!.id, - name: newData.name, - statement: newData.statement - }) +const onUpdate = async (data: ObstacleViewModel) => { + await updateObstacleUseCase.execute({ + id: data.id, + name: data.name, + statement: data.statement + }) - obstacles.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement - } - createDisabled.value = false - } else { - obstacles.value[index] = newData - await updateObstacleUseCase.execute(newData) - } + obstacles.value = await getObstaclesUseCase.execute(goals!.id) ?? [] } -const onRowEditCancel = ({ data, index }: { data: ObstacleViewModel, index: number }) => { - if (data.id !== emptyUuid) - return - - obstacles.value.splice(index, 1) - createDisabled.value = false -} +const onDelete = async (id: Uuid) => { + await deleteObstacleUseCase.execute({ parentId: goals!.id, id }) -const onRowDelete = async (obstacle: ObstacleViewModel) => { - if (!confirm(`Are you sure you want to delete ${obstacle.name}?`)) - return - obstacles.value = obstacles.value.filter(o => o.id !== obstacle.id) - await deleteObstacleUseCase.execute({ parentId: goals!.id, id: obstacle.id }) + obstacles.value = await getObstaclesUseCase.execute(goals!.id) ?? [] } -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } -} - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/goals/ui/pages/Outcomes.vue b/modules/goals/ui/pages/Outcomes.vue index 676601ae..553eca40 100644 --- a/modules/goals/ui/pages/Outcomes.vue +++ b/modules/goals/ui/pages/Outcomes.vue @@ -10,7 +10,7 @@ import GetOutcomesUseCase from '../../application/GetOutcomesUseCase'; import CreateOutcomeUseCase from '../../application/CreateOutcomeUseCase'; import UpdateOutcomeUseCase from '../../application/UpdateOutcomeUseCase'; import DeleteOutcomeUseCase from '../../application/DeleteOutcomeUseCase'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; const router = useRouter(), route = useRoute(), @@ -37,8 +37,7 @@ if (!solution) { type OutcomeViewModel = Pick; const outcomes = ref([]), - editingRows = ref([]), - dataTable = ref(); + emptyOutcome: OutcomeViewModel = { id: emptyUuid, name: '', statement: '' }; onMounted(async () => { outcomes.value = await getOutcomesUseCase.execute(goals!.id) ?? [] @@ -49,65 +48,30 @@ const filters = ref({ 'statement': { value: null, matchMode: FilterMatchMode.CONTAINS }, }); -const createDisabled = ref(false) +const onCreate = async (data: OutcomeViewModel) => { + const newId = await createOutcomeUseCase.execute({ + parentId: goals!.id, + name: data.name, + statement: data.statement + }) -const addNewRow = () => { - outcomes.value.unshift({ id: emptyUuid, name: '', statement: '' }) - editingRows.value = [outcomes.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null -} - -const onRowEditSave = async (event: { newData: OutcomeViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const inputs = (originalEvent.target! as HTMLElement).closest('tr')!.querySelectorAll('input') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createOutcomeUseCase.execute({ - parentId: goals!.id, - name: newData.name, - statement: newData.statement - }) - - outcomes.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement - } - createDisabled.value = false - } else { - outcomes.value[index] = newData - await updateOutcomeUseCase.execute(newData) - } + outcomes.value = await getOutcomesUseCase.execute(goals!.id) ?? [] } -const onRowEditCancel = ({ data, index }: { data: OutcomeViewModel, index: number }) => { - if (data.id !== emptyUuid) - return +const onUpdate = async (data: OutcomeViewModel) => { + await updateOutcomeUseCase.execute({ + id: data.id, + name: data.name, + statement: data.statement + }) - outcomes.value.splice(index, 1) - createDisabled.value = false + outcomes.value = await getOutcomesUseCase.execute(goals!.id) ?? [] } -const onRowDelete = async (outcome: OutcomeViewModel) => { - if (!confirm(`Are you sure you want to delete ${outcome.name}?`)) - return - outcomes.value = outcomes.value.filter(o => o.id !== outcome.id) - await deleteOutcomeUseCase.execute({ parentId: goals!.id, id: outcome.id }) -} +const onDelete = async (id: Uuid) => { + await deleteOutcomeUseCase.execute({ parentId: goals!.id, id }) -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } + outcomes.value = await getOutcomesUseCase.execute(goals!.id) ?? [] } @@ -117,14 +81,8 @@ const onSort = (event: any) => { of the system that will be achieved by the associated project.

- - - - + - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/modules/goals/ui/pages/Stakeholders.vue b/modules/goals/ui/pages/Stakeholders.vue index 9ff030f4..e45065ef 100644 --- a/modules/goals/ui/pages/Stakeholders.vue +++ b/modules/goals/ui/pages/Stakeholders.vue @@ -11,7 +11,7 @@ import CreateStakeholderUseCase from '../../application/CreateStakeholderUseCase import UpdateStakeHolderUseCase from '../../application/UpdateStakeHolderUseCase'; import DeleteStakeholderUseCase from '../../application/DeleteStakeholderUseCase'; import mermaid from 'mermaid'; -import { emptyUuid } from '~/domain/Uuid'; +import { emptyUuid, type Uuid } from '~/domain/Uuid'; import GetStakeHolderByIdUseCase from '../../application/GetStakeHolderByIdUseCase'; const router = useRouter(), @@ -43,20 +43,18 @@ type StakeHolderViewModel = Pick([]), category = ref(Object.values(StakeholderCategory)), segmentation = ref(Object.values(StakeholderSegmentation)), - editingRows = ref([]), - dataTable = ref(); + emptyStakeholder: StakeHolderViewModel = { + id: emptyUuid, + name: '', + statement: '', + availability: Stakeholder.AVAILABILITY_MIN, + influence: Stakeholder.INFLUENCE_MIN, + category: StakeholderCategory.KeyStakeholder, + segmentation: StakeholderSegmentation.Client + }; onMounted(async () => { - stakeholders.value = (await getStakeHoldersUseCase.execute(goals!.id) ?? []) - .map(o => ({ - id: o.id, - name: o.name, - statement: o.statement, - availability: o.availability, - influence: o.influence, - category: o.category, - segmentation: o.segmentation - })) + stakeholders.value = await getStakeHoldersUseCase.execute(goals!.id) ?? [] }) const filters = ref({ @@ -109,114 +107,31 @@ watch(stakeholders, async () => { }) }); -const createDisabled = ref(false) - -const addNewRow = () => { - stakeholders.value.unshift(new Stakeholder({ - id: emptyUuid, - parentId: goals!.id, - property: '', - name: '', - statement: '', - availability: Stakeholder.AVAILABILITY_MIN, - influence: Stakeholder.INFLUENCE_MIN, - segmentation: StakeholderSegmentation.Client - })) - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null - editingRows.value = [stakeholders.value[0]] - - // focus on the first input - setTimeout(() => { - const input = document.querySelector('.p-datatable-tbody tr input')! as HTMLInputElement - input.focus() - }, 100) -} - -const onRowEditSave = async (event: { newData: StakeHolderViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const row = (originalEvent.target! as HTMLElement).closest('tr')!, - inputs = row.querySelectorAll('input'), - dropDowns = row.querySelectorAll('.p-dropdown[required="true"]') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (![...dropDowns].every(dd => { - const value = dd.querySelector('.p-inputtext')!.textContent?.trim(), - result = value !== '' && !value?.startsWith('Select') - - dd.classList.toggle('p-invalid', !result) - - return result - })) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createStakeHolderUseCase.execute({ - parentId: goals!.id, - name: newData.name, - statement: newData.statement, - availability: newData.availability, - influence: newData.influence, - segmentation: newData.segmentation - }) +const onCreate = async (data: StakeHolderViewModel) => { + const stakeholder = await createStakeHolderUseCase.execute({ + ...data, + parentId: goals!.id + }); - const newStakeholder = (await getStakeHolderByIdUseCase.execute(newId))! - stakeholders.value[index] = newStakeholder - createDisabled.value = false - } else { - await updateStakeHolderUseCase.execute({ - parentId: goals!.id, - id: newData.id, - name: newData.name, - statement: newData.statement, - availability: newData.availability, - influence: newData.influence, - segmentation: newData.segmentation - }) - - const newStakeholder = (await getStakeHolderByIdUseCase.execute(newData.id))! - stakeholders.value[index] = newStakeholder - } + stakeholders.value = await getStakeHoldersUseCase.execute(goals!.id) ?? [] } -const onRowEditInit = ({ originalEvent }: any) => { - // focus on the first input when editing - const row = originalEvent.target.closest('tr') - setTimeout(() => { - const input = row.querySelector('input') - input.focus() - }, 100) -} - -const onRowEditCancel = ({ data, index }: { data: StakeHolderViewModel, index: number }) => { - if (data.id !== emptyUuid) - return +const onUpdate = async (data: StakeHolderViewModel) => { + await updateStakeHolderUseCase.execute({ + ...data, + parentId: goals!.id + }) - stakeholders.value.splice(index, 1) - createDisabled.value = false + stakeholders.value = await getStakeHoldersUseCase.execute(goals!.id) ?? [] } -const onRowDelete = async (stakeHolder: StakeHolderViewModel) => { - if (!confirm(`Are you sure you want to delete ${stakeHolder.name}?`)) - return - stakeholders.value = stakeholders.value.filter(o => o.id !== stakeHolder.id) - - await deleteStakeholderUseCase.execute({ parentId: goals!.id, id: stakeHolder.id }) -} +const onDelete = async (id: Uuid) => { + await deleteStakeholderUseCase.execute({ + parentId: goals!.id, + id + }) -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } + stakeholders.value = await getStakeHoldersUseCase.execute(goals!.id) ?? [] } @@ -229,17 +144,8 @@ const onSort = (event: any) => { - - - - - + - - - - - - - +
- - \ No newline at end of file + \ No newline at end of file diff --git a/modules/goals/ui/pages/UseCases.vue b/modules/goals/ui/pages/UseCases.vue index ff3d4bed..c7d61d0d 100644 --- a/modules/goals/ui/pages/UseCases.vue +++ b/modules/goals/ui/pages/UseCases.vue @@ -46,9 +46,8 @@ if (!solution) { type UseCaseViewModel = Pick; const useCases = ref([]), - stakeHolders = ref(await getStakeholdersUseCase.execute(goals!.id) ?? []), - editingRows = ref([]), - dataTable = ref(); + emptyUseCase: UseCaseViewModel = { id: emptyUuid, name: '', statement: '', primaryActorId: emptyUuid }, + stakeHolders = ref(await getStakeholdersUseCase.execute(goals!.id) ?? []) onMounted(async () => { useCases.value = await getUseCaseUseCase.execute(goals!.id) ?? [] @@ -60,103 +59,43 @@ const filters = ref({ 'statement': { value: null, matchMode: FilterMatchMode.CONTAINS }, }); -const createDisabled = ref(false) +const onCreate = async (data: UseCaseViewModel) => { + const newId = await createUseCaseUseCase.execute({ + ...data, + parentId: goals!.id + }); -const addNewRow = () => { - useCases.value.unshift({ id: emptyUuid, name: '', statement: '', primaryActorId: emptyUuid }) - editingRows.value = [useCases.value[0]] - createDisabled.value = true - // remove the sortfield to avoid the new row from being sorted - dataTable.value!.d_sortField = null -} - -const onRowEditSave = async (event: { newData: UseCaseViewModel, index: number, originalEvent: Event }) => { - const { newData, index, originalEvent } = event - - const row = (originalEvent.target! as HTMLElement).closest('tr')!, - inputs = row.querySelectorAll('input'), - dropDowns = row.querySelectorAll('.p-dropdown[required="true"]') - - if (![...inputs].every(o => o.reportValidity())) { - editingRows.value = [newData] - return - } - - if (![...dropDowns].every(dd => { - const value = dd.querySelector('.p-inputtext')!.textContent?.trim(), - result = value !== '' && !value?.startsWith('Select') - - dd.classList.toggle('p-invalid', !result) - - return result - })) { - editingRows.value = [newData] - return - } - - if (newData.id === emptyUuid) { - const newId = await createUseCaseUseCase.execute({ - parentId: goals!.id, - name: newData.name, - statement: newData.statement, - primaryActorId: newData.primaryActorId - }) - - useCases.value[index] = { - id: newId, - name: newData.name, - statement: newData.statement, - primaryActorId: newData.primaryActorId - } - createDisabled.value = false - } else { - useCases.value[index] = newData - await updateUseCaseUseCase.execute(newData) - } + useCases.value = await getUseCaseUseCase.execute(goals!.id) ?? [] } -const onRowEditCancel = ({ data, index }: { data: UseCaseViewModel, index: number }) => { - if (data.id !== emptyUuid) - return - - useCases.value.splice(index, 1) - createDisabled.value = false +const onDelete = async (id: Uuid) => { + await deleteUseCaseUseCase.execute({ id, parentId: goals!.id }); + useCases.value = await getUseCaseUseCase.execute(goals!.id) ?? [] } -const onRowDelete = async (useCase: UseCaseViewModel) => { - if (!confirm('Are you sure you want to delete this Use Case?')) - return - useCases.value = useCases.value.filter(u => u.id !== useCase.id) - - await deleteUseCaseUseCase.execute({ id: useCase.id, parentId: goals!.id }) -} +const onUpdate = async (data: UseCaseViewModel) => { + await updateUseCaseUseCase.execute({ + ...data, + }); -const onSort = (event: any) => { - if (editingRows.value.length > 0) { - editingRows.value = [] - createDisabled.value = false - } + useCases.value = await getUseCaseUseCase.execute(goals!.id) ?? [] } - \ No newline at end of file + \ No newline at end of file diff --git a/modules/solution/ui/pages/solution/[solutionSlug].vue b/modules/solution/ui/pages/solution/[solutionSlug].vue index ee7f4eda..0ec634a2 100644 --- a/modules/solution/ui/pages/solution/[solutionSlug].vue +++ b/modules/solution/ui/pages/solution/[solutionSlug].vue @@ -11,24 +11,20 @@ const router = useRouter(), if (!solution) router.push({ name: 'Solutions' }); + +const links = [ + { name: 'Project', icon: 'pi-box', label: 'Project' }, + { name: 'Environment', icon: 'pi-cloud', label: 'Environment' }, + { name: 'Goals', icon: 'pi-bullseye', label: 'Goals' }, + { name: 'System', icon: 'pi-sitemap', label: 'System' } +]