Skip to content

Commit 0de4b02

Browse files
Alessandro100qcdyx
andcommitted
official_updated_at added
Co-authored-by: Jingsi Lu <[email protected]>
1 parent 2a715c0 commit 0de4b02

File tree

9 files changed

+141
-112
lines changed

9 files changed

+141
-112
lines changed

api/src/feeds/impl/models/basic_feed_impl.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,12 @@ class Config:
2323
def from_orm(cls, feed: Feed | None, _=None) -> BasicFeed | None:
2424
if not feed:
2525
return None
26-
latest_official_status = None
27-
if len(feed.officialstatushistories) > 0:
28-
latest_official_status = max(feed.officialstatushistories, key=lambda x: x.timestamp).is_official
2926
return cls(
3027
id=feed.stable_id,
3128
data_type=feed.data_type,
3229
status=feed.status,
33-
official=latest_official_status,
30+
official=feed.official,
31+
official_updated_at=feed.official_updated_at,
3432
created_at=feed.created_at,
3533
external_ids=sorted(
3634
[ExternalIdImpl.from_orm(item) for item in feed.externalids], key=lambda x: x.external_id

docs/DatabaseCatalogAPI.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,12 @@ components:
362362
Official feeds are provided by the transit agency or a trusted source.
363363
type: boolean
364364
example: true
365+
official_updated_at:
366+
description: >
367+
The date and time the official status was last updated, in ISO 8601 date-time format.
368+
type: string
369+
example: 2023-07-10T22:06:00Z
370+
format: date-time
365371
external_ids:
366372
$ref: "#/components/schemas/ExternalIds"
367373
provider:

liquibase/changelog.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@
3333
<include file="changes/feat_741.sql" relativeToChangelogFile="true"/>
3434
<include file="changes/feat_794.sql" relativeToChangelogFile="true"/>
3535
<include file="changes/feat_794_2.sql" relativeToChangelogFile="true"/>
36+
<include file="changes/feat_871.sql" relativeToChangelogFile="true"/>
3637
</databaseChangeLog>

liquibase/changes/feat_871.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE Feed ADD COLUMN official_updated_at TIMESTAMP DEFAULT NULL;

liquibase/changes/official_tag_update.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
-- Query to update official tag for feeds with contact email in the feed table where the source is mdb
22

33
UPDATE public.feed f
4-
SET official = TRUE
4+
SET
5+
official = TRUE
6+
official_updated_at = NOW()
57
FROM public.externalid e
68
WHERE f.id = e.feed_id
79
AND f.feed_contact_email LIKE '%@%'

web-app/public/locales/en/feeds.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,6 @@
9393
"officialFeedTooltipShort": "Verified feed: Confirmed by the transit provider or the Mobility Database team for rider use.",
9494
"seeDetailPageProviders": "See detail page to view {providersCount} others",
9595
"openFullQualityReport": "Open Full Quality Report",
96-
"qualityReportUpdated": "Quality report updated"
96+
"qualityReportUpdated": "Quality report updated",
97+
"officialFeedUpdated": "Official verification updated"
9798
}

web-app/src/app/screens/Feed/DataQualitySummary.tsx

Lines changed: 97 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -24,102 +24,106 @@ export default function DataQualitySummary({
2424
latestDataset.validation_report === null) && (
2525
<WarningContentBox>{t('errorLoadingQualityReport')}</WarningContentBox>
2626
)}
27-
{latestDataset?.validation_report !== undefined &&
28-
latestDataset.validation_report !== null && (
29-
<Box sx={{ display: 'flex', gap: 1 }}>
30-
{isOfficialFeed && (
31-
<Tooltip title={t('officialFeedTooltip')} placement='top'>
32-
<Chip
33-
sx={verificationBadgeStyle}
34-
icon={<VerifiedIcon sx={{ fill: 'white' }}></VerifiedIcon>}
35-
label={t('officialFeed')}
36-
></Chip>
37-
</Tooltip>
38-
)}
27+
<Box sx={{ display: 'flex', gap: 1 }}>
28+
{isOfficialFeed && (
29+
<Tooltip title={t('officialFeedTooltip')} placement='top'>
3930
<Chip
40-
data-testid='error-count'
41-
clickable
42-
component='a'
43-
href={latestDataset?.validation_report?.url_html}
44-
target='_blank'
45-
rel='noopener noreferrer'
46-
icon={
47-
latestDataset?.validation_report?.unique_error_count !==
48-
undefined &&
49-
latestDataset?.validation_report?.unique_error_count > 0 ? (
50-
<ReportOutlined />
51-
) : (
52-
<CheckCircle />
53-
)
54-
}
55-
label={
56-
latestDataset?.validation_report?.unique_error_count !==
57-
undefined &&
58-
latestDataset?.validation_report?.unique_error_count > 0
59-
? `${latestDataset?.validation_report
60-
?.unique_error_count} ${t('common:feedback.errors')}`
61-
: t('common:feedback.noErrors')
62-
}
63-
color={
64-
latestDataset?.validation_report?.unique_error_count !==
65-
undefined &&
66-
latestDataset?.validation_report?.unique_error_count > 0
67-
? 'error'
68-
: 'success'
69-
}
70-
variant='outlined'
71-
/>
31+
sx={verificationBadgeStyle}
32+
icon={<VerifiedIcon sx={{ fill: 'white' }}></VerifiedIcon>}
33+
label={t('officialFeed')}
34+
></Chip>
35+
</Tooltip>
36+
)}
37+
{latestDataset?.validation_report !== undefined &&
38+
latestDataset.validation_report !== null && (
39+
<>
40+
<Chip
41+
data-testid='error-count'
42+
clickable
43+
component='a'
44+
href={latestDataset?.validation_report?.url_html}
45+
target='_blank'
46+
rel='noopener noreferrer'
47+
icon={
48+
latestDataset?.validation_report?.unique_error_count !==
49+
undefined &&
50+
latestDataset?.validation_report?.unique_error_count > 0 ? (
51+
<ReportOutlined />
52+
) : (
53+
<CheckCircle />
54+
)
55+
}
56+
label={
57+
latestDataset?.validation_report?.unique_error_count !==
58+
undefined &&
59+
latestDataset?.validation_report?.unique_error_count > 0
60+
? `${latestDataset?.validation_report
61+
?.unique_error_count} ${t('common:feedback.errors')}`
62+
: t('common:feedback.noErrors')
63+
}
64+
color={
65+
latestDataset?.validation_report?.unique_error_count !==
66+
undefined &&
67+
latestDataset?.validation_report?.unique_error_count > 0
68+
? 'error'
69+
: 'success'
70+
}
71+
variant='outlined'
72+
/>
7273

73-
<Chip
74-
data-testid='warning-count'
75-
clickable
76-
component='a'
77-
href={latestDataset?.validation_report?.url_html}
78-
target='_blank'
79-
rel='noopener noreferrer'
80-
icon={
81-
latestDataset?.validation_report?.unique_warning_count !==
82-
undefined &&
83-
latestDataset?.validation_report?.unique_warning_count > 0 ? (
84-
<ReportOutlined />
85-
) : (
86-
<CheckCircle />
87-
)
88-
}
89-
label={
90-
latestDataset?.validation_report?.unique_warning_count !==
91-
undefined &&
92-
latestDataset?.validation_report?.unique_warning_count > 0
93-
? `${latestDataset?.validation_report
94-
?.unique_warning_count} ${t('common:feedback.warnings')}`
95-
: t('common:feedback.no_warnings')
96-
}
97-
color={
98-
latestDataset?.validation_report?.unique_warning_count !==
99-
undefined &&
100-
latestDataset?.validation_report?.unique_warning_count > 0
101-
? 'warning'
102-
: 'success'
103-
}
104-
variant='outlined'
105-
/>
74+
<Chip
75+
data-testid='warning-count'
76+
clickable
77+
component='a'
78+
href={latestDataset?.validation_report?.url_html}
79+
target='_blank'
80+
rel='noopener noreferrer'
81+
icon={
82+
latestDataset?.validation_report?.unique_warning_count !==
83+
undefined &&
84+
latestDataset?.validation_report?.unique_warning_count > 0 ? (
85+
<ReportOutlined />
86+
) : (
87+
<CheckCircle />
88+
)
89+
}
90+
label={
91+
latestDataset?.validation_report?.unique_warning_count !==
92+
undefined &&
93+
latestDataset?.validation_report?.unique_warning_count > 0
94+
? `${latestDataset?.validation_report
95+
?.unique_warning_count} ${t(
96+
'common:feedback.warnings',
97+
)}`
98+
: t('common:feedback.no_warnings')
99+
}
100+
color={
101+
latestDataset?.validation_report?.unique_warning_count !==
102+
undefined &&
103+
latestDataset?.validation_report?.unique_warning_count > 0
104+
? 'warning'
105+
: 'success'
106+
}
107+
variant='outlined'
108+
/>
106109

107-
<Chip
108-
data-testid='info-count'
109-
icon={<InfoOutlinedIcon />}
110-
clickable
111-
component='a'
112-
href={latestDataset?.validation_report?.url_html}
113-
target='_blank'
114-
rel='noopener noreferrer'
115-
label={`${
116-
latestDataset?.validation_report?.unique_info_count ?? '0'
117-
} ${t('common:feedback.infoNotices')}`}
118-
color='primary'
119-
variant='outlined'
120-
/>
121-
</Box>
122-
)}
110+
<Chip
111+
data-testid='info-count'
112+
icon={<InfoOutlinedIcon />}
113+
clickable
114+
component='a'
115+
href={latestDataset?.validation_report?.url_html}
116+
target='_blank'
117+
rel='noopener noreferrer'
118+
label={`${
119+
latestDataset?.validation_report?.unique_info_count ?? '0'
120+
} ${t('common:feedback.infoNotices')}`}
121+
color='primary'
122+
variant='outlined'
123+
/>
124+
</>
125+
)}
126+
</Box>
123127
</Box>
124128
);
125129
}

