Merge pull request #12131 from awanlin/topic/custom-time-format-header-clocks

Added support for custom time format in header clocks
This commit is contained in:
Ben Lambert
2022-06-27 13:56:01 +02:00
committed by GitHub
11 changed files with 229 additions and 14 deletions
+26
View File
@@ -0,0 +1,26 @@
---
'@backstage/plugin-home': patch
---
Added support for customizing the time format used in the `HeaderWorldClock` component
Here's an example of how this can be used in the `HomePage.tsx` found in `\packages\app\src\components\home` to change the clock to be in the 24hr time format:
```diff
+const timeFormat: Intl.DateTimeFormatOptions = {
+ hour: '2-digit',
+ minute: '2-digit',
+ hour12: false,
+};
export const homePage = (
<Page themeId="home">
<Header title={<WelcomeTitle />} pageTitleOverride="Home">
+ <HeaderWorldClock clockConfigs={clockConfigs} customTimeFormat={timeFormat} />
</Header>
<Content>
<Grid container spacing={3}>
<Grid item xs={12}>
<HomePageSearchBar />
</Grid>
```
+10 -1
View File
@@ -49,10 +49,19 @@ const clockConfigs: ClockConfig[] = [
},
];
const timeFormat: Intl.DateTimeFormatOptions = {
hour: '2-digit',
minute: '2-digit',
hour12: false,
};
export const homePage = (
<Page themeId="home">
<Header title={<WelcomeTitle />} pageTitleOverride="Home">
<HeaderWorldClock clockConfigs={clockConfigs} />
<HeaderWorldClock
clockConfigs={clockConfigs}
customTimeFormat={timeFormat}
/>
</Header>
<Content>
<Grid container spacing={3}>
+2 -1
View File
@@ -59,9 +59,10 @@ export function createCardExtension<T>(options: {
name?: string;
}): Extension<(props: CardExtensionProps<T>) => JSX.Element>;
// @public (undocumented)
// @public
export const HeaderWorldClock: (props: {
clockConfigs: ClockConfig[];
customTimeFormat?: Intl.DateTimeFormatOptions | undefined;
}) => JSX.Element | null;
// @public
-2
View File
@@ -16,5 +16,3 @@
export { HomepageCompositionRoot } from './HomepageCompositionRoot';
export { SettingsModal } from './SettingsModal';
export { HeaderWorldClock } from './HeaderWorldClock';
export type { ClockConfig } from './HeaderWorldClock';
@@ -0,0 +1,97 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Header } from '@backstage/core-components';
import { wrapInTestApp } from '@backstage/test-utils';
import React, { ComponentType } from 'react';
import { ClockConfig, HeaderWorldClock } from './HeaderWorldClock';
export default {
title: 'Plugins/Home/Components/HeaderWorldClock',
decorators: [(Story: ComponentType<{}>) => wrapInTestApp(<Story />)],
};
export const Default = () => {
const clockConfigs: ClockConfig[] = [
{
label: 'NYC',
timeZone: 'America/New_York',
},
{
label: 'UTC',
timeZone: 'UTC',
},
{
label: 'STO',
timeZone: 'Europe/Stockholm',
},
{
label: 'TYO',
timeZone: 'Asia/Tokyo',
},
];
const timeFormat: Intl.DateTimeFormatOptions = {
hour: '2-digit',
minute: '2-digit',
hour12: true,
};
return (
<Header title="Header World Clock" pageTitleOverride="Home">
<HeaderWorldClock
clockConfigs={clockConfigs}
customTimeFormat={timeFormat}
/>
</Header>
);
};
export const TwentyFourHourClocks = () => {
const clockConfigs: ClockConfig[] = [
{
label: 'NYC',
timeZone: 'America/New_York',
},
{
label: 'UTC',
timeZone: 'UTC',
},
{
label: 'STO',
timeZone: 'Europe/Stockholm',
},
{
label: 'TYO',
timeZone: 'Asia/Tokyo',
},
];
const timeFormat: Intl.DateTimeFormatOptions = {
hour: '2-digit',
minute: '2-digit',
hour12: false,
};
return (
<Header title="24hr Header World Clock" pageTitleOverride="Home">
<HeaderWorldClock
clockConfigs={clockConfigs}
customTimeFormat={timeFormat}
/>
</Header>
);
};
@@ -86,3 +86,32 @@ describe('HeaderWorldClock with invalid Time Zone', () => {
expect(rendered.getByText('GMT')).toBeInTheDocument();
});
});
describe('HeaderWorldClock with custom Time Format', () => {
it('uses 24hr clock from custom Time Format', async () => {
const clockConfigs: ClockConfig[] = [
{
label: 'UTC',
timeZone: 'UTC',
},
];
const timeFormat: Intl.DateTimeFormatOptions = {
hour: '2-digit',
minute: '2-digit',
hour12: false,
};
const rendered = await renderInTestApp(
<ThemeProvider theme={lightTheme}>
<HeaderWorldClock
clockConfigs={clockConfigs}
customTimeFormat={timeFormat}
/>
</ThemeProvider>,
);
const currentTime = `${new Date().getHours()}:${new Date().getMinutes()}`;
expect(rendered.getByText(currentTime)).toBeInTheDocument();
});
});
@@ -32,7 +32,10 @@ export type ClockConfig = {
timeZone: string;
};
function getTimes(clockConfigs: ClockConfig[]) {
function getTimes(
clockConfigs: ClockConfig[],
customTimeFormat?: Intl.DateTimeFormatOptions,
) {
const d = new Date();
const lang = window.navigator.language;
@@ -47,7 +50,7 @@ function getTimes(clockConfigs: ClockConfig[]) {
const options: Intl.DateTimeFormatOptions = {
timeZone: clockConfig.timeZone,
...timeFormat,
...(customTimeFormat ?? timeFormat),
};
try {
@@ -68,24 +71,57 @@ function getTimes(clockConfigs: ClockConfig[]) {
return clocks;
}
/** @public */
export const HeaderWorldClock = (props: { clockConfigs: ClockConfig[] }) => {
const { clockConfigs } = props;
/**
* A component to display a configurable list of clocks for various time zones.
*
* @example
* Here's a simple example:
* ```
* // This will give you a clock for the time zone that Stockholm is in
* // you can add more than one but keep in mind space may be limited
* const clockConfigs: ClockConfig[] = [
* {
* label: 'STO',
* timeZone: 'Europe/Stockholm',
* },
* ];
*
* // Setting hour12 to false will make all the clocks show in the 24hr format
* const timeFormat: Intl.DateTimeFormatOptions = {
* hour: '2-digit',
* minute: '2-digit',
* hour12: false,
* };
*
* // Here is the component in use:
* <HeaderWorldClock
* clockConfigs={clockConfigs}
* customTimeFormat={timeFormat}
* />
* ```
*
* @public
*/
export const HeaderWorldClock = (props: {
clockConfigs: ClockConfig[];
customTimeFormat?: Intl.DateTimeFormatOptions;
}) => {
const { clockConfigs, customTimeFormat } = props;
const defaultTimes: TimeObj[] = [];
const [clocks, setTimes] = React.useState(defaultTimes);
React.useEffect(() => {
setTimes(getTimes(clockConfigs));
setTimes(getTimes(clockConfigs, customTimeFormat));
const intervalId = setInterval(() => {
setTimes(getTimes(clockConfigs));
setTimes(getTimes(clockConfigs, customTimeFormat));
}, 1000);
return () => {
clearInterval(intervalId);
};
}, [clockConfigs]);
}, [clockConfigs, customTimeFormat]);
if (clocks.length !== 0) {
return (
@@ -16,3 +16,4 @@
export * from './CompanyLogo';
export * from './Toolkit';
export type { ClockConfig } from './HeaderWorldClock';
+3 -2
View File
@@ -31,9 +31,10 @@ export {
ComponentTabs,
ComponentTab,
WelcomeTitle,
HeaderWorldClock,
} from './plugin';
export { SettingsModal, HeaderWorldClock } from './components';
export { SettingsModal } from './components';
export * from './assets';
export type { ClockConfig } from './components';
export type { ClockConfig } from './homePageComponents';
export { createCardExtension } from './extensions';
export type { ComponentRenderer } from './extensions';
+17
View File
@@ -136,3 +136,20 @@ export const HomePageStarredEntities = homePlugin.provide(
components: () => import('./homePageComponents/StarredEntities'),
}),
);
/**
* A component to display a configurable list of clocks for various time zones.
*
* @public
*/
export const HeaderWorldClock = homePlugin.provide(
createComponentExtension({
name: 'HeaderWorldClock',
component: {
lazy: () =>
import('./homePageComponents/HeaderWorldClock').then(
m => m.HeaderWorldClock,
),
},
}),
);