Skip to content

Commit

Permalink
Initial Redesign of Portfolio List View
Browse files Browse the repository at this point in the history
  • Loading branch information
gbdubs committed Jan 23, 2024
1 parent 1ae349b commit c343f98
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 18 deletions.
4 changes: 4 additions & 0 deletions frontend/assets/css/overrides.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ div.p-chips .p-chips-multiple-container {
div.p-chips .p-chips-multiple-container .p-chips-token {
margin-right: 0;
}

div.p-accordion .p-accordion-header:not(.p-disabled).p-highlight .p-accordion-header-link {
background-color: #f5f5f5
}
29 changes: 29 additions & 0 deletions frontend/components/CommonAccordionHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
interface Props {
heading: string
subHeading?: string | undefined
icon?: string | undefined
}
const props = defineProps<Props>()
</script>

<template>
<div class="flex justify-content-between align-items-center w-full flex-wrap px-2">
<div class="flex gap-1 flex-column">
<div class="text-lg font-bold">
{{ props.heading }}
</div>
<div
v-if="props.subHeading"
class="text-sm font-light"
>
{{ props.subHeading }}
</div>
</div>
<i
v-if="props.icon"
:class="props.icon"
/>
<slot />
</div>
</template>
103 changes: 85 additions & 18 deletions frontend/components/portfolio/ListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { portfolioEditor } from '@/lib/editor'
import { type Portfolio, AuditLogQuerySortBy, type PortfolioGroup, type Initiative, type Analysis } from '@/openapi/generated/pacta'
import { selectedCountSuffix } from '@/lib/selection'
import { createURLAuditLogQuery } from '@/lib/auditlogquery'
import { type WritableComputedRef } from 'vue'
const { linkToPortfolioGroup } = useMyDataURLs()
const { humanReadableTimeFromStandardString } = useTime()
Expand All @@ -19,11 +20,13 @@ interface Props {
analyses: Analysis[]
selectedPortfolioIds: string[]
expandedPortfolioIds: string[]
expandedSections: Map<string, number[]>
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:selectedPortfolioIds', value: string[]): void
(e: 'update:expandedPortfolioIds', value: string[]): void
(e: 'update:expandedSections', value: Map<string, number[]>): void
(e: 'refresh'): void
}
const emit = defineEmits<Emits>()
Expand All @@ -38,11 +41,15 @@ const expandedPortfolioIdsModel = computed({
get: () => props.expandedPortfolioIds ?? [],
set: (value: string[]) => { emit('update:expandedPortfolioIds', value) },
})
const expendedPortfolioSections = useState<Map<string, number[]>>('ListView.expandedPortfolioSections', () => new Map())
const expandedSectionsModel = computed({
get: () => props.expandedSections ?? new Map<string, number[]>(),
set: (value: Map<string, number[]>) => { emit('update:expandedSections', value) },
})
interface EditorObject extends ReturnType<typeof portfolioEditor> {
id: string
analyses: Analysis[]
expandedSections: WritableComputedRef<number[]>
}
const prefix = 'components/portfolio/ListView'
Expand Down Expand Up @@ -70,7 +77,6 @@ const expandedRows = computed<EditorObject[]>({
}
const ids = expandedPortfolioIdsModel.value
const result = editorObjects.value.filter((editorObject) => ids.includes(editorObject.id))
console.log('expandedRows = ', result.length)
return result
},
set: (value: EditorObject[]) => {
Expand All @@ -80,11 +86,22 @@ const expandedRows = computed<EditorObject[]>({
},
})
const editorObjects = computed<EditorObject[]>(() => props.portfolios.map((item) => ({
id: item.id,
...portfolioEditor(item, i18n),
analyses: props.analyses.filter((a) => a.portfolioSnapshot.portfolio?.id === item.id),
})))
const editorObjects = computed<EditorObject[]>(() => props.portfolios.map((item) => {
const expandedSectionSuffix = item.id.substring(item.id.length - 4)
return ({
...portfolioEditor(item, i18n),
id: item.id,
analyses: props.analyses.filter((a) => a.portfolioSnapshot.portfolio?.id === item.id),
expandedSections: computed<number[]>({
get: () => expandedSectionsModel.value.get(expandedSectionSuffix) ?? [],
set: (value: number[]) => {
const m = new Map<string, number[]>(expandedSectionsModel.value)
m.set(expandedSectionSuffix, value)
expandedSectionsModel.value = m
},
}),
})
}))
const selectedPortfolios = computed<Portfolio[]>(() => selectedRows.value.map((row) => row.currentValue.value))
Expand Down Expand Up @@ -217,16 +234,21 @@ const auditLogURL = (id: string) => {
#expansion="slotProps"
>
<div class="surface-100 p-3">
<h2 class="mb-3">
<h2 class="mb-3 mt-0">
{{ tt('Portfolio') }}: {{ slotProps.data.currentValue.value.name }}
</h2>
<PVAccordion
v-model:activeIndex="expendedPortfolioSections[slotProps.data.id]"
v-model:activeIndex="slotProps.data.expandedSections.value"
:multiple="true"
>
<PVAccordionTab
:header="tt('Edit Portfolio')"
>
<PVAccordionTab>
<template #header>
<CommonAccordionHeader
:heading="tt('EditHeading')"
:sub-heading="tt('EditSubHeading')"
icon="pi pi-pencil"
/>
</template>
<PortfolioEditor
v-model:editor-values="slotProps.data.editorValues.value"
:editor-fields="slotProps.data.editorFields.value"
Expand All @@ -250,9 +272,28 @@ const auditLogURL = (id: string) => {
</div>
</div>
</PVAccordionTab>
<PVAccordionTab
:header="tt('Memberships')"
>
<PVAccordionTab>
<template #header>
<CommonAccordionHeader
:heading="tt('MembershipsHeading')"
:sub-heading="tt('MembershipsSubHeading')"
>
<div class="flex gap-1 justify-content-center">
<PVInlineMessage
severity="info"
icon="pi pi-table"
>
{{ slotProps.data.currentValue.value.groups.length }}
</PVInlineMessage>
<PVInlineMessage
severity="info"
icon="pi pi-sitemap"
>
{{ slotProps.data.currentValue.value.initiatives.length }}
</PVInlineMessage>
</div>
</CommonAccordionHeader>
</template>
<div class="flex flex-column gap-2">
<PortfolioGroupMembershipMenuButton
:selected-portfolios="[slotProps.data.currentValue.value]"
Expand All @@ -267,16 +308,42 @@ const auditLogURL = (id: string) => {
/>
</div>
</PVAccordionTab>
<PVAccordionTab :header="tt('Analysis')">
<PVAccordionTab>
<template #header>
<CommonAccordionHeader
:heading="tt('AnalysesHeading')"
:sub-heading="tt('AnalysesSubHeading')"
>
<PVInlineMessage
v-if="slotProps.data.analyses.length === 0"
severity="success"
icon="pi pi-copy"
>
{{ tt('AnalysesComeHereChip') }}
</PVInlineMessage>
<div
v-else
class="bg-red-500"
>
{{ slotProps.data.analyses.map((a: Analysis) => a.analysisType) }}
</div>
</CommonAccordionHeader>
</template>
<AnalysisContextualListView
:analyses="slotProps.data.analyses"
:name="slotProps.data.currentValue.value.name"
:portfolio-id="slotProps.data.id"
@refresh="refresh"
/>
</PVAccordionTab>

<PVAccordionTab :header="tt('More Options')">
<PVAccordionTab>
<template #header>
<CommonAccordionHeader
:heading="tt('MoreHeading')"
:sub-heading="tt('MoreSubHeading')"
icon="pi pi-plus"
/>
</template>
<FormField
:label="tt('Audit Logs')"
:help-text="tt('AuditLogsHelpText')"
Expand Down
17 changes: 17 additions & 0 deletions frontend/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,23 @@
"Groups": "Groups",
"How To Run a Report": "How To Run a Report",
"Initiatives": "Initiatives",
"EditHeading": "Edit Portfolio",
"EditSubHeading": "Modify portfolio metadata, for organization and to change how it is analyzed.",
"MembershipsHeading": "Portfolio Groups and Initiative Participation",
"MembershipsSubHeading": "Manage which portfolio groups this portfolio is a part of, and which initiatives it is a member of.",
"AnalysesHeading": "Reports and Audits",
"AnalysesSubHeading": "View and create reports and audits about this portfolio.",
"AnalysesComeHereChip": "Running an audit is recommended",
"MoreHeading": "Settings and More",
"MoreSubHeading": "View audit logs, delete this portfolio, view debugging information",
"Audit Logs": "Audit Logs",
"View Audit Logs": "View Audit Logs For Portfolio",
"AuditLogsHelpText": "Audit logs are a record of who has accessed or modified this analysis, and when. This is useful for debugging, for understanding who has seen this analysis, and for establishing peace of mind that your data's security is being upheld.",
"Raw Portfolio Metadata": "Raw Portfolio Metadata",
"RawPortfolioMetadataHelpText": "This is the raw metadata for this portfolio. It is not editable, and is only shown for reference and technical debugging. If you're having a problem with this portfolio, attaching the metadata here to a bug report may be helpful.",
"Portfolio Metadata": "Portfolio Metadata",
"Delete Portfolio": "Delete Portfolio",
"DeletePortfolioHelpText": "This will delete this portfolio from the platform, including all of the analyses that it has been a part of. It will also remove the portfolio from all initiatives and portfolio groups. This action cannot be undone, proceed with caution.",
"Memberships": "Portfolio Groups and Initiative Participation",
"Name": "Name",
"Upload New Portfolios": "Upload New Portfolios",
Expand Down
1 change: 1 addition & 0 deletions frontend/lib/mydata/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const QueryParamSelectedPortfolioGroupIds = 'sg'
export const QueryParamExpandedPortfolioGroupIds = 'eg'
export const QueryParamSelectedAnalysisIds = 'sa'
export const QueryParamExpandedAnalysisIds = 'ea'
export const QueryParamExpandedSections = 'es'

export enum Tab {
Portfolio = 'p',
Expand Down
22 changes: 22 additions & 0 deletions frontend/pages/my-data.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
QueryParamExpandedPortfolioGroupIds,
QueryParamSelectedAnalysisIds,
QueryParamExpandedAnalysisIds,
QueryParamExpandedSections,
} from '@/lib/mydata'
const prefix = 'pages/my-data'
Expand All @@ -31,6 +32,26 @@ const expandedPortfolioGroupIds = joinedWithCommas(fromQueryReactiveWithDefault(
const selectedAnalysisIds = joinedWithCommas(fromQueryReactiveWithDefault(QueryParamSelectedAnalysisIds, ''))
const expandedAnalysisIds = joinedWithCommas(fromQueryReactiveWithDefault(QueryParamExpandedAnalysisIds, ''))
const tabQP = fromQueryReactiveWithDefault(QueryParamTab, 'p')
const expandedSectionsArray = joinedWithCommas(fromQueryReactiveWithDefault(QueryParamExpandedSections, ''))
const expandedSections = computed<Map<string, number[]>>({
get: () => {
const result = new Map<string, number[]>()
expandedSectionsArray.value.forEach((v) => {
const [k, ...vv] = v.split(':')
result.set(k, vv.map((vvv) => parseInt(vvv)))
})
return result
},
set: (v: Map<string, number[]>) => {
const result: string[] = []
v.forEach((vv, k) => {
if (vv.length > 0) {
result.push(`${k}:${vv.join(':')}`)
}
})
expandedSectionsArray.value = result
},
})
const [
{ data: incompleteUploadsData, refresh: refreshIncompleteUploadsApi },
Expand Down Expand Up @@ -149,6 +170,7 @@ const activeIndex = computed<number>({
v-if="portfolioData && portfolioGroupData && initiativeData"
v-model:selected-portfolio-ids="selectedPortfolioIds"
v-model:expanded-portfolio-ids="expandedPortfolioIds"
v-model:expanded-sections="expandedSections"
:portfolios="portfolioData.items"
:portfolio-groups="portfolioGroupData.items"
:analyses="analysesData.items"
Expand Down
2 changes: 2 additions & 0 deletions frontend/plugins/primevue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Dialog from 'primevue/dialog'
import Dropdown from 'primevue/dropdown'
import FileUpload from 'primevue/fileupload'
import Image from 'primevue/image'
import InlineMessage from 'primevue/inlinemessage'
import InputNumber from 'primevue/inputnumber'
import InputSwitch from 'primevue/inputswitch'
import InputText from 'primevue/inputtext'
Expand Down Expand Up @@ -50,6 +51,7 @@ export default defineNuxtPlugin(({ vueApp }) => {
vueApp.component('PVDropdown', Dropdown)
vueApp.component('PVFileUpload', FileUpload)
vueApp.component('PVImage', Image)
vueApp.component('PVInlineMessage', InlineMessage)
vueApp.component('PVInputNumber', InputNumber)
vueApp.component('PVInputSwitch', InputSwitch)
vueApp.component('PVInputText', InputText)
Expand Down

0 comments on commit c343f98

Please sign in to comment.