Skip to content

Commit

Permalink
Formalizes URL Structure
Browse files Browse the repository at this point in the history
  • Loading branch information
gbdubs committed Jan 22, 2024
1 parent 13136cc commit 7b044c0
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 261 deletions.
3 changes: 2 additions & 1 deletion frontend/components/analysis/ContextualListView.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { AnalysisType, type Analysis } from '@/openapi/generated/pacta'
import { linkToAnalysis } from '@/lib/mydata'
const { humanReadableTimeFromStandardString } = useTime()
const i18n = useI18n()
Expand Down Expand Up @@ -98,7 +99,7 @@ const reportButtonClasses = computed(() => {
<LinkButton
class="p-button-outlined p-button-xs p-button-secondary"
icon="pi pi-arrow-right"
:to="localePath(`/my-data?tab=a&analyses=${slotProps.data.id}`)"
:to="linkToAnalysis(localePath, slotProps.data.id)"
/>
</template>
</PVColumn>
Expand Down
35 changes: 27 additions & 8 deletions frontend/components/analysis/ListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,27 @@ interface Props {
portfolioGroups: PortfolioGroup[]
initiatives: Initiative[]
analyses: Analysis[]
selectedPortfolioIds: string[]
selectedPortfolioGroupIds: string[]
selectedAnalysisIds: string[]
expandedAnalysisIds: string[]
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:selectedPortfolioIds', value: string[]): void
(e: 'update:selectedPortfolioGroupIds', value: string[]): void
(e: 'update:selectedAnalysisIds', value: string[]): void
(e: 'update:expandedAnalysisIds', value: string[]): void
(e: 'refresh'): void
}
const emit = defineEmits<Emits>()
const refresh = () => { emit('refresh') }
const selectedAnalysisIDs = computed({
const selectedAnalysisIdsModel = computed({
get: () => props.selectedAnalysisIds ?? [],
set: (value: string[]) => { emit('update:selectedAnalysisIds', value) },
})
const expandedAnalysisIdsModel = computed({
get: () => props.expandedAnalysisIds ?? [],
set: (value: string[]) => { emit('update:expandedAnalysisIds', value) },
})
interface EditorObject extends ReturnType<typeof analysisEditor> {
id: string
Expand All @@ -44,16 +46,33 @@ interface EditorObject extends ReturnType<typeof analysisEditor> {
const prefix = 'components/analysis/ListView'
const tt = (s: string) => t(`${prefix}.${s}`)
const expandedRows = useState<EditorObject[]>(`${prefix}.expandedRows`, () => [])
const selectedRows = computed<EditorObject[]>({
get: () => {
const ids = selectedAnalysisIDs.value
const ids = selectedAnalysisIdsModel.value
return editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
},
set: (value: EditorObject[]) => {
const ids = value.map((row) => row.id)
ids.sort()
selectedAnalysisIdsModel.value = ids
},
})
const readyToExpand = useState<boolean>(`${prefix}.readyToExpand`, () => false)
onMounted(() => {
readyToExpand.value = true
})
const expandedRows = computed<EditorObject[]>({
get: () => {
if (!readyToExpand.value) {
return []
}
const ids = expandedAnalysisIdsModel.value
return editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
},
set: (value: EditorObject[]) => {
const ids = value.map((row) => row.id)
ids.sort()
selectedAnalysisIDs.value = ids
expandedAnalysisIdsModel.value = ids
},
})
Expand Down
3 changes: 2 additions & 1 deletion frontend/components/analysis/RunButton.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { type RunAnalysisReq, type Analysis, type AnalysisType } from '@/openapi/generated/pacta'
import { linkToAnalysis } from '@/lib/mydata'
const pactaClient = usePACTA()
const { loading: { withLoading } } = useModal()
Expand Down Expand Up @@ -98,7 +99,7 @@ const completeBtnTo = computed(() => {
if (!analysisId.value) {
return ''
}
return localePath(`/my-data?tab=a&analyses=${analysisId.value}`)
return linkToAnalysis(localePath, analysisId.value)
})
const completeBtnLabel = computed(() => {
if (!analysisId.value) {
Expand Down
45 changes: 36 additions & 9 deletions frontend/components/portfolio/ListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { portfolioEditor } from '@/lib/editor'
import { type Portfolio, type PortfolioGroup, type Initiative, type Analysis } from '@/openapi/generated/pacta'
import { selectedCountSuffix } from '@/lib/selection'
import { linkToPortfolioGroup } from '@/lib/mydata'
const {
humanReadableTimeFromStandardString,
Expand All @@ -18,24 +19,26 @@ interface Props {
initiatives: Initiative[]
analyses: Analysis[]
selectedPortfolioIds: string[]
selectedPortfolioGroupIds: string[]
selectedAnalysisIds: string[]
expandedPortfolioIds: string[]
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:selectedPortfolioIds', value: string[]): void
(e: 'update:selectedPortfolioGroupIds', value: string[]): void
(e: 'update:selectedAnalysisIds', value: string[]): void
(e: 'update:expandedPortfolioIds', value: string[]): void
(e: 'refresh'): void
}
const emit = defineEmits<Emits>()
const refresh = () => { emit('refresh') }
const selectedPortfolioIDs = computed({
const selectedPortfolioIdsModel = computed({
get: () => props.selectedPortfolioIds ?? [],
set: (value: string[]) => { emit('update:selectedPortfolioIds', value) },
})
const expandedPortfolioIdsModel = computed({
get: () => props.expandedPortfolioIds ?? [],
set: (value: string[]) => { emit('update:expandedPortfolioIds', value) },
})
interface EditorObject extends ReturnType<typeof portfolioEditor> {
id: string
Expand All @@ -44,16 +47,36 @@ interface EditorObject extends ReturnType<typeof portfolioEditor> {
const prefix = 'components/portfolio/ListView'
const tt = (s: string) => t(`${prefix}.${s}`)
const expandedRows = useState<EditorObject[]>(`${prefix}.expandedRows`, () => [])
const selectedRows = computed<EditorObject[]>({
get: () => {
const ids = selectedPortfolioIDs.value
const ids = selectedPortfolioIdsModel.value
return editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
},
set: (value: EditorObject[]) => {
const ids = value.map((row) => row.id)
ids.sort()
selectedPortfolioIDs.value = ids
selectedPortfolioIdsModel.value = ids
},
})
const readyToExpand = useState<boolean>(`${prefix}.readyToExpand`, () => false)
onMounted(() => {
readyToExpand.value = true
})
const expandedRows = computed<EditorObject[]>({
get: () => {
if (!readyToExpand.value) {
return []
}
const ids = expandedPortfolioIdsModel.value
const result = editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
console.log('expandedRows = ', result.length)
return result
},
set: (value: EditorObject[]) => {
const ids = value.map((row) => row.id)
ids.sort()
expandedPortfolioIdsModel.value = ids
},
})
Expand Down Expand Up @@ -85,6 +108,10 @@ const deleteSelected = () => Promise.all([selectedRows.value.map((row) => delete
<template>
<div class="flex flex-column gap-3">
<div class="flex gap-2 flex-wrap">
<StandardDebug
:value="props.expandedPortfolioIds"
label="Expanded Portfolio IDs"
/>
<PVButton
icon="pi pi-refresh"
class="p-button-outlined p-button-secondary p-button-sm"
Expand Down Expand Up @@ -155,7 +182,7 @@ const deleteSelected = () => Promise.all([selectedRows.value.map((row) => delete
class="p-button-outlined p-button-xs"
icon="pi pi-table"
:label="membership.portfolioGroup.name"
:to="localePath(`/my-data?tab=pg&pgids=${membership.portfolioGroup.id}`)"
:to="linkToPortfolioGroup(localePath, membership.portfolioGroup.id)"
/>
</div>
<div
Expand Down
41 changes: 32 additions & 9 deletions frontend/components/portfolio/group/ListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { portfolioGroupEditor } from '@/lib/editor'
import { type Portfolio, type PortfolioGroup, type PortfolioGroupMembershipPortfolio, type Analysis } from '@/openapi/generated/pacta'
import { selectedCountSuffix } from '@/lib/selection'
import { linkToPortfolios } from '@/lib/mydata'
const {
humanReadableTimeFromStandardString,
Expand All @@ -16,23 +17,25 @@ interface Props {
portfolios: Portfolio[]
portfolioGroups: PortfolioGroup[]
analyses: Analysis[]
selectedPortfolioIds: string[]
selectedPortfolioGroupIds: string[]
selectedAnalysisIds: string[]
expandedPortfolioGroupIds: string[]
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:selectedPortfolioIds', value: string[]): void
(e: 'update:selectedPortfolioGroupIds', value: string[]): void
(e: 'update:selectedAnalysisIds', value: string[]): void
(e: 'update:expandedPortfolioGroupIds', value: string[]): void
(e: 'refresh'): void
}
const emit = defineEmits<Emits>()
const selectedPortfolioGroupIDs = computed({
const selectedPortfolioGroupIdsModel = computed({
get: () => props.selectedPortfolioGroupIds ?? [],
set: (value: string[]) => { emit('update:selectedPortfolioGroupIds', value) },
})
const expandedPortfolioGroupIdsModel = computed({
get: () => props.expandedPortfolioGroupIds ?? [],
set: (value: string[]) => { emit('update:expandedPortfolioGroupIds', value) },
})
interface EditorObject extends ReturnType<typeof portfolioGroupEditor> {
id: string
Expand All @@ -50,13 +53,33 @@ const editorObjects = computed<EditorObject[]>(() => props.portfolioGroups.map(
}),
))
const expandedRows = useState<EditorObject[]>(`${prefix}.expandedRows`, () => [])
const selectedRows = computed<EditorObject[]>({
get: () => {
return editorObjects.value.filter((editorObject) => selectedPortfolioGroupIDs.value.includes(editorObject.id))
const ids = selectedPortfolioGroupIdsModel.value
return editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
},
set: (value: EditorObject[]) => {
const ids = value.map((row) => row.id)
ids.sort()
selectedPortfolioGroupIdsModel.value = ids
},
})
const readyToExpand = useState<boolean>(`${prefix}.readyToExpand`, () => false)
onMounted(() => {
readyToExpand.value = true
})
const expandedRows = computed<EditorObject[]>({
get: () => {
if (!readyToExpand.value) {
return []
}
const ids = expandedPortfolioGroupIdsModel.value
return editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
},
set: (value: EditorObject[]) => {
selectedPortfolioGroupIDs.value = value.map((row) => row.id)
const ids = value.map((row) => row.id)
ids.sort()
expandedPortfolioGroupIdsModel.value = ids
},
})
Expand Down Expand Up @@ -142,7 +165,7 @@ const editorObjectToIds = (editorObject: EditorObject): string[] => {
<template #body="slotProps">
<LinkButton
:disabled="editorObjectToIds(slotProps.data).length === 0"
:to="localePath(`/my-data?tab=p&pids=${ editorObjectToIds(slotProps.data).join(',')}`)"
:to="linkToPortfolios(localePath, editorObjectToIds(slotProps.data))"
:label="`${editorObjectToIds(slotProps.data).length}`"
icon="pi pi-th-large"
class="py-1 px-2 p-button-outlined p-button-secondary"
Expand Down
55 changes: 55 additions & 0 deletions frontend/lib/mydata/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { type LocalePathFunction } from 'vue-i18n-routing'

const pageURLBase = '/my-data'

export const QueryParamTab = 'tab'
export const QueryParamSelectedPortfolioIds = 'sp'
export const QueryParamExpandedPortfolioIds = 'ep'
export const QueryParamSelectedPortfolioGroupIds = 'sg'
export const QueryParamExpandedPortfolioGroupIds = 'eg'
export const QueryParamSelectedAnalysisIds = 'sa'
export const QueryParamExpandedAnalysisIds = 'ea'

export enum Tab {
Portfolio = 'p',
PortfolioGroup = 'g',
IncompleteUpload = 'i',
Analysis = 'a',
}

export const linkToPortfolio = (localePath: LocalePathFunction, id: string): string => {
return linkToPortfolios(localePath, [id])
}

export const linkToPortfolios = (localePath: LocalePathFunction, ids: string[]): string => {
const q = new URLSearchParams()
q.set(QueryParamExpandedPortfolioIds, ids.join(','))
q.set(QueryParamTab, Tab.Portfolio)
return localePath(pageURLBase + '?' + q.toString())
}

export const linkToPortfolioGroup = (localePath: LocalePathFunction, id: string): string => {
const q = new URLSearchParams()
q.set(QueryParamExpandedPortfolioGroupIds, id)
q.set(QueryParamTab, Tab.PortfolioGroup)
return localePath(pageURLBase + '?' + q.toString())
}

export const linkToAnalysis = (localePath: LocalePathFunction, id: string): string => {
const q = new URLSearchParams()
q.set(QueryParamSelectedAnalysisIds, id)
q.set(QueryParamTab, Tab.Analysis)
return localePath(pageURLBase + '?' + q.toString())
}

export const linkToIncompleteUpload = (localePath: LocalePathFunction): string => {
const q = new URLSearchParams()
q.set(QueryParamTab, Tab.IncompleteUpload)
return localePath(pageURLBase + '?' + q.toString())
}

export const linkToPortfolioList = (localePath: LocalePathFunction): string => {
const q = new URLSearchParams()
q.set(QueryParamTab, Tab.Portfolio)
return localePath(pageURLBase + '?' + q.toString())
}
13 changes: 5 additions & 8 deletions frontend/pages/audit-logs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type AuditLogQuerySort, type AuditLogQueryWhere, type AuditLogQueryReq,
import { urlReactiveAuditLogQuery } from '@/lib/auditlogquery'
import { type DataTableSortMeta } from 'primevue/datatable'
import { FilterMatchMode } from 'primevue/api'
import { linkToPortfolio, linkToPortfolioGroup, linkToAnalysis, linkToIncompleteUpload } from '@/lib/mydata'
const prefix = 'pages/audit-logs'
Expand Down Expand Up @@ -416,18 +417,14 @@ const tableSortModel = computed<DataTableSortMeta[]>({
const getTargetLink = (t: AuditLogTargetType, id: string): string => {
switch (t) {
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_PORTFOLIO:
// TODO(grady) make this directly addressable
return localePath(`/my-data/${id}`)
return linkToPortfolio(localePath, id)
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_PORTFOLIO_GROUP:
// TODO(grady) make this directly addressable
return localePath(`/my-data/${id}`)
return linkToPortfolioGroup(localePath, id)
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_INCOMPLETE_UPLOAD:
// TODO(grady) make this directly addressable
return localePath(`/my-data/${id}`)
return linkToIncompleteUpload(localePath)
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_ANALYSIS:
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_ANALYSIS_ARTIFACT:
// TODO(grady) make this directly addressable
return localePath(`/my-data/${id}`)
return linkToAnalysis(localePath, id)
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_USER:
return localePath(`/user/${id}`)
case AuditLogTargetType.AUDIT_LOG_TARGET_TYPE_INITIATIVE:
Expand Down
Loading

0 comments on commit 7b044c0

Please sign in to comment.