(form)
+
+ const [backgroundColor, setBackgroundColor] = useState(
+ form.values.backgroundColor,
+ )
+
+ const theme = useTheme()
+ const [t] = useTranslation("serviceBannerSettings")
+
+ return (
+ <>
+
+ {pageTitle("Service Banner Settings")}
+
+
+
+
+ {isEntitled ? : }
+
+
+
+ {isEntitled ? (
+
+ ) : (
+ <>
+
+ Your license does not include Service Banners.{" "}
+ Contact sales to learn more.
+
+
+ >
+ )}
+ >
+ )
+}
+
+const useStyles = makeStyles(() => ({
+ form: {
+ maxWidth: "500px",
+ },
+}))
+
+export default ServiceBannerSettingsPage
diff --git a/site/src/xServices/StateContext.tsx b/site/src/xServices/StateContext.tsx
index 21a35b3c4dc33..a085fb795823c 100644
--- a/site/src/xServices/StateContext.tsx
+++ b/site/src/xServices/StateContext.tsx
@@ -7,11 +7,13 @@ import { updateCheckMachine } from "./updateCheck/updateCheckXService"
import { deploymentConfigMachine } from "./deploymentConfig/deploymentConfigMachine"
import { entitlementsMachine } from "./entitlements/entitlementsXService"
import { siteRolesMachine } from "./roles/siteRolesXService"
+import { serviceBannerMachine } from "./serviceBanner/serviceBannerXService"
interface XServiceContextType {
authXService: ActorRefFrom
buildInfoXService: ActorRefFrom
entitlementsXService: ActorRefFrom
+ serviceBannerXService: ActorRefFrom
siteRolesXService: ActorRefFrom
// Since the info here is used by multiple deployment settings page and we don't want to refetch them every time
deploymentConfigXService: ActorRefFrom
@@ -35,6 +37,7 @@ export const XServiceProvider: FC<{ children: ReactNode }> = ({ children }) => {
authXService: useInterpret(authMachine),
buildInfoXService: useInterpret(buildInfoMachine),
entitlementsXService: useInterpret(entitlementsMachine),
+ serviceBannerXService: useInterpret(serviceBannerMachine),
siteRolesXService: useInterpret(siteRolesMachine),
deploymentConfigXService: useInterpret(deploymentConfigMachine),
updateCheckXService: useInterpret(updateCheckMachine),
diff --git a/site/src/xServices/serviceBanner/serviceBannerXService.ts b/site/src/xServices/serviceBanner/serviceBannerXService.ts
new file mode 100644
index 0000000000000..9f8dd6d1caa22
--- /dev/null
+++ b/site/src/xServices/serviceBanner/serviceBannerXService.ts
@@ -0,0 +1,134 @@
+import { displaySuccess } from "components/GlobalSnackbar/utils"
+import { assign, createMachine } from "xstate"
+import * as API from "../../api/api"
+import { ServiceBanner } from "../../api/typesGenerated"
+
+export const Language = {
+ getServiceBannerError: "Error getting service banner.",
+ setServiceBannerError: "Error setting service banner.",
+}
+
+export type ServiceBannerContext = {
+ serviceBanner: ServiceBanner
+ getServiceBannerError?: Error | unknown
+ setServiceBannerError?: Error | unknown
+ preview: boolean
+}
+
+export type ServiceBannerEvent =
+ | {
+ type: "GET_BANNER"
+ }
+ | { type: "SET_PREVIEW_BANNER"; serviceBanner: ServiceBanner }
+ | { type: "SET_BANNER"; serviceBanner: ServiceBanner }
+
+const emptyBanner = {
+ enabled: false,
+}
+
+export const serviceBannerMachine = createMachine(
+ {
+ id: "serviceBannerMachine",
+ predictableActionArguments: true,
+ tsTypes: {} as import("./serviceBannerXService.typegen").Typegen0,
+ schema: {
+ context: {} as ServiceBannerContext,
+ events: {} as ServiceBannerEvent,
+ services: {
+ getServiceBanner: {
+ data: {} as ServiceBanner,
+ },
+ setServiceBanner: {
+ data: {},
+ },
+ },
+ },
+ context: {
+ serviceBanner: emptyBanner,
+ preview: false,
+ },
+ initial: "idle",
+ states: {
+ idle: {
+ on: {
+ GET_BANNER: "gettingBanner",
+ SET_PREVIEW_BANNER: "settingPreviewBanner",
+ SET_BANNER: "settingBanner",
+ },
+ },
+ gettingBanner: {
+ entry: "clearGetBannerError",
+ invoke: {
+ id: "getBanner",
+ src: "getBanner",
+ onDone: {
+ target: "idle",
+ actions: ["assignBanner"],
+ },
+ onError: {
+ target: "idle",
+ actions: ["assignGetBannerError"],
+ },
+ },
+ },
+ settingPreviewBanner: {
+ entry: [
+ "clearGetBannerError",
+ "clearSetBannerError",
+ "assignPreviewBanner",
+ ],
+ always: {
+ target: "idle",
+ },
+ },
+ settingBanner: {
+ entry: "clearSetBannerError",
+ invoke: {
+ id: "setBanner",
+ src: "setBanner",
+ onDone: {
+ target: "idle",
+ actions: ["assignBanner", "notifyUpdateBannerSuccess"],
+ },
+ onError: {
+ target: "idle",
+ actions: ["assignSetBannerError"],
+ },
+ },
+ },
+ },
+ },
+ {
+ actions: {
+ assignPreviewBanner: assign({
+ serviceBanner: (_, event) => event.serviceBanner,
+ // The xState docs suggest that we can use a static value, but I failed
+ // to find a way to do that that doesn't generate type errors.
+ preview: (_, __) => true,
+ }),
+ notifyUpdateBannerSuccess: () => {
+ displaySuccess("Successfully updated Service Banner!")
+ },
+ assignBanner: assign({
+ serviceBanner: (_, event) => event.data as ServiceBanner,
+ preview: (_, __) => false,
+ }),
+ assignGetBannerError: assign({
+ getServiceBannerError: (_, event) => event.data,
+ }),
+ clearGetBannerError: assign({
+ getServiceBannerError: (_) => undefined,
+ }),
+ assignSetBannerError: assign({
+ setServiceBannerError: (_, event) => event.data,
+ }),
+ clearSetBannerError: assign({
+ setServiceBannerError: (_) => undefined,
+ }),
+ },
+ services: {
+ getBanner: API.getServiceBanner,
+ setBanner: (_, event) => API.setServiceBanner(event.serviceBanner),
+ },
+ },
+)
diff --git a/site/yarn.lock b/site/yarn.lock
index 9d8bd36864e64..b221cfd005fdd 100644
--- a/site/yarn.lock
+++ b/site/yarn.lock
@@ -1247,6 +1247,11 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+"@icons/material@^0.2.4":
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
+ integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
+
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@@ -2892,6 +2897,18 @@
"@types/connect" "*"
"@types/node" "*"
+"@types/color-convert@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.0.tgz#8f5ee6b9e863dcbee5703f5a517ffb13d3ea4e22"
+ integrity sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==
+ dependencies:
+ "@types/color-name" "*"
+
+"@types/color-name@*":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
+ integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
+
"@types/connect@*":
version "3.4.35"
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
@@ -3146,6 +3163,14 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
+"@types/react-color@^3.0.6":
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.6.tgz#602fed023802b2424e7cd6ff3594ccd3d5055f9a"
+ integrity sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==
+ dependencies:
+ "@types/react" "*"
+ "@types/reactcss" "*"
+
"@types/react-dom@18.0.6":
version "18.0.6"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.6.tgz#36652900024842b74607a17786b6662dd1e103a1"
@@ -3199,6 +3224,13 @@
"@types/scheduler" "*"
csstype "^3.0.2"
+"@types/reactcss@*":
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/@types/reactcss/-/reactcss-1.2.6.tgz#133c1e7e896f2726370d1d5a26bf06a30a038bcc"
+ integrity sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==
+ dependencies:
+ "@types/react" "*"
+
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
@@ -9459,7 +9491,7 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
-lodash-es@^4.17.21:
+lodash-es@^4.17.15, lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
@@ -9484,7 +9516,7 @@ lodash.uniq@4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
-lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
+lodash@^4.0.1, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -9622,6 +9654,11 @@ markdown-table@^3.0.0:
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.2.tgz#9b59eb2c1b22fe71954a65ff512887065a7bb57c"
integrity sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==
+material-colors@^1.2.1:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
+ integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
+
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -11372,7 +11409,7 @@ prompts@^2.0.1, prompts@^2.4.0:
kleur "^3.0.3"
sisteransi "^1.0.5"
-prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -11543,6 +11580,19 @@ react-chartjs-2@4.3.1:
resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz#9941e7397fb963f28bb557addb401e9ff96c6681"
integrity sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==
+react-color@^2.19.3:
+ version "2.19.3"
+ resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d"
+ integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==
+ dependencies:
+ "@icons/material" "^0.2.4"
+ lodash "^4.17.15"
+ lodash-es "^4.17.15"
+ material-colors "^1.2.1"
+ prop-types "^15.5.10"
+ reactcss "^1.2.0"
+ tinycolor2 "^1.4.1"
+
react-docgen-typescript@^2.1.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c"
@@ -11715,6 +11765,13 @@ react@18.2.0:
dependencies:
loose-envify "^1.1.0"
+reactcss@^1.2.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
+ integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==
+ dependencies:
+ lodash "^4.0.1"
+
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -13115,6 +13172,11 @@ tiny-warning@^1.0.2:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+tinycolor2@^1.4.1:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
+ integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"