-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #50 from GSA-TTS/submission-report
Submission Report UI
- Loading branch information
Showing
11 changed files
with
661 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
.usa-tag__success { | ||
border-radius: 4px; | ||
border: 1px solid var(--Green-cool-vivid-green-cool-vivid-10v, #b7f5bd); | ||
background: var(--Green-cool-vivid-green-cool-vivid-10v, #b7f5bd); | ||
color: black; | ||
display: inline-flex; | ||
padding: 2px 8px; | ||
align-items: center; | ||
} | ||
|
||
.usa-tag__info { | ||
border-radius: 4px; | ||
background: var(--Blue-vivid-blue-vivid-10v, #cfe8ff); | ||
color: black; | ||
display: inline-flex; | ||
padding: 2px 8px; | ||
align-items: center; | ||
} | ||
|
||
.usa-tag__warning { | ||
border-radius: 4px; | ||
border: 1px solid var(--Warning-warning, #ffbe2e); | ||
background: var(--Warning-warning, #ffbe2e); | ||
color: black; | ||
display: inline-flex; | ||
padding: 2px 8px; | ||
align-items: center; | ||
} | ||
|
||
.usa-tag__error { | ||
border-radius: 4px; | ||
border: 1px solid var(--Error-error-dark, #b50909); | ||
background: var(--Error-error-dark, #b50909); | ||
color: white; | ||
display: inline-flex; | ||
padding: 2px 8px; | ||
align-items: center; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
nad_ch/controllers/web/src/components/CompletenessReport.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
|
||
import { | ||
CompletenessReport, | ||
CompletenessReportComponent, | ||
} from './CompletenessReport'; | ||
import { AlpineComponent } from 'alpinejs'; | ||
import { fetchReportData } from '../services'; | ||
|
||
jest.mock('../services', () => ({ | ||
fetchReportData: jest.fn(), | ||
})); | ||
|
||
describe('CompletenessReportComponent', () => { | ||
let component: AlpineComponent<CompletenessReportComponent>; | ||
const mockReportData = { | ||
features: [ | ||
{ | ||
provided_feature_name: 'AddNum_Pre', | ||
nad_feature_name: 'AddNum_Pre', | ||
populated_count: 1141, | ||
null_count: 0, | ||
required: false, | ||
status: 'No error', | ||
populated_percentage: '100%', | ||
null_percentage: '0%', | ||
}, | ||
{ | ||
provided_feature_name: 'Add_Number', | ||
nad_feature_name: 'Add_Number', | ||
populated_count: 1141, | ||
null_count: 0, | ||
required: true, | ||
status: 'No error', | ||
populated_percentage: '100%', | ||
null_percentage: '0%', | ||
}, | ||
], | ||
overview: { | ||
data_update_required: false, | ||
etl_update_required: false, | ||
feature_count: 10, | ||
features_flagged: 2, | ||
}, | ||
}; | ||
|
||
beforeEach(() => { | ||
(fetchReportData as jest.Mock).mockResolvedValue(mockReportData); | ||
component = CompletenessReport('1'); | ||
}); | ||
|
||
it('initializes with default data', () => { | ||
expect(component.id).toBe(1); | ||
expect(component.isLoading).toBe(true); | ||
expect(component.groupedFeatures).toEqual([]); | ||
expect(component.isGroupedByStatus).toBe(false); | ||
}); | ||
|
||
it('loads report data on init', async () => { | ||
await component.init(); | ||
expect(fetchReportData).toHaveBeenCalledWith(1); | ||
expect(component.isLoading).toBe(false); | ||
expect(component.report).toEqual(mockReportData); | ||
}); | ||
|
||
it('groups features by status', () => { | ||
component.report = mockReportData; | ||
const groupedFeatures = component.groupFeatures(mockReportData.features); | ||
expect(groupedFeatures).toEqual([ | ||
{ | ||
status: 'No error', | ||
features: [ | ||
{ | ||
provided_feature_name: 'AddNum_Pre', | ||
nad_feature_name: 'AddNum_Pre', | ||
populated_count: 1141, | ||
null_count: 0, | ||
required: false, | ||
status: 'No error', | ||
populated_percentage: '100%', | ||
null_percentage: '0%', | ||
}, | ||
{ | ||
provided_feature_name: 'Add_Number', | ||
nad_feature_name: 'Add_Number', | ||
populated_count: 1141, | ||
null_count: 0, | ||
required: true, | ||
status: 'No error', | ||
populated_percentage: '100%', | ||
null_percentage: '0%', | ||
}, | ||
], | ||
}, | ||
]); | ||
}); | ||
|
||
it('computes buttonText based on isGroupedByStatus', () => { | ||
expect(component.buttonText).toBe('Group by Status'); | ||
component.isGroupedByStatus = true; | ||
expect(component.buttonText).toBe('Ungroup by Status'); | ||
}); | ||
|
||
it('computes toggleButtonClass based on isGroupedByStatus', () => { | ||
expect(component.toggleButtonClass).toBe('usa-button-toggle-off'); | ||
component.isGroupedByStatus = true; | ||
expect(component.toggleButtonClass).toBe('usa-button-toggle-on'); | ||
}); | ||
|
||
it('gets status tag class based on different statuses', () => { | ||
expect(component.getStatusTagClass('No error')).toBe('usa-tag__success'); | ||
expect(component.getStatusTagClass('Updated by calculation')).toBe( | ||
'usa-tag__warning', | ||
); | ||
expect(component.getStatusTagClass('Rejected')).toBe('usa-tag__error'); | ||
expect(component.getStatusTagClass('Other')).toBe('usa-tag__info'); | ||
}); | ||
}); |
112 changes: 112 additions & 0 deletions
112
nad_ch/controllers/web/src/components/CompletenessReport.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { AlpineComponent } from 'alpinejs'; | ||
import { fetchReportData } from '../services'; | ||
|
||
export type CompletenessReport = { | ||
features: Feature[]; | ||
overview: Overview; | ||
}; | ||
|
||
type Overview = { | ||
data_update_required: boolean; | ||
etl_update_required: boolean; | ||
feature_count: number; | ||
features_flagged: number; | ||
}; | ||
|
||
type Feature = { | ||
provided_feature_name: string; | ||
nad_feature_name: string; | ||
populated_count: number; | ||
null_count: number; | ||
required: boolean; | ||
status: string; | ||
populated_percentage: string; | ||
null_percentage: string; | ||
}; | ||
|
||
type GroupedFeature = { | ||
status: string; | ||
features: Feature[]; | ||
}; | ||
|
||
export interface CompletenessReportComponent { | ||
id: number; | ||
isLoading: boolean; | ||
report: CompletenessReport | null; | ||
groupedFeatures: GroupedFeature[]; | ||
isGroupedByStatus: boolean; | ||
buttonText: string; | ||
toggleButtonClass: string; | ||
init(): Promise<void>; | ||
groupFeatures(features: Feature[]): GroupedFeature[]; | ||
getStatusTagClass(status: string): string; | ||
} | ||
|
||
export function CompletenessReport( | ||
id: string, | ||
): AlpineComponent<CompletenessReportComponent> { | ||
return { | ||
id: parseInt(id), | ||
isLoading: true, | ||
report: { | ||
features: [], | ||
overview: { | ||
data_update_required: false, | ||
etl_update_required: false, | ||
feature_count: 0, | ||
features_flagged: 0, | ||
}, | ||
}, | ||
groupedFeatures: [], | ||
isGroupedByStatus: false, | ||
async init(): Promise<void> { | ||
try { | ||
this.report = await fetchReportData(this.id); | ||
if (this.report) { | ||
this.groupedFeatures = this.groupFeatures(this.report.features); | ||
} | ||
} catch (error) { | ||
console.error('Failed to load report:', error); | ||
} finally { | ||
this.isLoading = false; | ||
} | ||
}, | ||
groupFeatures(features: Feature[]): GroupedFeature[] { | ||
const groupedByStatus = features.reduce<Record<string, Feature[]>>( | ||
(acc, obj) => { | ||
if (!acc[obj.status]) { | ||
acc[obj.status] = []; | ||
} | ||
acc[obj.status].push(obj); | ||
return acc; | ||
}, | ||
{}, | ||
); | ||
|
||
return Object.keys(groupedByStatus).map((status) => ({ | ||
status: status, | ||
features: groupedByStatus[status], | ||
})); | ||
}, | ||
get buttonText(): string { | ||
return this.isGroupedByStatus ? 'Ungroup by Status' : 'Group by Status'; | ||
}, | ||
get toggleButtonClass(): string { | ||
return this.isGroupedByStatus | ||
? 'usa-button-toggle-on' | ||
: 'usa-button-toggle-off'; | ||
}, | ||
getStatusTagClass(status: string): string { | ||
switch (status) { | ||
case 'No error': | ||
return 'usa-tag__success'; | ||
case 'Updated by calculation': | ||
return 'usa-tag__warning'; | ||
case 'Rejected': | ||
return 'usa-tag__error'; | ||
default: | ||
return 'usa-tag__info'; | ||
} | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { BASE_URL } from './config'; | ||
import { CompletenessReport } from './components/CompletenessReport'; | ||
|
||
export async function fetchReportData(id: number): Promise<CompletenessReport> { | ||
const response = await fetch(`${BASE_URL}/api/reports/${id}`); | ||
const reportData = await response.json(); | ||
return reportData; | ||
} |
Oops, something went wrong.