Skip to content

Commit

Permalink
feat(list): manage columns (#352)
Browse files Browse the repository at this point in the history
* feat(datastore): add hook for accessing datastore

* fix(types): fix types for section handle

* feat(constants): add constants for columns and translated properties

* fix: update types for sectionlistcolumns

* fix: add selector to usedatastore

* feat(managecolumns): manage columns implementation

* fix: integrate selectedcoluns with list

* fix: mergecolumns

* fix: managecolumns style

* refactor: managecolumns

* chore: add remeda util lib

* refactor: refactor to config for listviews

* refactor: manage list view

* fix: respect order of selected columns

* fix(datastore): always use put for datastore

* refactor: allow arbitrary path as column

* refactor: remove remeda, implement uniqueBy

* fix: add uniqueBy

* fix: add test for path

* fix: add maxDepth to getFieldFilterFromPath

* fix: fix some tests

* fix: remove typepath file

* refactor: cleanup

* fix(constants): prevent circular dependency (#354)

* fix(managelistview): enforce at least one column

* refactor: rename DataStoreModelListView schema

* refactor: rename useDataStoreValuesQuery

* refactor(modelvale): simplify modelvalue

* fix: fix imports

* refactor: remove component from list config

* fix: fix tests

* refactor: minor cleanup

* refactor: cleanup

---------

Co-authored-by: Jan-Gerke Salomon <[email protected]>
  • Loading branch information
Birkbjo and Mohammer5 authored Oct 18, 2023
1 parent ad57a5f commit 9ecd37d
Show file tree
Hide file tree
Showing 53 changed files with 1,348 additions and 162 deletions.
1 change: 1 addition & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare module '@dhis2/d2-i18n' {
const language: string
export function t(key: string, options?: any): string
export function exists(key: string): boolean
}

declare module '@dhis2/ui'
Expand Down
97 changes: 77 additions & 20 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,39 @@ msgstr "Type to filter options"
msgid "No matches"
msgstr "No matches"

msgid "Data set"
msgstr "Data set"

msgid "Clear all filters"
msgstr "Clear all filters"

msgid "Search by name, code or ID"
msgstr "Search by name, code or ID"

msgid "At least one column must be selected"
msgstr "At least one column must be selected"

msgid "Available table columns"
msgstr "Available table columns"

msgid "Selected table columns"
msgstr "Selected table columns"

msgid "Reset to default columns"
msgstr "Reset to default columns"

msgid "Failed to save"
msgstr "Failed to save"

msgid "Manage {{section}} table columns"
msgstr "Manage {{section}} table columns"

msgid "Cancel"
msgstr "Cancel"

msgid "Update table columns"
msgstr "Update table columns"

msgid "Public can edit"
msgstr "Public can edit"

Expand All @@ -123,6 +150,15 @@ msgstr "Public can view"
msgid "Public cannot access"
msgstr "Public cannot access"

msgid "Public access"
msgstr "Public access"

msgid "Domain"
msgstr "Domain"

msgid "Value"
msgstr "Value"

msgid "Category"
msgstr "Category"

Expand Down Expand Up @@ -177,9 +213,6 @@ msgstr "Data element group set"
msgid "Data element group sets"
msgstr "Data element group sets"

msgid "Data set"
msgstr "Data set"

msgid "Data sets"
msgstr "Data sets"

Expand Down Expand Up @@ -519,29 +552,56 @@ msgstr "Image"
msgid "GeoJSON"
msgstr "GeoJSON"

msgid "Something went wrong when submitting the form"
msgstr "Something went wrong when submitting the form"
msgid "Code"
msgstr "Code"

msgid "Cancel"
msgstr "Cancel"
msgid "Created by"
msgstr "Created by"

msgid "Save and close"
msgstr "Save and close"
msgid "Favorite"
msgstr "Favorite"

msgid "Name"
msgstr "Name"
msgid "Href"
msgstr "Href"

msgid "Domain"
msgstr "Domain"
msgid "Id"
msgstr "Id"

msgid "Value"
msgstr "Value"
msgid "Last updated by"
msgstr "Last updated by"

msgid "Created"
msgstr "Created"

msgid "Domain type"
msgstr "Domain type"

msgid "Last updated"
msgstr "Last updated"

msgid "Public access"
msgstr "Public access"
msgid "Name"
msgstr "Name"

msgid "Sharing"
msgstr "Sharing"

msgid "Short name"
msgstr "Short name"

msgid "Value type"
msgstr "Value type"

msgid "Owner"
msgstr "Owner"

msgid "Zero is significant"
msgstr "Zero is significant"

msgid "Something went wrong when submitting the form"
msgstr "Something went wrong when submitting the form"

msgid "Save and close"
msgstr "Save and close"

msgid "Exit without saving"
msgstr "Exit without saving"
Expand All @@ -567,9 +627,6 @@ msgstr "Short name"
msgid "Often used in reports where space is limited"
msgstr "Often used in reports where space is limited"

msgid "Code"
msgstr "Code"

msgid "Description"
msgstr "Description"

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"react-router-dom": "^6.11.2",
"use-debounce": "^9.0.4",
"use-query-params": "^2.2.1",
"zod": "^3.22.2",
"zustand": "^4.4.0"
}
}
2 changes: 1 addition & 1 deletion src/app/layout/Breadcrumb.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import '@testing-library/jest-dom'
import { configure, render } from '@testing-library/react'
import React from 'react'
import { useMatches, HashRouter } from 'react-router-dom'
import { OVERVIEW_SECTIONS, SECTIONS_MAP } from '../../constants/sections'
import { OVERVIEW_SECTIONS, SECTIONS_MAP } from '../../lib'
import { MatchRouteHandle, RouteHandle } from '../routes/types'
import { Breadcrumbs, BreadcrumbItem } from './Breadcrumb'