web-app/src/app/screens/Feed/index.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -423,19 +423,28 @@ export default function Feed(): React.ReactElement {
423423
)}
424424
<Box>
425425
{latestDataset?.validation_report?.validated_at != undefined && (
426-
<>
427-
<Typography
428-
data-testid='last-updated'
429-
variant={'caption'}
430-
width={'100%'}
431-
component={'div'}
432-
>
433-
{`${t('qualityReportUpdated')}: ${new Date(
434-
latestDataset.validation_report.validated_at,
435-
).toDateString()}`}
436-
</Typography>
437-
{/* TODO: add timestamp for badge verify */}
438-
</>
426+
<Typography
427+
data-testid='last-updated'
428+
variant={'caption'}
429+
width={'100%'}
430+
component={'div'}
431+
>
432+
{`${t('qualityReportUpdated')}: ${new Date(
433+
latestDataset.validation_report.validated_at,
434+
).toDateString()}`}
435+
</Typography>
436+
)}
437+
{feed?.official_updated_at != undefined && (
438+
<Typography
439+
data-testid='last-updated'
440+
variant={'caption'}
441+
width={'100%'}
442+
component={'div'}
443+
>
444+
{`${t('officialFeedUpdated')}: ${new Date(
445+
feed?.official_updated_at,
446+
).toDateString()}`}
447+
</Typography>
439448
)}
440449
</Box>
441450

web-app/src/app/services/feeds/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ export interface components {
144144
* @example true
145145
*/
146146
official?: boolean;
147+
/**
148+
* Format: date-time
149+
* @description The date and time the official status was last updated, in ISO 8601 date-time format.
150+
*
151+
* @example "2023-07-10T22:06:00.000Z"
152+
*/
153+
official_updated_at?: string;
147154
external_ids?: components['schemas']['ExternalIds'];
148155
/**
149156
* @description A commonly used name for the transit provider included in the feed.

0 commit comments

Comments
 (0)