From 70842ebcb0c5f94bcc473a1c4dc0d79d6cc046a3 Mon Sep 17 00:00:00 2001
From: Michael Haufe
Date: Mon, 10 Jun 2024 20:38:06 -0500
Subject: [PATCH] Unified and abstracted DataTables as XDataTable component
(#137)
---
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 data found
+ Loading data...
+
+
+
+
\ 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".
-
-
-
-
-
-
+
@@ -151,22 +101,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No assumptions found
- Loading assumptions...
-
-
-
\ 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.
-
-
-
-
-
-
+
@@ -149,22 +99,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No components found
- Loading components...
-
-
-
\ 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.
-
-
-
-
-
-
+
@@ -165,22 +114,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No constraints found
- Loading constraints...
-
-
-
\ 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."
-
-
-
-
-
-
+
@@ -150,22 +105,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No effects found
- Loading effects...
-
-
-
\ 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.
-
-
-
-
-
-
+
@@ -148,22 +104,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No Glossary terms found
- Loading Glossary...
-
-
-
\ 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' }
+]
@@ -32,28 +41,9 @@ if (!solution) {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/environment/ui/pages/Invariants.vue b/modules/environment/ui/pages/Invariants.vue
index 7f6e552b..3195f519 100644
--- a/modules/environment/ui/pages/Invariants.vue
+++ b/modules/environment/ui/pages/Invariants.vue
@@ -1,6 +1,6 @@
@@ -117,15 +80,9 @@ const onSort = (event: any) => {
Invariants are properties that must always be true. They are used to
constrain the possible states of a system.
-
-
-
-
-
-
+
+
@@ -149,22 +106,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No invariants found
- Loading 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' }
+]
@@ -32,29 +41,10 @@ if (!solution) {
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
\ 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) ?? []
}
@@ -116,14 +81,8 @@ const onSort = (event: any) => {
Example: "Providing an interface to the user to change the color of the background is out-of-scope."
-
-
-
-
-
-
+
@@ -147,22 +106,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No Limitations found
- Loading Limitations...
-
-
-
\ 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
- }
-}
@@ -116,14 +81,8 @@ const onSort = (event: any) => {
Obstacles are the challenges that prevent the goals from being achieved.
-
-
-
-
-
-
+
@@ -147,22 +106,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No Obstacles found
- Loading Obstacles...
-
-
-
\ 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.
-
-
-
-
-
-
+
@@ -148,22 +106,5 @@ const onSort = (event: any) => {
-
-
-
-
-
-
-
-
-
-
- No Outcomes found
- Loading Outcomes...
-
-
-
\ 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 Stakeholders found.
- Loading Stakeholders...
-
+
-
-
\ 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) ?? []
}
A Use Case describes the interaction between a system and an actor to achieve a specific goal.
- These can be thought of as analogous Epics
+ These can be thought of as analogous Epics.
+
+
+ Before you can define a Use Case, you must define one or more
+ Actors .
-
-
-
-
-
-
+
{
-
-
-
-
-
-
-
-
-
-
-
- No Use Cases found.
- Before you can define a Use Case, you must define one or more
- Actors
-
- Loading Use Cases...
-
+
Diagram
-
-
\ 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' }
+]
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/modules/system/ui/pages/Index.vue b/modules/system/ui/pages/Index.vue
index 6ee9533c..62abd434 100644
--- a/modules/system/ui/pages/Index.vue
+++ b/modules/system/ui/pages/Index.vue
@@ -1,14 +1,29 @@
System
-
-
+