From 76a0d49eff24182a4a02bcb98f0955ad817a3e43 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Mon, 25 Nov 2024 14:56:47 +0000 Subject: [PATCH 1/4] feat: add swr as dependency --- package.json | 3 ++- yarn.lock | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b22773c7..9d8c4443b 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,8 @@ "react": "^18.2.0", "react-dom": "^18.3.1", "redux": "^4.0.5", - "scroll-lock": "^2.1.4" + "scroll-lock": "^2.1.4", + "swr": "^2.2.5" }, "bugs": { "url": "https://github.com/ably/ably-ui/issues" diff --git a/yarn.lock b/yarn.lock index 47b9bfb2d..ee1b2ac8c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3515,6 +3515,11 @@ cli-width@^4.1.0: resolved "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz" integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== +client-only@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + cliui@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" @@ -8237,6 +8242,14 @@ svgo@^2.8.0: picocolors "^1.0.0" stable "^0.1.8" +swr@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.5.tgz#063eea0e9939f947227d5ca760cc53696f46446b" + integrity sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg== + dependencies: + client-only "^0.0.1" + use-sync-external-store "^1.2.0" + tailwindcss@^3.3.6: version "3.4.15" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.15.tgz#04808bf4bf1424b105047d19e7d4bfab368044a9" @@ -8630,6 +8643,11 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +use-sync-external-store@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" From 2a1bbc2da16ec29317dbf1a99496c0cbdbf22ffa Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Mon, 25 Nov 2024 15:11:24 +0000 Subject: [PATCH 2/4] refactor: Status component rebuilt with SWR Main reason is to have only a single ajax request for status data on the page, no matter how many status icons are embedded. Also extract the icon portion into its own StatusIcon component that can be better used in other components, especially inside other anchor tags --- src/core/Status.tsx | 68 +++++++++++++++--------------- src/core/Status/Status.stories.tsx | 42 ++++++++++++++---- 2 files changed, 68 insertions(+), 42 deletions(-) diff --git a/src/core/Status.tsx b/src/core/Status.tsx index c3f9c9ee9..4c800d8cf 100644 --- a/src/core/Status.tsx +++ b/src/core/Status.tsx @@ -1,4 +1,9 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; +import useSWR from "swr"; +import clsx from "clsx"; + +// Our SWR fetcher function +const fetcher = (url: string) => fetch(url).then((res) => res.json()); const indicatorClass = (indicator?: string) => { switch (indicator) { @@ -17,41 +22,37 @@ const indicatorClass = (indicator?: string) => { } }; +export const StatusIcon = ({ + statusUrl, + refreshInterval = 1000 * 60, +}: { + statusUrl: string; + refreshInterval?: number; +}) => { + const { data, error, isLoading } = useSWR(statusUrl, fetcher, { + refreshInterval, + }); + + return ( + + ); +}; + const Status = ({ statusUrl, additionalCSS, + refreshInterval = 1000 * 60, }: { statusUrl: string; additionalCSS?: string; + refreshInterval?: number; }) => { - const [data, setData] = useState<{ status: { indicator: string } } | null>( - null, - ); - - useEffect(() => { - let interval: NodeJS.Timeout; - - if (statusUrl !== "") { - const fetchData = async () => { - try { - const response = await fetch(statusUrl); - const jsonData = await response.json(); - setData(jsonData); - } catch (error) { - console.error("Error fetching status data:", error); - } - }; - - fetchData(); - - interval = setInterval(fetchData, 60000); // Fetch data every minute - } - - return () => { - clearInterval(interval); - }; - }, [statusUrl]); - return ( - - - + ); }; diff --git a/src/core/Status/Status.stories.tsx b/src/core/Status/Status.stories.tsx index 91c7b2423..0880ea9c1 100644 --- a/src/core/Status/Status.stories.tsx +++ b/src/core/Status/Status.stories.tsx @@ -1,5 +1,6 @@ import React from "react"; import { delay, http, HttpResponse } from "msw"; +import { SWRConfig } from "swr"; import Status from "../Status"; const statusUrl = "https://ntqy1wz94gjv.statuspage.io/api/v2/status.json"; @@ -13,6 +14,10 @@ export default { tags: ["!autodocs"], }; +const withEmptySWRCache = (component: JSX.Element) => ( + new Map() }}>{component} +); + export const Loading = { parameters: { msw: { @@ -29,10 +34,25 @@ export const Loading = { }, }, }, - render: () => , + render: () => + withEmptySWRCache(), +}; + +export const Error = { + parameters: { + msw: { + handlers: { + statusError: http.get(statusUrl, () => { + return HttpResponse.error(); + }), + }, + }, + }, + render: () => + withEmptySWRCache(), }; -const mockParametersWithStatus = (indicator) => { +const mockParametersWithStatus = (indicator: string) => { return { msw: { handlers: { @@ -52,30 +72,36 @@ const mockParametersWithStatus = (indicator) => { export const None = { parameters: mockParametersWithStatus("none"), - render: () => , + render: () => + withEmptySWRCache(), }; export const Operational = { parameters: mockParametersWithStatus("operational"), - render: () => , + render: () => + withEmptySWRCache(), }; export const Minor = { parameters: mockParametersWithStatus("minor"), - render: () => , + render: () => + withEmptySWRCache(), }; export const Major = { parameters: mockParametersWithStatus("major"), - render: () => , + render: () => + withEmptySWRCache(), }; export const Critical = { parameters: mockParametersWithStatus("critical"), - render: () => , + render: () => + withEmptySWRCache(), }; export const Unknown = { parameters: mockParametersWithStatus("unknown"), - render: () => , + render: () => + withEmptySWRCache(), }; From a22799a6bc276cec8bb558b20dfde8a0fb497a64 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Mon, 25 Nov 2024 15:12:50 +0000 Subject: [PATCH 3/4] chore: switch to using the StatusIcon component in meganav & footer For the meganav this resolves the issue of invalid markup (a > a) --- src/core/Footer.tsx | 10 ++++++---- .../Footer/__snapshots__/Footer.stories.tsx.snap | 14 ++++---------- src/core/MeganavContentDevelopers.tsx | 9 +++------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/core/Footer.tsx b/src/core/Footer.tsx index a6b754f21..282cde8e8 100644 --- a/src/core/Footer.tsx +++ b/src/core/Footer.tsx @@ -2,7 +2,7 @@ import React from "react"; import Icon from "./Icon"; import _absUrl from "./url-base.js"; -import Status from "./Status.js"; +import { StatusIcon } from "./Status"; type FooterProps = { paths: { @@ -209,14 +209,16 @@ const Footer = ({ paths, urlBase, statusUrl }: FooterProps) => { SDKs -
  • +
  • System status + -
  • diff --git a/src/core/Footer/__snapshots__/Footer.stories.tsx.snap b/src/core/Footer/__snapshots__/Footer.stories.tsx.snap index 82fb910c2..f8289c9bd 100644 --- a/src/core/Footer/__snapshots__/Footer.stories.tsx.snap +++ b/src/core/Footer/__snapshots__/Footer.stories.tsx.snap @@ -175,20 +175,14 @@ exports[`Components/Footer Default smoke-test 1`] = ` SDKs -
  • - + - System status - - - - - + System status +
  • diff --git a/src/core/MeganavContentDevelopers.tsx b/src/core/MeganavContentDevelopers.tsx index 226e297e3..31ca9d96e 100644 --- a/src/core/MeganavContentDevelopers.tsx +++ b/src/core/MeganavContentDevelopers.tsx @@ -2,7 +2,7 @@ import React from "react"; import Icon from "./Icon"; import { AbsUrl } from "./Meganav"; -import Status from "./Status"; +import { StatusIcon } from "./Status"; const MeganavContentDevelopers = ({ absUrl, @@ -186,12 +186,9 @@ const MeganavContentDevelopers = ({ href="https://status.ably.com/" className="group ui-meganav-media py-12" > -

    +

    Status - +

    From 0c450235717867f459e957066eb8e937d624b02c Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Mon, 25 Nov 2024 16:04:46 +0000 Subject: [PATCH 4/4] chore: bump version to 15.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d8c4443b..3ecdf4e2d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ably/ui", - "version": "15.0.1", + "version": "15.0.2", "description": "Home of the Ably design system library ([design.ably.com](https://design.ably.com)). It provides a showcase, development/test environment and a publishing pipeline for different distributables.", "repository": { "type": "git",