Skip to content

Commit

Permalink
4098 - Metadata: Select Options per cycle + select years options (#4101)
Browse files Browse the repository at this point in the history
  • Loading branch information
minotogna authored Nov 11, 2024
1 parent 70d424d commit 9d15ff9
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import { useOnChange } from './hooks/useOnChange'

const YearSelection: React.FC = () => {
const { t } = useTranslation()
const { cycleName, sectionName } = useOriginalDataPointRouteParams()
const { sectionName } = useOriginalDataPointRouteParams()
const originalDataPoint = useOriginalDataPoint()
const canEditData = useIsEditTableDataEnabled(sectionName)
const onChange = useOnChange()
const { years, reservedYears } = useODPYears(cycleName)
const { years, reservedYears } = useODPYears()
const validYear = ODPs.validateYear(originalDataPoint)
const disabled = Boolean(!canEditData)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import React, { useEffect, useRef } from 'react'

import { Cols } from 'meta/assessment'

import { useCycle } from 'client/store/assessment'
import MultiSelect from 'client/components/MultiSelect'
import { PropsCell } from 'client/pages/Section/DataTable/Table/Row/RowData/Cell/props'
import { DOMs } from 'client/utils/dom'

const Multiselect: React.FC<PropsCell> = (props) => {
const { onChangeNodeValue, col, nodeValue, disabled } = props
const { options, labelKeyPrefix } = col.props.select

const value = nodeValue?.raw
const cycle = useCycle()
const ref = useRef(null)

const { labelKeyPrefix } = Cols.getSelectProps({ cycle, col })
const options = Cols.getSelectOptions({ cycle, col })
const value = nodeValue?.raw
const values = Array.isArray(value) ? value : []

const ref = useRef(null)

useEffect(() => {
if (ref) {
const row = ref.current.closest('tr')
Expand All @@ -25,14 +29,14 @@ const Multiselect: React.FC<PropsCell> = (props) => {
}, [ref, value])

return (
<div className="fra-table__select-container multiple" ref={ref}>
<div ref={ref} className="fra-table__select-container multiple">
<MultiSelect
disabled={disabled}
options={options.map((option) => ({ label: `${labelKeyPrefix}.${option.name}`, value: option.name }))}
values={values}
onChange={(values: Array<string>) => {
onChangeNodeValue({ ...nodeValue, raw: values })
}}
options={options.map((option) => ({ label: `${labelKeyPrefix}.${option.name}`, value: option.name }))}
values={values}
/>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { useTranslation } from 'react-i18next'

import { TFunction } from 'i18next'

import { Col, ColSelectOption, NodeValue } from 'meta/assessment'
import { Col, Cols, ColSelectOption, NodeValue } from 'meta/assessment'

import { useCycle } from 'client/store/assessment'
import { Option, OptionsGroup, OptionsOrGroups } from 'client/components/Inputs/Select'

const getLabel = (option: ColSelectOption, t: TFunction, labelKeyPrefix = 'yesNoTextSelect'): string => {
Expand All @@ -19,9 +20,12 @@ type Props = {

export const useOptions = (props: Props): OptionsOrGroups => {
const { col } = props
const { options: optionsProps, labelKeyPrefix } = col.props.select

const { t } = useTranslation()
const cycle = useCycle()

const { labelKeyPrefix } = Cols.getSelectProps({ cycle, col })
const optionsProps = Cols.getSelectOptions({ cycle, col })

return useMemo<OptionsOrGroups>(() => {
const groups: Array<OptionsGroup> = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default (props: Props): Returned => {
value: value.raw,
type,
valuePrev: nodeValue.raw,
options: col.props.select?.options,
options: Cols.getSelectOptions({ cycle, col }),
})

dispatch(
Expand Down Expand Up @@ -137,7 +137,7 @@ export default (props: Props): Returned => {
value,
type: colSpecType,
valuePrev: nodeValue.raw,
options: colSpec.props.select?.options,
options: Cols.getSelectOptions({ cycle, col: colSpec }),
})
const nodeValueUpdate = { raw: valueUpdate }

Expand Down
7 changes: 4 additions & 3 deletions src/client/store/ui/originalDataPoint/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Arrays } from 'utils/arrays'
import { Dates } from 'utils/dates'

import { CycleName, OriginalDataPoint } from 'meta/assessment'
import { OriginalDataPoint } from 'meta/assessment'

import { useAppSelector } from 'client/store'
import { useCountryRouteParams } from 'client/hooks/useRouteParams'
Expand All @@ -26,11 +27,11 @@ export const useIsOriginalDataPointUpdating = () => useAppSelector((state) => st
export const useOriginalDataPointReservedYears = () =>
useAppSelector((state) => state.ui.originalDataPoint?.reservedYears)

export const useODPYears = (cycleName: CycleName): { years: Array<number>; reservedYears: Array<number> } => {
export const useODPYears = (): { years: Array<number>; reservedYears: Array<number> } => {
const reservedYears = useOriginalDataPointReservedYears() ?? []

return {
years: Arrays.reverse(Arrays.range(1950, Number(cycleName))),
years: Arrays.reverse(Arrays.range(1950, Dates.getCurrentYear())),
reservedYears: reservedYears.map((reservedYear) => reservedYear.year),
}
}
5 changes: 3 additions & 2 deletions src/meta/assessment/col.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ export interface ColSelectOption {
}

export interface ColSelectProps {
options: Array<ColSelectOption>
labelKeyPrefix?: string
options?: Array<ColSelectOption>
years?: { start: number; end?: number }
}

export interface ColStyle extends CSSProperties {
Expand All @@ -60,7 +61,7 @@ export interface ColProps {
labels?: Record<CycleUuid, Label>
linkedNodes?: Record<CycleUuid, ColLinkedNode>
readonly?: boolean
select?: ColSelectProps
select?: Record<CycleUuid, ColSelectProps>
style?: Record<CycleUuid, ColStyle>
validateFns?: Record<CycleUuid, Array<string>>
variableNo?: Record<CycleUuid, string>
Expand Down
28 changes: 27 additions & 1 deletion src/meta/assessment/cols.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { TFunction } from 'i18next'
import { Arrays } from 'utils/arrays'
import { Dates } from 'utils/dates'
import { Objects } from 'utils/objects'

import { Cycle } from 'meta/assessment/cycle'
import { Labels } from 'meta/assessment/labels'

import { Col, ColStyle, ColType } from './col'
import { Col, ColSelectOption, ColSelectProps, ColStyle, ColType } from './col'
import { Row } from './row'

const cloneProps = (props: { cycleSource: Cycle; cycleTarget: Cycle; col: Col }): Col['props'] => {
Expand Down Expand Up @@ -89,12 +91,36 @@ const getStyle = (props: { cycle: Cycle; col: Col }): ColStyle => {
return style[cycle.uuid] ?? {}
}

const getSelectProps = (props: { cycle: Cycle; col: Col }): ColSelectProps => {
const { col, cycle } = props

return col.props.select?.[cycle.uuid] ?? { options: [] }
}

const getSelectOptions = (props: { cycle: Cycle; col: Col }): Array<ColSelectOption> => {
const selectProps = getSelectProps(props)
const { options, years } = selectProps
if (!Objects.isNil(options)) {
return options
}

if (!Objects.isNil(years)) {
const { start, end = Dates.getCurrentYear() + 1 } = years

return Arrays.reverse(Arrays.range(start, end)).map<ColSelectOption>((year) => ({ name: String(year) }))
}

throw new Error(`Unable to get col options. col: ${JSON.stringify(props.col)}`)
}

export const Cols = {
cloneProps,
getCalculateFn,
getClassNames,
getColName,
getLabel,
getSelectOptions,
getSelectProps,
getStyle,
hasLinkedNodes,
isCalculated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const removeMetadata = async (props: Props, client: BaseProtocol): Promis
table_section: ['descriptions', 'lables'],
table: ['cellsExportAlways', 'columnNames', 'columnsExport', 'columnsExportAlways', 'disableErrorMessage'],
row: ['calculateFn', 'calculateIf', 'chart', 'excludeFromDataExport', 'linkToSection', 'validateFns', 'withReview'],
col: ['calculateFn', 'classNames', 'labels', 'linkedNodes', 'style', 'validateFns', 'variableNo'],
col: ['calculateFn', 'classNames', 'labels', 'linkedNodes', 'select', 'style', 'validateFns', 'variableNo'],
}

const query = tableNames.map((tableName) => {
Expand Down
3 changes: 2 additions & 1 deletion src/server/repository/adapter/col.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface ColDB {

export const ColAdapter = (colDB: ColDB): Col => {
const {
props: { calculateFn, classNames, labels, linkedNodes, style, validateFns, variableNo, ...otherProps },
props: { calculateFn, classNames, labels, linkedNodes, select, style, validateFns, variableNo, ...otherProps },
...col
} = colDB

Expand All @@ -24,6 +24,7 @@ export const ColAdapter = (colDB: ColDB): Col => {
classNames,
labels,
linkedNodes,
select,
style,
variableNo,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ColType } from 'meta/assessment'

import { AssessmentController } from 'server/controller/assessment'
import { BaseProtocol, Schemas } from 'server/db'

export default async (client: BaseProtocol) => {
const assessments = await AssessmentController.getAll({}, client)

await Promise.all(
assessments.map(async (assessment) => {
const schemaAssessment = Schemas.getName(assessment)

await client.query(`
with col_props as
(select c.id
, c.props -> 'select' #- '{options}' ||
jsonb_build_object('years', jsonb_build_object('start', 1980)) as select_props
from ${schemaAssessment}.col c
left join ${schemaAssessment}.row r on r.id = c.row_id
left join ${schemaAssessment}."table" t on t.id = r.table_id
where t.props ->> 'name' = 'growingStockComposition2025'
and c.props ->> 'colName' = 'mostRecentYear')
update ${schemaAssessment}.col c
set props = c.props || jsonb_build_object('select', cp.select_props)
from col_props cp
where c.id = cp.id
;
with col_props_disagg as
(select c.id
, jsonb_array_elements_text(c.props -> 'cycles') as cycle_uuid
, c.props -> 'select' as select_props
from ${schemaAssessment}.col c
left join ${schemaAssessment}.row r on r.id = c.row_id
left join ${schemaAssessment}."table" t on t.id = r.table_id
where c.props ->> 'colType' in ('${ColType.multiselect}','${ColType.select}')
order by c.id)
, col_props as
(select cp.id
, jsonb_object_agg(cp.cycle_uuid, cp.select_props) as select_props
from col_props_disagg cp
group by cp.id)
update ${schemaAssessment}.col c
set props = c.props || jsonb_build_object('select', cp.select_props)
from col_props cp
where c.id = cp.id
;
`)

await AssessmentController.generateMetadataCache({ assessment }, client)
})
)
}
4 changes: 4 additions & 0 deletions src/utils/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
differenceInMonths,
differenceInWeeks,
format,
getYear,
isAfter,
isBefore,
parseISO,
Expand All @@ -25,11 +26,14 @@ export const getRelativeDate = (rawDate: any, i18n: any) => {
return i18n.t('time.aMomentAgo')
}

const getCurrentYear = (): number => getYear(new Date())

export const Dates = {
addDays,
addMonths,
differenceInDays,
format,
getCurrentYear,
getRelativeDate,
isAfter,
isBefore,
Expand Down

0 comments on commit 9d15ff9

Please sign in to comment.