Skip to content

Commit 60a7c39

Browse files
Merge branch 'release/v0.17.0-beta' into khairul-syazwan/fix-button-ibm-plex-font-release-0.17
2 parents 4f27876 + 4363124 commit 60a7c39

7 files changed

Lines changed: 53 additions & 22 deletions

File tree

plugins/functions/analytics-svc/src/mri/endpoint/InclusionReportEndpoint.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -551,22 +551,18 @@ export class InclusionReportEndpoint extends BaseQueryEngineEndpoint {
551551
return [];
552552
}
553553

554-
let basicDataInclusionReportFilters;
555-
if (basicDataFilters.length === 1) {
556-
basicDataInclusionReportFilters = [
557-
structuredClone(basicDataFiltercard),
554+
// Split Basic Data into distinct filtercards, one per constrained attribute.
555+
// This must also happen for a single constrained attribute
556+
const basicDataInclusionReportFilters = basicDataFilters.map((e) => {
557+
// Clone overall structure of Basic Data filter card and replace attributes.content with individual Basic Data attributes.content
558+
const basicDataFiltercardClone =
559+
structuredClone(basicDataFiltercard);
560+
basicDataFiltercardClone.content[0].attributes.content = [
561+
structuredClone(e),
558562
];
559-
} else {
560-
// Split Basic Data into distinct filtercards
561-
basicDataInclusionReportFilters = basicDataFilters.map((e) => {
562-
// Clone overall structure of Basic Data filter card and replace attributes.content with individual Basic Data attributes.content
563-
const basicDataFiltercardClone =
564-
structuredClone(basicDataFiltercard);
565-
basicDataFiltercardClone.content[0].attributes.content = [e];
566-
567-
return basicDataFiltercardClone;
568-
});
569-
}
563+
564+
return basicDataFiltercardClone;
565+
});
570566

571567
// Update basic data to use dynamically generated interactions.basicdata in cdm config
572568
basicDataInclusionReportFilters.forEach((e, idx) => {

plugins/ui/apps/portal/src/components/Charts/Common/Drilldown/DrilldownPrevalenceByMonthChart/DrilldownPrevalenceByMonthChart.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,21 @@ const DrilldownPrevalenceByMonthChart: FC<DrilldownPrevalenceByMonthChartProps>
2828
);
2929
}
3030

31+
// Sort data by XCALENDARMONTH
32+
const sortedData = [...data].sort((a: any, b: any) => {
33+
return Number(a["XCALENDARMONTH"]) - Number(b["XCALENDARMONTH"]);
34+
});
35+
3136
// Parse and format line chart data
3237
// Parse XCALENDARMONTH from e.g 200910 -> 10/2009
33-
const lineChartXAxisData = data.map(
38+
const lineChartXAxisData = sortedData.map(
3439
(obj: any) => obj["XCALENDARMONTH"].toString().slice(-2) + "/" + obj["XCALENDARMONTH"].toString().slice(0, 4)
3540
);
3641

3742
const series = [
3843
{
3944
type: "line",
40-
data: data.map((obj: any) => Number(obj["YPREVALENCE1000PP"]).toFixed()),
45+
data: sortedData.map((obj: any) => Number(obj["YPREVALENCE1000PP"]).toFixed()),
4146
},
4247
];
4348

plugins/ui/apps/portal/src/components/Charts/Common/Drilldown/DrilldownTrellisChart/DrilldownTrellisChart.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ const DrilldownTrellisChart: FC<DrilldownTrellisChartProps> = ({
5656
const TITLE_OFFSET = 6 / numRows; // Dynamic offset for grid titles
5757
const ROW_LABEL_OFFSET = 9 / numRows; // Dynamic offset for row labels
5858

59-
// Get keys from trellisData sorted
60-
const sortedTrellisNames = Object.keys(trellisData).sort();
59+
// Get keys from trellisData sorted naturally, so numeric ranges are ordered by value
60+
// instead of lexicographically
61+
const sortedTrellisNames = Object.keys(trellisData).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
6162

6263
// Calculate global y-axis range for harmonization across all plots
6364
const allYValues = data.map((obj: any) => Number(obj[trellisXAxisKey])).filter((v: number) => !isNaN(v));

plugins/ui/apps/vue-mri-ui-lib/src/components/ShinyViewer/CompleteRequiredFiltersModal.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ import MessageBox from '../MessageBox.vue'
154154
import appButton from '@/lib/ui/app-button.vue'
155155
import ConceptSetTypeaheadField from './ConceptSetTypeaheadField.vue'
156156
import type { WizardFieldDefinition } from '@/utils/dashboardFlowUtils'
157-
import { isConditionField } from '@/utils/dashboardFlowUtils'
157+
import { isConditionField, normalizeWizardFieldValueForComparison } from '@/utils/dashboardFlowUtils'
158158
import InputParser from '@/lib/utils/InputParser'
159159
import RangeConstraintTokenDefinition from '@/lib/utils/RangeConstraintTokenDefinition'
160160
import RangeConstraintPatternDefinition from '@/lib/utils/RangeConstraintPatternDefinition'
@@ -460,7 +460,8 @@ function markFieldDirty(fieldId: string) {
460460
}
461461
462462
// For regular fields
463-
const hasChanged = currentValue !== initialValue
463+
const hasChanged =
464+
normalizeWizardFieldValueForComparison(currentValue) !== normalizeWizardFieldValueForComparison(initialValue)
464465
465466
if (hasChanged) {
466467
dirtyFields.add(fieldId)

plugins/ui/apps/vue-mri-ui-lib/src/composables/useDashboardFlow.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,12 @@ export function useDashboardFlow(
998998
}
999999
const rawValue = rawInput?.value ?? rawInput
10001000
if (rawValue === null || typeof rawValue === 'undefined' || String(rawValue).trim() === '') {
1001+
if (constraintType === 'text' || constraintType === 'conceptSet') {
1002+
return dispatch('updateConstraintValue', {
1003+
constraintId: constraint.id,
1004+
value: [],
1005+
})
1006+
}
10011007
return Promise.reject(new Error(`Missing value for ${constraint.props.name || constraint.id}`))
10021008
}
10031009
const finalDisplayValue = displayValue || rawInput?.displayName || String(rawValue)

plugins/ui/apps/vue-mri-ui-lib/src/utils/__tests__/dashboardFlowUtils.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { describe, expect, it } from 'vitest'
2-
import { getWizardFlow, isWizardVisibleOnSurface, parseNumericInput, validateRequiredFields } from '../dashboardFlowUtils'
2+
import {
3+
getWizardFlow,
4+
isWizardVisibleOnSurface,
5+
normalizeWizardFieldValueForComparison,
6+
parseNumericInput,
7+
validateRequiredFields,
8+
} from '../dashboardFlowUtils'
39

410
const createExpression = (operator: string, value: string | number) => ({
511
type: 'Expression' as const,
@@ -214,3 +220,15 @@ describe('wizard metadata helpers', () => {
214220
expect(getWizardFlow({ flow: 'table1-config' })).toBe('table1-config')
215221
})
216222
})
223+
224+
describe('wizard field value helpers', () => {
225+
it('treats null, undefined, and an empty string as the same empty form value', () => {
226+
expect(normalizeWizardFieldValueForComparison(null)).toBe('')
227+
expect(normalizeWizardFieldValueForComparison(undefined)).toBe('')
228+
expect(normalizeWizardFieldValueForComparison('')).toBe('')
229+
})
230+
231+
it('preserves non-empty field values', () => {
232+
expect(normalizeWizardFieldValueForComparison('FEMALE')).toBe('FEMALE')
233+
})
234+
})

plugins/ui/apps/vue-mri-ui-lib/src/utils/dashboardFlowUtils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ export interface RequiredFieldValidationResult {
100100
breakdown: FieldComparisonBreakdown[]
101101
}
102102

103+
export function normalizeWizardFieldValueForComparison(value: unknown): unknown {
104+
return value === null || typeof value === 'undefined' ? '' : value
105+
}
106+
103107
function getLastPathSegment(path: string): string {
104108
const tokens = path.split('.')
105109
return tokens[tokens.length - 1] || path

0 commit comments

Comments
 (0)