From 2435d7a49bdba351355e6a8e3b0d39a9088d71ed Mon Sep 17 00:00:00 2001
From: Andre Wanlin <67169551+awanlin@users.noreply.github.com>
Date: Tue, 12 Oct 2021 12:54:44 -0500
Subject: [PATCH] Move HomepageTimer and use props over config (#7533)
---
.changeset/wicked-clocks-kneel.md | 37 ++++++
.changeset/witty-dolls-walk.md | 5 +
packages/app/src/components/home/HomePage.tsx | 36 ++++--
packages/core-components/api-report.md | 2 +-
.../layout/HomepageTimer/HomepageTimer.tsx | 4 +
plugins/home/api-report.md | 17 +++
.../HeaderWorldClock.test.tsx | 88 +++++++++++++++
.../HeaderWorldClock/HeaderWorldClock.tsx | 105 ++++++++++++++++++
.../src/components/HeaderWorldClock/index.ts | 17 +++
plugins/home/src/components/index.ts | 2 +
plugins/home/src/index.ts | 3 +-
11 files changed, 304 insertions(+), 12 deletions(-)
create mode 100644 .changeset/wicked-clocks-kneel.md
create mode 100644 .changeset/witty-dolls-walk.md
create mode 100644 plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx
create mode 100644 plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx
create mode 100644 plugins/home/src/components/HeaderWorldClock/index.ts
diff --git a/.changeset/wicked-clocks-kneel.md b/.changeset/wicked-clocks-kneel.md
new file mode 100644
index 0000000000..fc2ee54440
--- /dev/null
+++ b/.changeset/wicked-clocks-kneel.md
@@ -0,0 +1,37 @@
+---
+'@backstage/plugin-home': patch
+---
+
+Added HeaderWorldClock to the Home plugin which is a copy of the HomepageTimer from core-components that has been updated to use props over static config from app-config.yaml. To use HeaderWorldClock you'll need to create an array of ClockConfig like this:
+
+```ts
+const clockConfigs: ClockConfig[] = [
+ {
+ label: 'NYC',
+ timeZone: 'America/New_York',
+ },
+ {
+ label: 'UTC',
+ timeZone: 'UTC',
+ },
+ {
+ label: 'STO',
+ timeZone: 'Europe/Stockholm',
+ },
+ {
+ label: 'TYO',
+ timeZone: 'Asia/Tokyo',
+ },
+];
+```
+
+Then you can pass `clockConfigs` into the HeaderWorldClock like this:
+
+```ts
+
+
+ ...
+
+```
diff --git a/.changeset/witty-dolls-walk.md b/.changeset/witty-dolls-walk.md
new file mode 100644
index 0000000000..0c6532e725
--- /dev/null
+++ b/.changeset/witty-dolls-walk.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-components': patch
+---
+
+Deprecated HomepageTimer in favor of HeaderWorldClock which is found in the [home plugin](https://github.com/backstage/backstage/tree/master/plugins/home)
diff --git a/packages/app/src/components/home/HomePage.tsx b/packages/app/src/components/home/HomePage.tsx
index 33ac1a7e8c..5a19cef6f6 100644
--- a/packages/app/src/components/home/HomePage.tsx
+++ b/packages/app/src/components/home/HomePage.tsx
@@ -15,26 +15,42 @@
*/
import {
- Content,
- Header,
- HomepageTimer,
- Page,
-} from '@backstage/core-components';
-import {
- ComponentAccordion,
- ComponentTab,
- ComponentTabs,
HomePageRandomJoke,
+ ComponentAccordion,
+ ComponentTabs,
+ ComponentTab,
WelcomeTitle,
+ HeaderWorldClock,
+ ClockConfig,
} from '@backstage/plugin-home';
+import { Content, Header, Page } from '@backstage/core-components';
import { HomePageSearchBar } from '@backstage/plugin-search';
import Grid from '@material-ui/core/Grid';
import React from 'react';
+const clockConfigs: ClockConfig[] = [
+ {
+ label: 'NYC',
+ timeZone: 'America/New_York',
+ },
+ {
+ label: 'UTC',
+ timeZone: 'UTC',
+ },
+ {
+ label: 'STO',
+ timeZone: 'Europe/Stockholm',
+ },
+ {
+ label: 'TYO',
+ timeZone: 'Asia/Tokyo',
+ },
+];
+
export const HomePage = () => (
} pageTitleOverride="Home">
-
+
diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md
index 38fe19fc8b..dc8115287a 100644
--- a/packages/core-components/api-report.md
+++ b/packages/core-components/api-report.md
@@ -569,7 +569,7 @@ export function HelpIcon(props: IconComponentProps): JSX.Element;
// Warning: (ae-missing-release-tag) "HomepageTimer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
-// @public (undocumented)
+// @public @deprecated
export function HomepageTimer(_props: {}): JSX.Element | null;
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
diff --git a/packages/core-components/src/layout/HomepageTimer/HomepageTimer.tsx b/packages/core-components/src/layout/HomepageTimer/HomepageTimer.tsx
index a78f4af8ca..a825d52c94 100644
--- a/packages/core-components/src/layout/HomepageTimer/HomepageTimer.tsx
+++ b/packages/core-components/src/layout/HomepageTimer/HomepageTimer.tsx
@@ -67,6 +67,10 @@ function getTimes(configApi: ConfigApi) {
return clocks;
}
+/**
+ * Please use the HeaderWorldClock in the home plugin
+ * @deprecated in favor of the HeaderWorldClock which is found in the to home plugin
+ */
export function HomepageTimer(_props: {}) {
const configApi = useApi(configApiRef);
diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md
index a1cd98124a..57b0b899e2 100644
--- a/plugins/home/api-report.md
+++ b/plugins/home/api-report.md
@@ -10,6 +10,14 @@ import { Extension } from '@backstage/core-plugin-api';
import { ReactNode } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
+// Warning: (ae-missing-release-tag) "ClockConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type ClockConfig = {
+ label: string;
+ timeZone: string;
+};
+
// Warning: (ae-missing-release-tag) "ComponentAccordion" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -76,6 +84,15 @@ export function createCardExtension({
} & T) => JSX.Element
>;
+// Warning: (ae-missing-release-tag) "HeaderWorldClock" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export const HeaderWorldClock: ({
+ clockConfigs,
+}: {
+ clockConfigs: ClockConfig[];
+}) => JSX.Element | null;
+
// Warning: (ae-missing-release-tag) "HomepageCompositionRoot" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
diff --git a/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx b/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx
new file mode 100644
index 0000000000..9dbfceac81
--- /dev/null
+++ b/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx
@@ -0,0 +1,88 @@
+/*
+ * 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 { renderInTestApp } from '@backstage/test-utils';
+import { HeaderWorldClock, ClockConfig } from './HeaderWorldClock';
+import React from 'react';
+import { lightTheme } from '@backstage/theme';
+import { ThemeProvider } from '@material-ui/core';
+
+describe('HeaderWorldClock with valid Time Zones', () => {
+ it('displays Time Zones as expected', async () => {
+ const clockConfigs: ClockConfig[] = [
+ {
+ label: 'NYC',
+ timeZone: 'America/New_York',
+ },
+ {
+ label: 'UTC',
+ timeZone: 'UTC',
+ },
+ {
+ label: 'STO',
+ timeZone: 'Europe/Stockholm',
+ },
+ {
+ label: 'TYO',
+ timeZone: 'Asia/Tokyo',
+ },
+ ];
+
+ const rendered = await renderInTestApp(
+
+
+ ,
+ );
+
+ expect(rendered.getByText('NYC')).toBeInTheDocument();
+ expect(rendered.getByText('UTC')).toBeInTheDocument();
+ expect(rendered.getByText('STO')).toBeInTheDocument();
+ expect(rendered.getByText('TYO')).toBeInTheDocument();
+ });
+});
+
+describe('HeaderWorldClock with no Time Zones provided', () => {
+ it('should not appear in output', async () => {
+ const clockConfigs: ClockConfig[] = [];
+
+ const rendered = await renderInTestApp(
+
+
+ ,
+ );
+
+ expect(rendered.container).toBeEmptyDOMElement();
+ });
+});
+
+describe('HeaderWorldClock with invalid Time Zone', () => {
+ it('uses GMT as fallback Time Zone', async () => {
+ const clockConfigs: ClockConfig[] = [
+ {
+ label: 'New York',
+ timeZone: 'America/New_Pork',
+ },
+ ];
+
+ const rendered = await renderInTestApp(
+
+
+ ,
+ );
+
+ expect(rendered.getByText('GMT')).toBeInTheDocument();
+ });
+});
diff --git a/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx b/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx
new file mode 100644
index 0000000000..32bf305020
--- /dev/null
+++ b/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2020 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 React from 'react';
+import { HeaderLabel } from '@backstage/core-components';
+
+const timeFormat: Intl.DateTimeFormatOptions = {
+ hour: '2-digit',
+ minute: '2-digit',
+};
+
+type TimeObj = {
+ time: string;
+ label: string;
+};
+
+export type ClockConfig = {
+ label: string;
+ timeZone: string;
+};
+
+function getTimes(clockConfigs: ClockConfig[]) {
+ const d = new Date();
+ const lang = window.navigator.language;
+
+ const clocks: TimeObj[] = [];
+
+ if (!clockConfigs) {
+ return clocks;
+ }
+
+ for (const clockConfig of clockConfigs) {
+ let label = clockConfig.label;
+
+ const options: Intl.DateTimeFormatOptions = {
+ timeZone: clockConfig.timeZone,
+ ...timeFormat,
+ };
+
+ try {
+ new Date().toLocaleString(lang, options);
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `The timezone ${options.timeZone} is invalid. Defaulting to GMT`,
+ );
+ options.timeZone = 'GMT';
+ label = 'GMT';
+ }
+
+ const time = d.toLocaleTimeString(lang, options);
+ clocks.push({ time, label });
+ }
+
+ return clocks;
+}
+
+export const HeaderWorldClock = ({
+ clockConfigs,
+}: {
+ clockConfigs: ClockConfig[];
+}) => {
+ const defaultTimes: TimeObj[] = [];
+ const [clocks, setTimes] = React.useState(defaultTimes);
+
+ React.useEffect(() => {
+ setTimes(getTimes(clockConfigs));
+
+ const intervalId = setInterval(() => {
+ setTimes(getTimes(clockConfigs));
+ }, 1000);
+
+ return () => {
+ clearInterval(intervalId);
+ };
+ }, [clockConfigs]);
+
+ if (clocks.length !== 0) {
+ return (
+ <>
+ {clocks.map(clock => (
+
+ ))}
+ >
+ );
+ }
+ return null;
+};
diff --git a/plugins/home/src/components/HeaderWorldClock/index.ts b/plugins/home/src/components/HeaderWorldClock/index.ts
new file mode 100644
index 0000000000..0893c0586c
--- /dev/null
+++ b/plugins/home/src/components/HeaderWorldClock/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 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.
+ */
+export { HeaderWorldClock } from './HeaderWorldClock';
+export type { ClockConfig } from './HeaderWorldClock';
diff --git a/plugins/home/src/components/index.ts b/plugins/home/src/components/index.ts
index aae0cbe26d..1408853f5f 100644
--- a/plugins/home/src/components/index.ts
+++ b/plugins/home/src/components/index.ts
@@ -16,3 +16,5 @@
export { HomepageCompositionRoot } from './HomepageCompositionRoot';
export { SettingsModal } from './SettingsModal';
+export { HeaderWorldClock } from './HeaderWorldClock';
+export type { ClockConfig } from './HeaderWorldClock';
diff --git a/plugins/home/src/index.ts b/plugins/home/src/index.ts
index 0004cf5a23..a8b8e7ab14 100644
--- a/plugins/home/src/index.ts
+++ b/plugins/home/src/index.ts
@@ -29,5 +29,6 @@ export {
ComponentTab,
WelcomeTitle,
} from './plugin';
-export { SettingsModal } from './components';
+export { SettingsModal, HeaderWorldClock } from './components';
+export type { ClockConfig } from './components';
export { createCardExtension } from './extensions';