Expand Down
10 changes: 7 additions & 3 deletions src/app/layout/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react'
import { Link, useMatches } from 'react-router-dom'
import { Section, isOverviewSection } from '../../constants'
import { getSectionPath, getOverviewPath } from '../../lib'
import { MatchRouteHandle } from '../routes/types'
import {
Section,
isOverviewSection,
getSectionPath,
getOverviewPath,
} from '../../lib'
import type { MatchRouteHandle } from '../routes/types'
import css from './Breadcrumb.module.css'

const BreadcrumbSeparator = () => <span className={css.separator}>/</span>
Expand Down
2 changes: 1 addition & 1 deletion src/app/routes/LegacyAppRedirect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import i18n from '@dhis2/d2-i18n'
import { NoticeBox, Button } from '@dhis2/ui'
import React from 'react'
import { useParams, Params } from 'react-router-dom'
import { isOverviewSection, Section, SECTIONS_MAP } from '../../constants'
import { isOverviewSection, Section, SECTIONS_MAP } from '../../lib'

const legacyPath = '/dhis-web-maintenance/index.html#/'

Expand Down
2 changes: 0 additions & 2 deletions src/app/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import {
Section,
SchemaSection,
OVERVIEW_SECTIONS,
} from '../../constants'
import {
getSectionPath,
isModuleNotFoundError,
isValidUid,
Expand Down
5 changes: 2 additions & 3 deletions src/app/routes/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { useMatches } from 'react-router-dom'
import type { SchemaSection } from '../../constants/sections'

import type { ModelSection } from '../../types'
// utility type to type a match with a handle-property returned from useMatches
// since handle is unknown, we need to cast it to the correct type
type MatchWithHandle<THandle> = ReturnType<typeof useMatches>[number] & {
Expand All @@ -10,8 +9,8 @@ type MatchWithHandle<THandle> = ReturnType<typeof useMatches>[number] & {
// common type for possible handle-properties used in Route
export type RouteHandle = {
hideSidebar?: boolean
section?: ModelSection
showFooter?: boolean
section?: SchemaSection
crumb?: () => React.ReactNode
}

Expand Down
2 changes: 0 additions & 2 deletions src/app/sidebar/SidebarLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import {
OVERVIEW_SECTIONS,
SECTIONS_MAP,
Section,
} from '../../constants/sections'
import {
getOverviewPath,
getSectionPath,
useIsSectionAuthorizedPredicate,
Expand Down
37 changes: 22 additions & 15 deletions src/components/sectionList/SectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,20 @@ import {
} from '@dhis2/ui'
import React, { PropsWithChildren } from 'react'
import { CheckBoxOnChangeObject } from '../../types'
import { IdentifiableObject } from '../../types/generated'
import { SelectedColumns } from './types'

type SectionListProps<Model extends IdentifiableObject> = {
headerColumns: SelectedColumns<Model>
type SectionListProps = {
headerColumns: SelectedColumns
onSelectAll: (checked: boolean) => void
allSelected?: boolean
}

export const SectionList = <Model extends IdentifiableObject>({
export const SectionList = ({
allSelected,
headerColumns,
children,
onSelectAll,
}: PropsWithChildren<SectionListProps<Model>>) => {
}: PropsWithChildren<SectionListProps>) => {
return (
<DataTable>
<TableHead>
Expand All @@ -37,19 +36,27 @@ export const SectionList = <Model extends IdentifiableObject>({
}
/>
</DataTableColumnHeader>
{headerColumns.map((headerColumn) => (
<DataTableColumnHeader
key={headerColumn.modelPropertyName}
>
{headerColumn.label}
</DataTableColumnHeader>
))}
<DataTableColumnHeader>
{i18n.t('Actions')}
</DataTableColumnHeader>
{headerColumns.length > 0 && (
<HeaderColumns headerColumns={headerColumns} />
)}
</DataTableRow>
</TableHead>
<TableBody>{children}</TableBody>
</DataTable>
)
}

const HeaderColumns = ({
headerColumns,
}: {
headerColumns: SelectedColumns
}) => (
<>
{headerColumns.map((headerColumn) => (
<DataTableColumnHeader key={headerColumn.path}>
{headerColumn.label}
</DataTableColumnHeader>
))}
<DataTableColumnHeader>{i18n.t('Actions')}</DataTableColumnHeader>
</>
)
19 changes: 6 additions & 13 deletions src/components/sectionList/SectionListRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,18 @@ import { SelectedColumns, SelectedColumn } from './types'

export type SectionListRowProps<Model extends IdentifiableObject> = {
modelData: GistModel<Model>
selectedColumns: SelectedColumns<Model>
selectedColumns: SelectedColumns
onSelect: (modelId: string, checked: boolean) => void
selected: boolean
renderValue: (
column: SelectedColumn<Model>['modelPropertyName'],
value: GistModel<Model>[typeof column]
) => React.ReactNode
renderColumnValue: (column: SelectedColumn) => React.ReactNode
}

export function SectionListRow<Model extends IdentifiableObject>({
selectedColumns,
modelData,
onSelect,
selected,
renderValue,
renderColumnValue,
}: SectionListRowProps<Model>) {
return (
<DataTableRow
Expand All @@ -39,13 +36,9 @@ export function SectionListRow<Model extends IdentifiableObject>({
}}
/>
</DataTableCell>
{selectedColumns.map(({ modelPropertyName }) => (
<DataTableCell key={modelPropertyName}>
{modelData[modelPropertyName] &&
renderValue(
modelPropertyName,
modelData[modelPropertyName]
)}
{selectedColumns.map((selectedColumn) => (
<DataTableCell key={selectedColumn.path}>
{renderColumnValue(selectedColumn)}
</DataTableCell>
))}
<DataTableCell>
Expand Down
Loading

0 comments on commit 9ecd37d

Please sign in to comment.