From 7863d9acc33d9cc3447c598672a31d5e6bbedf5a Mon Sep 17 00:00:00 2001 From: jared-dickman Date: Wed, 13 Mar 2024 13:22:20 -0600 Subject: [PATCH] feat: global navigation and styling (#124) Co-authored-by: Gabriel Tiburcio Co-authored-by: Gary Kaganas --- .eslintrc.js => .eslintrc.cjs | 9 +- .github/workflows/release.yml | 11 +- .gitignore | 3 +- .stylelintignore | 3 + .stylelintrc | 1 + design/GlobalToken.json | 180 ++-- design/LightTheme.ts | 34 +- package-lock.json | 822 +++++++++++++++++- package.json | 12 +- release.config.js => release.config.cjs | 2 +- src/assets/svg/alicorn.svg | 3 + src/assets/svg/chart-column.svg | 4 + src/assets/svg/chart-line.svg | 3 + src/assets/svg/circle-nodes.svg | 3 + src/assets/svg/cloud.svg | 3 + src/assets/svg/connections.svg | 3 + src/assets/svg/database.svg | 3 + src/assets/svg/folder-closed.svg | 3 + src/assets/svg/gear.svg | 3 + src/assets/svg/grid.svg | 3 + src/assets/svg/heart.svg | 3 + src/assets/svg/lightbulb.svg | 3 + src/assets/svg/message-question.svg | 3 + src/assets/svg/shield-keyhole.svg | 3 + src/assets/svg/signout.svg | 7 + src/assets/svg/sitemap.svg | 4 + src/assets/svg/sparkles.svg | 4 + src/assets/svg/split.svg | 3 + src/assets/svg/users.svg | 3 + src/assets/svg/wrench.svg | 3 + .../data-display/Badge/Badge.stories.tsx | 4 +- .../data-display/Tooltip/Tooltip.tsx | 6 +- src/components/data-display/Tree/Tree.tsx | 2 +- .../data-entry/Mentions/Mentions.stories.tsx | 58 +- .../general/Typography/Typography.tsx | 11 +- src/components/icons/README.md | 4 + src/components/icons/index.ts | 49 ++ src/components/index.ts | 39 +- .../layout/Center/Center.stories.tsx | 16 +- src/components/layout/Center/Center.tsx | 22 +- .../GlobalNavigation.stories.tsx | 236 ++--- .../GlobalNavigation/GlobalNavigation.tsx | 31 +- .../GlobalNavigationItems.d.ts | 5 +- .../GlobalNavigation/NavigationCreate.tsx | 24 +- .../GlobalNavigation/NavigationSearch.tsx | 11 +- .../navigation/GlobalNavigation/SuiteLogo.tsx | 7 +- .../GlobalNavigation/WorkspaceInputLabel.tsx | 22 - .../GlobalNavigation/WorkspaceSearchLabel.tsx | 8 - .../GlobalNavigation/WorkspaceSelector.tsx | 204 ----- .../WorkspaceSelector/WorkspaceNoResults.tsx | 7 + .../WorkspaceSelector/WorkspaceSelector.tsx | 255 +++--- .../WorkspaceSelectorContent.tsx | 42 + .../WorkspaceSelectorContentItems.tsx | 16 + .../WorkspaceSelectorItems.d.ts | 16 +- .../WorkspaceSelector/WorkspaceSignout.tsx | 16 + .../WorkspaceSelector/workspace-selector.css | 127 ++- .../WorkspaceSelectorItems.d.ts | 29 - .../WorkspaceSignoutLabel.tsx | 18 - .../GlobalNavigation/global-navigation.css | 288 +++--- .../GlobalNavigation/stories-utils.ts | 38 + src/styles/_variables.css | 64 +- src/utils/debounce.ts | 6 +- src/utils/global.d.ts | 5 +- src/utils/utils.spec.ts | 72 +- src/utils/utils.ts | 46 +- 65 files changed, 1967 insertions(+), 981 deletions(-) rename .eslintrc.js => .eslintrc.cjs (93%) create mode 100644 .stylelintignore rename release.config.js => release.config.cjs (96%) create mode 100644 src/assets/svg/alicorn.svg create mode 100644 src/assets/svg/chart-column.svg create mode 100644 src/assets/svg/chart-line.svg create mode 100644 src/assets/svg/circle-nodes.svg create mode 100644 src/assets/svg/cloud.svg create mode 100644 src/assets/svg/connections.svg create mode 100644 src/assets/svg/database.svg create mode 100644 src/assets/svg/folder-closed.svg create mode 100644 src/assets/svg/gear.svg create mode 100644 src/assets/svg/grid.svg create mode 100644 src/assets/svg/heart.svg create mode 100644 src/assets/svg/lightbulb.svg create mode 100644 src/assets/svg/message-question.svg create mode 100644 src/assets/svg/shield-keyhole.svg create mode 100644 src/assets/svg/signout.svg create mode 100644 src/assets/svg/sitemap.svg create mode 100644 src/assets/svg/sparkles.svg create mode 100644 src/assets/svg/split.svg create mode 100644 src/assets/svg/users.svg create mode 100644 src/assets/svg/wrench.svg create mode 100644 src/components/icons/README.md create mode 100644 src/components/icons/index.ts delete mode 100644 src/components/navigation/GlobalNavigation/WorkspaceInputLabel.tsx delete mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSearchLabel.tsx delete mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSelector.tsx create mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceNoResults.tsx create mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContent.tsx create mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContentItems.tsx create mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSignout.tsx delete mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSelectorItems.d.ts delete mode 100644 src/components/navigation/GlobalNavigation/WorkspaceSignoutLabel.tsx create mode 100644 src/components/navigation/GlobalNavigation/stories-utils.ts diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 93% rename from .eslintrc.js rename to .eslintrc.cjs index 61174d87b..66b9a663f 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -2,6 +2,7 @@ module.exports = { env: { browser: true, es2024: true, + jest: true }, settings: { react: { @@ -103,18 +104,18 @@ module.exports = { 'NavigationIcon', 'NavigationList', 'WorkspaceSelector', - 'WorkspaceSearchLabel', - 'WorkspaceSignoutLabel', - 'WorkspaceInputLabel', + 'WorkspaceNoResults', + 'WorkspaceSignout', ], }, ], '@typescript-eslint/strict-boolean-expressions': 'off', '@typescript-eslint/consistent-type-definitions': 'off', '@typescript-eslint/no-use-before-define': ['error', { allowNamedExports: true, functions: false }], + "@typescript-eslint/promise-function-async": "warn", 'react/react-in-jsx-scope': 'off', 'import/no-duplicates': 'off', - 'react/jsx-boolean-value': ['always'], + 'react/jsx-boolean-value': 'warn' }, globals: { React: true, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1957189ae..73503b0c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,15 +4,9 @@ on: workflow_dispatch: jobs: - # release is done from main branch. - confirm-public-repo-main-branch: - name: 'Confirm release is run from public/main branch' - uses: mParticle/mparticle-workflows/.github/workflows/sdk-release-repo-branch-check.yml@main - release: name: Perform Release runs-on: ubuntu-latest - needs: confirm-public-repo-main-branch env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -27,7 +21,6 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - ref: main - name: Import GPG Key uses: crazy-max/ghaction-import-gpg@v4 @@ -39,7 +32,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 - with: + with: node-version: 'latest' - name: Install Dependencies @@ -57,4 +50,4 @@ jobs: if: failure() with: name: npm-logs - path: ~/.npm/_logs \ No newline at end of file + path: ~/.npm/_logs diff --git a/.gitignore b/.gitignore index 1b905fd56..3a679cd87 100644 --- a/.gitignore +++ b/.gitignore @@ -89,7 +89,6 @@ out # Nuxt.js build / generate output .nuxt -dist # Gatsby files .cache/ @@ -138,4 +137,6 @@ out/ test/reports test/test-bundle.js.map test/stub/test-stub-bundle.js + +dist/ **/dist \ No newline at end of file diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 000000000..add8ba4c3 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +src/styles/_variables.css \ No newline at end of file diff --git a/.stylelintrc b/.stylelintrc index 1ca93c3e4..4ad154476 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -6,6 +6,7 @@ "stylelint-no-indistinguishable-colors" ], "rules": { + "selector-class-pattern": null, "block-no-empty": true, "comment-no-empty": true, "no-duplicate-selectors": true, diff --git a/design/GlobalToken.json b/design/GlobalToken.json index 53758dee2..553ed5571 100644 --- a/design/GlobalToken.json +++ b/design/GlobalToken.json @@ -108,7 +108,7 @@ "value": "cubic-bezier(0.23, 1, 0.32, 1)" }, "borderRadius": { - "value": "6px" + "value": "8px" }, "sizeUnit": { "value": "4px" @@ -143,6 +143,12 @@ "controlOutline": { "value": "rgba(0.21176470816135406, 0, 0.8196078538894653, 0.10000000149011612)" }, + "colorWarningOutline": { + "value": "#fffbe6" + }, + "colorErrorOutline": { + "value": "#fff1f0" + }, "controlItemBgHover": { "value": "#f8f6fb" }, @@ -191,9 +197,90 @@ "colorSplit": { "value": "#eceae9" }, + "colorPrimaryBg": { + "value": "#f8f6fb" + }, + "colorPrimaryBgHover": { + "value": "#ebe8f8" + }, + "colorPrimaryBorder": { + "value": "#c3aeff" + }, + "colorPrimaryBorderHover": { + "value": "#ab8eff" + }, + "colorPrimaryHover": { + "value": "#ab8eff" + }, + "colorPrimaryActive": { + "value": "#8255ff" + }, + "colorPrimaryTextHover": { + "value": "#5f29f8" + }, + "colorPrimaryText": { + "value": "#2c00aa" + }, + "colorPrimaryTextActive": { + "value": "#20007a" + }, + "colorSuccessHover": { + "value": "#73d13d" + }, + "colorSuccessTextHover": { + "value": "#237804" + }, + "colorSuccessText": { + "value": "#135200" + }, + "colorSuccessTextActive": { + "value": "#092b00" + }, + "colorWarningHover": { + "value": "#ffc53d" + }, + "colorWarningTextHover": { + "value": "#ad6800" + }, + "colorWarningText": { + "value": "#874d00" + }, + "colorWarningTextActive": { + "value": "#613400" + }, + "colorErrorBg": { + "value": "#fff1f0" + }, + "colorErrorBgHover": { + "value": "#ffccc7" + }, + "colorErrorBorder": { + "value": "#ffa39e" + }, + "colorErrorBorderHover": { + "value": "#ff7875" + }, + "colorErrorHover": { + "value": "#ff4d4f" + }, + "colorErrorActive": { + "value": "#cf1322" + }, + "colorErrorTextHover": { + "value": "#a8071a" + }, + "colorErrorText": { + "value": "#820014" + }, + "colorErrorTextActive": { + "value": "#5c0011" + }, "colorBgMask": { "value": "#babbb5" }, + "borderRadiusLG": { + "value": "16px" + }, "mpBrandPrimary.1": { "value": "#f8f6fb" }, @@ -1046,33 +1133,6 @@ "colorBgBlur": { "value": "transparent" }, - "colorPrimaryBg": { - "value": "#f1e6ff" - }, - "colorPrimaryBgHover": { - "value": "#c8a3ff" - }, - "colorPrimaryBorder": { - "value": "#a677f7" - }, - "colorPrimaryBorderHover": { - "value": "#804beb" - }, - "colorPrimaryHover": { - "value": "#5b23de" - }, - "colorPrimaryActive": { - "value": "#2800ab" - }, - "colorPrimaryTextHover": { - "value": "#5b23de" - }, - "colorPrimaryText": { - "value": "#3600d1" - }, - "colorPrimaryTextActive": { - "value": "#2800ab" - }, "colorSuccessBg": { "value": "#f6ffed" }, @@ -1085,48 +1145,9 @@ "colorSuccessBorderHover": { "value": "#95de64" }, - "colorSuccessHover": { - "value": "#95de64" - }, "colorSuccessActive": { "value": "#389e0d" }, - "colorSuccessTextHover": { - "value": "#73d13d" - }, - "colorSuccessText": { - "value": "#52c41a" - }, - "colorSuccessTextActive": { - "value": "#389e0d" - }, - "colorErrorBg": { - "value": "#fff1f0" - }, - "colorErrorBgHover": { - "value": "#ffccc7" - }, - "colorErrorBorder": { - "value": "#ffa39e" - }, - "colorErrorBorderHover": { - "value": "#ff7875" - }, - "colorErrorHover": { - "value": "#ff4d4f" - }, - "colorErrorActive": { - "value": "#cf1322" - }, - "colorErrorTextHover": { - "value": "#ff4d4f" - }, - "colorErrorText": { - "value": "#f5222d" - }, - "colorErrorTextActive": { - "value": "#cf1322" - }, "colorWarningBg": { "value": "#fffbe6" }, @@ -1139,21 +1160,9 @@ "colorWarningBorderHover": { "value": "#ffd666" }, - "colorWarningHover": { - "value": "#ffd666" - }, "colorWarningActive": { "value": "#d48806" }, - "colorWarningTextHover": { - "value": "#ffc53d" - }, - "colorWarningText": { - "value": "#faad14" - }, - "colorWarningTextActive": { - "value": "#d48806" - }, "colorInfoBg": { "value": "#e6f4ff" }, @@ -1296,13 +1305,10 @@ "value": "2px" }, "borderRadiusSM": { - "value": "4px" - }, - "borderRadiusLG": { - "value": "8px" + "value": "6px" }, "borderRadiusOuter": { - "value": "4px" + "value": "6px" }, "colorFillContent": { "value": "#ebe8f8" @@ -1352,12 +1358,6 @@ "colorIconHover": { "value": "#0f0e0e" }, - "colorErrorOutline": { - "value": "rgba(255, 22, 5, 0.06)" - }, - "colorWarningOutline": { - "value": "rgba(255, 215, 5, 0.1)" - }, "fontSizeIcon": { "value": "12px" }, diff --git a/design/LightTheme.ts b/design/LightTheme.ts index c93089963..cad753d4c 100644 --- a/design/LightTheme.ts +++ b/design/LightTheme.ts @@ -2,12 +2,14 @@ * This theme is copy/pasted from figma, via the Token Buddy for Ant Design plugin * */ -import { IMpThemeConfig } from 'design/MpThemeConfig' +import { type IMpThemeConfig } from 'design/MpThemeConfig' export const LightTheme: IMpThemeConfig = { token: { colorLinkHover: '#ab8eff', controlOutline: 'rgba(0.21176470816135406, 0, 0.8196078538894653, 0.10000000149011612)', + colorWarningOutline: '#fffbe6', + colorErrorOutline: '#fff1f0', controlItemBgHover: '#f8f6fb', controlItemBgActive: '#ebe8f8', controlItemBgActiveHover: '#c3aeff', @@ -24,10 +26,38 @@ export const LightTheme: IMpThemeConfig = { colorBorder: '#c3aeff', colorBorderSecondary: '#eceae9', colorSplit: '#eceae9', + colorPrimaryBg: '#f8f6fb', + colorPrimaryBgHover: '#ebe8f8', + colorPrimaryBorder: '#c3aeff', + colorPrimaryBorderHover: '#ab8eff', + colorPrimaryHover: '#ab8eff', + colorPrimaryActive: '#8255ff', + colorPrimaryTextHover: '#5f29f8', + colorPrimaryText: '#2c00aa', + colorPrimaryTextActive: '#20007a', + colorSuccessHover: '#73d13d', + colorSuccessTextHover: '#237804', + colorSuccessText: '#135200', + colorSuccessTextActive: '#092b00', + colorWarningHover: '#ffc53d', + colorWarningTextHover: '#ad6800', + colorWarningText: '#874d00', + colorWarningTextActive: '#613400', + colorErrorBg: '#fff1f0', + colorErrorBgHover: '#ffccc7', + colorErrorBorder: '#ffa39e', + colorErrorBorderHover: '#ff7875', + colorErrorHover: '#ff4d4f', + colorErrorActive: '#cf1322', + colorErrorTextHover: '#a8071a', + colorErrorText: '#820014', + colorErrorTextActive: '#5c0011', colorBgMask: '#babbb5', colorTextBase: '#0f0e0e', colorPrimary: '#3600d1', colorError: '#f5222d', + borderRadiusLG: 16, + borderRadius: 8, fontFamily: "'GT America', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", fontFamilyCode: "'Roboto Mono', Consolas, 'Liberation Mono', Menlo, Courier, monospace", @@ -62,6 +92,8 @@ export const LightTheme: IMpThemeConfig = { Button: { borderColorDisabled: '#dcdcd8', primaryShadow: '0 2px 0 rgba(54, 0, 209, 0.1)', + onlyIconSizeLG: 20, + onlyIconSizeSM: 12, }, Menu: { darkItemBg: '#212020', diff --git a/package-lock.json b/package-lock.json index e5a6109b1..01bf7fc1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mparticle/aquarium", - "version": "1.1.1", + "version": "1.6.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mparticle/aquarium", - "version": "1.1.1", + "version": "1.6.2", "license": "Apache-2.0", "devDependencies": { "@storybook/addon-essentials": "7.6.14", @@ -24,6 +24,7 @@ "@typescript-eslint/eslint-plugin": "6.19.0", "@vitejs/plugin-react": "4.2.1", "concurrently": "8.2.2", + "cz-conventional-changelog": "^3.3.0", "eslint": "8.56.0", "eslint-config-prettier": "9.1.0", "eslint-config-standard-with-typescript": "43.0.0", @@ -2279,6 +2280,180 @@ "node": ">=0.1.90" } }, + "node_modules/@commitlint/config-validator": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.0.tgz", + "integrity": "sha512-oxJ2k+jBPRyWzv1ixfxwGZO5DJ1S+v3D8u/QESMwuPh3kQmeOYBRxGI+5FDWMwiVSHpztlhvvxDAU9SFXeMqUA==", + "dev": true, + "optional": true, + "dependencies": { + "@commitlint/types": "^19.0.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "optional": true + }, + "node_modules/@commitlint/execute-rule": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz", + "integrity": "sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.0.2.tgz", + "integrity": "sha512-ZbSQ8+vMsGHuZ/YxyDBz3i5zacQuAvON37xQGshGew/KwBmPfrF/sGEHNsD/znm3j2H6+iF5xslfkH1D382gbg==", + "dev": true, + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.0", + "@commitlint/execute-rule": "^19.0.0", + "@commitlint/resolve-extends": "^19.0.2", + "@commitlint/types": "^19.0.0", + "chalk": "^5.3.0", + "cosmiconfig": "^8.3.6", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "optional": true + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/load/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "optional": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@commitlint/load/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "optional": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.0.2.tgz", + "integrity": "sha512-yCdY4+JZpKPwnR6/YZAs9Ukpr3oqHbjYmwszEH2djYjprczg8j2okIeZyNM4dzD6+BqlSu/y0Eou2vE+wP+KnA==", + "dev": true, + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.0", + "@commitlint/types": "^19.0.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.0.0.tgz", + "integrity": "sha512-qLjLUdYXKi0TIavONrjBkxrElp7KguqDbvzIRbqTdJBV/cAAr8QEhHe1qUq8OcCM3gFWTlUrDz3ISZbkRoGsAg==", + "dev": true, + "optional": true, + "dependencies": { + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@csstools/css-parser-algorithms": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.0.tgz", @@ -9465,6 +9640,15 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -9960,6 +10144,15 @@ "node": ">= 0.8" } }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/caching-transform": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", @@ -10096,6 +10289,12 @@ "node": ">=10" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -10257,6 +10456,15 @@ "node": ">=8" } }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -10422,6 +10630,108 @@ "node": "^12.20.0 || >=14" } }, + "node_modules/commitizen": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", + "dev": true, + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/commitizen/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/commitizen/node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/commitizen/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/commitizen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/commitizen/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/commitizen/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -10629,6 +10939,12 @@ "node": ">= 0.6" } }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", + "dev": true + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -10713,6 +11029,24 @@ } } }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", + "dev": true, + "optional": true, + "dependencies": { + "jiti": "^1.19.1" + }, + "engines": { + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" + } + }, "node_modules/cosmiconfig/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -10808,29 +11142,120 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/cwd": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", + "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", + "dev": true, + "dependencies": { + "find-pkg": "^0.1.2", + "fs-exists-sync": "^0.1.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } + }, + "node_modules/cz-conventional-changelog/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cz-conventional-changelog/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cz-conventional-changelog/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/cz-conventional-changelog/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/cz-conventional-changelog/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cz-conventional-changelog/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "engines": { "node": ">=4" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/cwd": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", - "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", + "node_modules/cz-conventional-changelog/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "find-pkg": "^0.1.2", - "fs-exists-sync": "^0.1.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=0.8" + "node": ">=4" } }, "node_modules/date-fns": { @@ -11126,6 +11551,15 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", @@ -12634,6 +13068,20 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/extract-zip": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", @@ -12764,6 +13212,30 @@ "integrity": "sha512-3yurQZ2hD9VISAhJJP9bpYFNQrHHBXE2JxxjY5aLEcDi46RmAzJE2OC9FAde0yis5ElW0jTTzs0zfg/Cca4XqQ==", "dev": true }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -12960,6 +13432,16 @@ "node": ">=0.10.0" } }, + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, "node_modules/find-pkg": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", @@ -12995,6 +13477,12 @@ "node": ">= 6" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -13011,6 +13499,97 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/findup-sync/node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -13455,6 +14034,32 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "optional": true, + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "optional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/global-modules": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", @@ -14036,6 +14641,17 @@ "node": ">=8" } }, + "node_modules/import-meta-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", + "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", + "dev": true, + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -14076,6 +14692,69 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -14578,6 +15257,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -16224,6 +16909,16 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "optional": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/jju": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", @@ -16527,18 +17222,45 @@ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", "dev": true }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "optional": true + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "optional": true + }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "optional": true + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -16555,6 +17277,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/longest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -16725,6 +17456,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -16913,6 +17650,12 @@ "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", "dev": true }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -17756,6 +18499,15 @@ "node": ">=0.10.0" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -19915,6 +20667,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -21332,6 +22093,12 @@ "node": ">=12.22" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -21393,6 +22160,18 @@ "node": ">=14.0.0" } }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -22939,6 +23718,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", diff --git a/package.json b/package.json index 7eaa81155..890755b0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mparticle/aquarium", - "version": "1.1.1", + "version": "1.6.2", "description": "mParticle Component Library", "license": "Apache-2.0", "keywords": [ @@ -23,9 +23,9 @@ "dist/style.css" ], "peerDependencies": { + "antd": ">=5.13.1", "react": ">=17.0.2", - "react-dom": ">=17.0.2", - "antd": ">=5.13.1" + "react-dom": ">=17.0.2" }, "devDependencies": { "@storybook/addon-essentials": "7.6.14", @@ -43,6 +43,7 @@ "@typescript-eslint/eslint-plugin": "6.19.0", "@vitejs/plugin-react": "4.2.1", "concurrently": "8.2.2", + "cz-conventional-changelog": "3.3.0", "eslint": "8.56.0", "eslint-config-prettier": "9.1.0", "eslint-config-standard-with-typescript": "43.0.0", @@ -90,5 +91,10 @@ "*.{json,yml,md}": [ "prettier --write" ] + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } } } diff --git a/release.config.js b/release.config.cjs similarity index 96% rename from release.config.js rename to release.config.cjs index 58e6f2c05..f764a064c 100644 --- a/release.config.js +++ b/release.config.cjs @@ -1,5 +1,5 @@ module.exports = { - branches: ['main'], + branches: ['main', 'next'], tagFormat: 'v${version}', repositoryUrl: 'https://github.com/mParticle/aquarium', plugins: [ diff --git a/src/assets/svg/alicorn.svg b/src/assets/svg/alicorn.svg new file mode 100644 index 000000000..5c4bab4fe --- /dev/null +++ b/src/assets/svg/alicorn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/chart-column.svg b/src/assets/svg/chart-column.svg new file mode 100644 index 000000000..9aff09957 --- /dev/null +++ b/src/assets/svg/chart-column.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svg/chart-line.svg b/src/assets/svg/chart-line.svg new file mode 100644 index 000000000..b9bf69e93 --- /dev/null +++ b/src/assets/svg/chart-line.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/circle-nodes.svg b/src/assets/svg/circle-nodes.svg new file mode 100644 index 000000000..7f575b158 --- /dev/null +++ b/src/assets/svg/circle-nodes.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/cloud.svg b/src/assets/svg/cloud.svg new file mode 100644 index 000000000..fefc77300 --- /dev/null +++ b/src/assets/svg/cloud.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/connections.svg b/src/assets/svg/connections.svg new file mode 100644 index 000000000..8b9622fc4 --- /dev/null +++ b/src/assets/svg/connections.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/database.svg b/src/assets/svg/database.svg new file mode 100644 index 000000000..7500aeb41 --- /dev/null +++ b/src/assets/svg/database.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/folder-closed.svg b/src/assets/svg/folder-closed.svg new file mode 100644 index 000000000..9c6c71e5e --- /dev/null +++ b/src/assets/svg/folder-closed.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/gear.svg b/src/assets/svg/gear.svg new file mode 100644 index 000000000..462717ad0 --- /dev/null +++ b/src/assets/svg/gear.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/grid.svg b/src/assets/svg/grid.svg new file mode 100644 index 000000000..17c823a33 --- /dev/null +++ b/src/assets/svg/grid.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/heart.svg b/src/assets/svg/heart.svg new file mode 100644 index 000000000..4c2313807 --- /dev/null +++ b/src/assets/svg/heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/lightbulb.svg b/src/assets/svg/lightbulb.svg new file mode 100644 index 000000000..012b306d9 --- /dev/null +++ b/src/assets/svg/lightbulb.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/message-question.svg b/src/assets/svg/message-question.svg new file mode 100644 index 000000000..67a73cd50 --- /dev/null +++ b/src/assets/svg/message-question.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/shield-keyhole.svg b/src/assets/svg/shield-keyhole.svg new file mode 100644 index 000000000..036ba79f5 --- /dev/null +++ b/src/assets/svg/shield-keyhole.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/signout.svg b/src/assets/svg/signout.svg new file mode 100644 index 000000000..3838047b5 --- /dev/null +++ b/src/assets/svg/signout.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/assets/svg/sitemap.svg b/src/assets/svg/sitemap.svg new file mode 100644 index 000000000..f024ebad7 --- /dev/null +++ b/src/assets/svg/sitemap.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svg/sparkles.svg b/src/assets/svg/sparkles.svg new file mode 100644 index 000000000..051c3d508 --- /dev/null +++ b/src/assets/svg/sparkles.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svg/split.svg b/src/assets/svg/split.svg new file mode 100644 index 000000000..d9d8dc96b --- /dev/null +++ b/src/assets/svg/split.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/users.svg b/src/assets/svg/users.svg new file mode 100644 index 000000000..9c35630cd --- /dev/null +++ b/src/assets/svg/users.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/wrench.svg b/src/assets/svg/wrench.svg new file mode 100644 index 000000000..7b0600d83 --- /dev/null +++ b/src/assets/svg/wrench.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/data-display/Badge/Badge.stories.tsx b/src/components/data-display/Badge/Badge.stories.tsx index 8d4e41253..5617f4ca1 100644 --- a/src/components/data-display/Badge/Badge.stories.tsx +++ b/src/components/data-display/Badge/Badge.stories.tsx @@ -130,7 +130,7 @@ export const ExampleStandalone: Story = { export const ExampleOverflowCount: Story = { render: () => { return ( - + @@ -302,4 +302,4 @@ export const ExampleColors: Story = { ) }, -} \ No newline at end of file +} diff --git a/src/components/data-display/Tooltip/Tooltip.tsx b/src/components/data-display/Tooltip/Tooltip.tsx index 21350d134..874b3a824 100644 --- a/src/components/data-display/Tooltip/Tooltip.tsx +++ b/src/components/data-display/Tooltip/Tooltip.tsx @@ -7,11 +7,11 @@ export interface ITooltipProps extends AntTooltipPropsWithTitle {} export const Tooltip = (props: ITooltipProps) => { return ( - + {/* Fragment fixes tooltip sometimes not showing */} - {/*https://github.com/ant-design/ant-design/issues/15909*/} + {/* https://github.com/ant-design/ant-design/issues/15909 */} <>{props.children} ) -} \ No newline at end of file +} diff --git a/src/components/data-display/Tree/Tree.tsx b/src/components/data-display/Tree/Tree.tsx index 6fb2e99a5..e0ae0783e 100644 --- a/src/components/data-display/Tree/Tree.tsx +++ b/src/components/data-display/Tree/Tree.tsx @@ -1,4 +1,4 @@ -import { Tree as AntTree, TreeDataNode } from 'antd' +import { Tree as AntTree, type TreeDataNode } from 'antd' import { type TreeProps as AntTreeProps } from 'antd' import { ConfigProvider } from 'src/components' diff --git a/src/components/data-entry/Mentions/Mentions.stories.tsx b/src/components/data-entry/Mentions/Mentions.stories.tsx index 26693e38d..3ec3356f9 100644 --- a/src/components/data-entry/Mentions/Mentions.stories.tsx +++ b/src/components/data-entry/Mentions/Mentions.stories.tsx @@ -66,15 +66,14 @@ export const Primary: Story = { control: 'select', options: ['outlined', 'borderless', 'filled'], }, - }, -// @ts-ignore - status: { - control: 'select', - options: ['error', 'warning'] - }, - placement: { - control: 'select', - options: ['top', 'bottom'], + status: { + control: 'select', + options: ['error', 'warning'], + }, + placement: { + control: 'select', + options: ['top', 'bottom'], + }, }, } @@ -165,10 +164,15 @@ export const ExampleVariants: Story = { }, } +type ItemType = { + login: string + avatar_url: string +} + export const ExampleAsync: Story = { render: () => { const [loading, setLoading] = useState(false) - const [users, setUsers] = useState>([]) + const [users, setUsers] = useState([]) const ref = useRef() const loadGithubUsers = (key: string) => { if (!key) { @@ -177,10 +181,10 @@ export const ExampleAsync: Story = { } void fetch(`https://api.github.com/search/users?q=${key}`) .then(async res => await res.json()) - .then(({ items = [] }) => { + .then(({ items = [] }: { items: ItemType[] }) => { if (ref.current !== key) return setLoading(false) - setUsers(items.slice(0, 10) || []) + setUsers(items.slice(0, 10) ?? []) }) } const debounceLoadGithubUsers = useCallback(loadGithubUsers, []) @@ -240,7 +244,13 @@ export const ExampleForm: Story = { } return ( -
+ { + void onFinish() + }} + > { - const [value, setValue] = useState('hello world'); + const [value, setValue] = useState('hello world') return ( <>

- }} /> + }} />

@@ -345,15 +355,14 @@ export const ExampleClearIcon: Story = {
) }, -}; +} export const ExampleStatus: Story = { render: () => { - const onChange = (value: string) => { - console.log('Change:', value); - }; - + console.log('Change:', value) + } + const options = [ { value: 'afc163', @@ -367,9 +376,8 @@ export const ExampleStatus: Story = { value: 'yesmeck', label: 'yesmeck', }, - ]; - - + ] + return ( @@ -389,6 +397,6 @@ export const ExampleStatus: Story = { /> - ); + ) }, -}; \ No newline at end of file +} diff --git a/src/components/general/Typography/Typography.tsx b/src/components/general/Typography/Typography.tsx index 41e57e526..bf5ea299b 100644 --- a/src/components/general/Typography/Typography.tsx +++ b/src/components/general/Typography/Typography.tsx @@ -1,14 +1,13 @@ import { Typography as AntTypography } from 'antd' import { ConfigProvider } from 'src/components' import { type ReactNode } from 'react' -import { TextProps as AntTextProps } from 'antd/es/typography/Text' -import { TitleProps as AntTitleProps } from 'antd/es/typography/Title' -import { LinkProps as AntLinkProps } from 'antd/es/typography/Link' -import { ParagraphProps as AntParagraphProps } from 'antd/es/typography/Paragraph' +import { type TextProps as AntTextProps } from 'antd/es/typography/Text' +import { type TitleProps as AntTitleProps } from 'antd/es/typography/Title' +import { type LinkProps as AntLinkProps } from 'antd/es/typography/Link' +import { type ParagraphProps as AntParagraphProps } from 'antd/es/typography/Paragraph' export const Typography = AntTypography - export interface ITextProps extends AntTextProps { children: ReactNode } @@ -47,4 +46,4 @@ export const Paragraph = (props: IParagraphProps) => ( {props.children} -) \ No newline at end of file +) diff --git a/src/components/icons/README.md b/src/components/icons/README.md new file mode 100644 index 000000000..8ba86687c --- /dev/null +++ b/src/components/icons/README.md @@ -0,0 +1,4 @@ +# Icons + +In order to add new icons to the Aquarium, add the .svg files to the `src/assets/svg/` directory, +import/export them from `src/components/icons/index.ts` and export them from `src/components/index.ts` diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts new file mode 100644 index 000000000..02c2f852d --- /dev/null +++ b/src/components/icons/index.ts @@ -0,0 +1,49 @@ +import ChartLineIcon from 'src/assets/svg/chart-line.svg?react' +import ConnectionsIcon from 'src/assets/svg/connections.svg?react' +import DatabaseIcon from 'src/assets/svg/database.svg?react' +import GridIcon from 'src/assets/svg/grid.svg?react' +import ShieldKeyholeIcon from 'src/assets/svg/shield-keyhole.svg?react' +import UsersIcon from 'src/assets/svg/users.svg?react' +import WrenchIcon from 'src/assets/svg/wrench.svg?react' +import AlicornIcon from 'src/assets/svg/alicorn.svg?react' +import MessageQuestionIcon from 'src/assets/svg/message-question.svg?react' +import GearIcon from 'src/assets/svg/gear.svg?react' +import SparklesIcon from 'src/assets/svg/sparkles.svg?react' +import SiteMapIcon from 'src/assets/svg/sitemap.svg?react' +import ChartColumnIcon from 'src/assets/svg/chart-column.svg?react' +import HeartIcon from 'src/assets/svg/heart.svg?react' +import LightBulbIcon from 'src/assets/svg/lightbulb.svg?react' +import SplitIcon from 'src/assets/svg/split.svg?react' +import CircleNodesIcon from 'src/assets/svg/circle-nodes.svg?react' +import CloudIcon from 'src/assets/svg/cloud.svg?react' +import FolderClosedIcon from 'src/assets/svg/folder-closed.svg?react' +import AddIcon from 'src/assets/svg/add.svg?react' +import MpLogoIcon from 'src/assets/svg/mpLogo.svg?react' +import LockIcon from 'src/assets/svg/lock.svg?react' +import SearchIcon from 'src/assets/svg/search.svg?react' + +export { + AddIcon, + LockIcon, + MpLogoIcon, + SearchIcon, + ChartLineIcon, + ConnectionsIcon, + DatabaseIcon, + GridIcon, + ShieldKeyholeIcon, + UsersIcon, + WrenchIcon, + AlicornIcon, + MessageQuestionIcon, + GearIcon, + SparklesIcon, + SiteMapIcon, + ChartColumnIcon, + HeartIcon, + LightBulbIcon, + SplitIcon, + CircleNodesIcon, + CloudIcon, + FolderClosedIcon, +} diff --git a/src/components/index.ts b/src/components/index.ts index be5b0b3fa..b1b759fba 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -70,7 +70,7 @@ export { type SubMenuType, type MenuItemGroupType, type MenuDividerType, - type IMenuInfo + type IMenuInfo, } from './navigation/Menu/Menu' export { ConfigProvider, type IConfigProviderProps } from './other/ConfigProvider/ConfigProvider' export { Affix, type IAffixProps } from './other/Affix/Affix' @@ -81,19 +81,46 @@ export { type IGlobalNavigationProps, } from './navigation/GlobalNavigation/GlobalNavigation' export type { - IGlobalNavigationLogo, + IBaseGlobalNavigationItem, IGlobalNavigationManagement, IGlobalNavigationTool, -} from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' + IGlobalNavigationLogo, +} from './navigation/GlobalNavigation/GlobalNavigationItems' export type { INavigationCreateProps, INavigationCreateGroup, INavigationCreateItem, -} from 'src/components/navigation/GlobalNavigation/NavigationCreate' -export type { +} from './navigation/GlobalNavigation/NavigationCreate' +export type { INavigationOrg, INavigationWorkspace, INavigationAccount, IWorkspaceSelectorDisplayItem, IWorkspaceSelectorItem, -} from './navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems' \ No newline at end of file +} from './navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems' +export { SuiteLogo } from './navigation/GlobalNavigation/SuiteLogo' +export { + AddIcon, + LockIcon, + MpLogoIcon, + SearchIcon, + ChartLineIcon, + ConnectionsIcon, + DatabaseIcon, + GridIcon, + ShieldKeyholeIcon, + UsersIcon, + WrenchIcon, + AlicornIcon, + MessageQuestionIcon, + GearIcon, + SparklesIcon, + SiteMapIcon, + ChartColumnIcon, + HeartIcon, + LightBulbIcon, + SplitIcon, + CircleNodesIcon, + CloudIcon, + FolderClosedIcon, +} from './icons/index' \ No newline at end of file diff --git a/src/components/layout/Center/Center.stories.tsx b/src/components/layout/Center/Center.stories.tsx index b98df7e57..516bb70cb 100644 --- a/src/components/layout/Center/Center.stories.tsx +++ b/src/components/layout/Center/Center.stories.tsx @@ -1,17 +1,15 @@ -import { Meta } from "@storybook/react"; -import { StoryObj } from "@storybook/react"; -import { Center } from "src/components/layout/Center/Center"; +import { type Meta } from '@storybook/react' +import { type StoryObj } from '@storybook/react' +import { Center } from 'src/components/layout/Center/Center' const meta: Meta = { - title: "Aquarium/Layout/Center", + title: 'Aquarium/Layout/Center', component: Center, args: {}, -}; -export default meta; - +} +export default meta type Story = StoryObj - -export const Primary: Story = {}; \ No newline at end of file +export const Primary: Story = {} diff --git a/src/components/layout/Center/Center.tsx b/src/components/layout/Center/Center.tsx index 1cdf10e00..f80f0b32a 100644 --- a/src/components/layout/Center/Center.tsx +++ b/src/components/layout/Center/Center.tsx @@ -1,11 +1,13 @@ -import React from "react"; -import { IFlexProps } from "src/components/layout/Flex/Flex"; -import { Flex } from "src/components/layout/Flex/Flex"; +import React from 'react' +import { type IFlexProps } from 'src/components/layout/Flex/Flex' +import { Flex } from 'src/components/layout/Flex/Flex' -export const Center = (props: Omit) => { - return <> - - {props.children} - - ; -}; \ No newline at end of file +export const Center = (props: Omit) => { + return ( + <> + + {props.children} + + + ) +} diff --git a/src/components/navigation/GlobalNavigation/GlobalNavigation.stories.tsx b/src/components/navigation/GlobalNavigation/GlobalNavigation.stories.tsx index 5b23a16b4..24c6e9fe1 100644 --- a/src/components/navigation/GlobalNavigation/GlobalNavigation.stories.tsx +++ b/src/components/navigation/GlobalNavigation/GlobalNavigation.stories.tsx @@ -1,38 +1,62 @@ +import React from 'react' import { type Meta } from '@storybook/react' import { type StoryObj } from '@storybook/react' -import { GlobalNavigation } from 'src/components' +import { + ChartLineIcon, + ConnectionsIcon, + DatabaseIcon, + GearIcon, + GlobalNavigation, + GridIcon, + MessageQuestionIcon, + UsersIcon, + WrenchIcon, + MpLogoIcon, +} from 'src/components' import { Space } from 'src/components' import { Center } from 'src/components' import { Button } from 'src/components' import { type INavigationCreateProps } from 'src/components' +import { FolderClosedIcon } from 'src/components' +import { ShieldKeyholeIcon } from 'src/components' +import { HeartIcon } from 'src/components' +import { AlicornIcon } from 'src/components' +import { CloudIcon } from 'src/components' import { Badge } from 'src/components/data-display/Badge/Badge' import { type INavigationOrg } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems' import { type IGlobalNavigationLogo } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' import { type IGlobalNavigationManagement } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' import { type IGlobalNavigationTool } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' -import MpLogo from 'src/assets/svg/mpLogo.svg?react' +import { SparklesIcon } from 'src/components' +import { CircleNodesIcon } from 'src/components' +import { SplitIcon } from 'src/components' +import { LightBulbIcon } from 'src/components' +import { generateOrgs } from 'src/components/navigation/GlobalNavigation/stories-utils' const defaultLogo: IGlobalNavigationLogo = { label: 'Aqua', - icon: , + icon: , + onSuiteLogoClick: () => { + alert('Going to Aqua Home!') + }, } const defaultTools: IGlobalNavigationTool[] = [ { label: 'Tool 1', isActive: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, { label: 'Tool 2', - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, { label: 'Tool 3', - icon: , + icon: , type: 'link', }, ] @@ -40,20 +64,20 @@ const defaultManagement: IGlobalNavigationManagement[] = [ { label: 'Notifications', hideLabel: true, - icon: , + icon: , type: 'link', }, { label: 'Support', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, { label: 'Settings', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, @@ -71,7 +95,7 @@ const defaultOrgs: INavigationOrg[] = [ id: 'workspace1', label: 'Workspace 1', isActive: true, - onClick: e => { + onClick: () => { alert('Selected Workspace 1') }, }, @@ -99,7 +123,9 @@ const meta: Meta = { alert('signing out!') }, }, - onMpHomeClick:() => { alert('Going to mP!') } + onMpHomeClick: () => { + alert('Going to mP!') + }, }, } export default meta @@ -110,7 +136,10 @@ export const Primary: Story = {} const mpLogo: IGlobalNavigationLogo = { label: 'Data Platform', - icon: , + icon: , + onSuiteLogoClick: () => { + alert('Going to mP Home!') + }, } function Beta(label: string) { @@ -125,7 +154,7 @@ function Beta(label: string) { const mpTools: IGlobalNavigationTool[] = [ { label: 'Activity', - icon: , + icon: , type: 'menu', children: [ { label: 'Platform Trends' }, @@ -143,7 +172,7 @@ const mpTools: IGlobalNavigationTool[] = [ }, { label: 'Data Master', - icon: , + icon: , type: 'menu', children: [ { label: 'Catalog' }, @@ -156,54 +185,41 @@ const mpTools: IGlobalNavigationTool[] = [ }, { label: 'Audiences', - icon: , + icon: , type: 'menu', children: [{ label: 'Real-time' }, { label: 'Standard' }, { label: 'Journeys' }], }, { - label: 'Observability', - icon: , + label: 'Connections', + icon: , type: 'menu', - children: [ - { label: 'Connect' }, - { - label: 'Filter', - isNestedMenu: true, - children: [{ label: 'Platforms' }, { label: 'Feeds' }], - }, - ], + children: [{ label: 'Connect' }, { label: 'Platform Filters' }, { label: 'Feed Filters' }], }, { label: 'Setup', - icon: , + icon: , type: 'menu', children: [{ label: 'Inputs' }, { label: 'Outputs' }, { label: 'Data Warehouse' }, { label: 'CRM' }], }, { label: 'Directory', - icon: , + icon: , type: 'link', }, ] const mpManagement: IGlobalNavigationManagement[] = [ - { - label: 'Notifications', - hideLabel: true, - icon: , - type: 'link', - }, { isActive: true, label: 'Support', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, { label: 'Settings', hideLabel: true, - icon: , + icon: , type: 'menu', children: [ { label: 'Platform Settings' }, @@ -225,7 +241,7 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace1', label: 'Workspace 1', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 1') }, }, @@ -233,7 +249,7 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace1a', label: 'Workspace 1a', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 1a') }, }, @@ -241,42 +257,12 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace1b', label: 'Workspace 1b', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 1b') }, }, ], }, - { - id: 'account1a', - label: 'Account 1a', - workspaces: [ - { - id: 'workspace12', - label: 'Workspace 12', - isActive: false, - onClick: e => { - alert('Selected workspace 12') - }, - }, - { - id: 'workspace12a', - label: 'Workspace 12a', - isActive: false, - onClick: e => { - alert('Selected workspace 12a') - }, - }, - { - id: 'workspace12b', - label: 'Workspace 12b', - isActive: false, - onClick: e => { - alert('Selected workspace 12b') - }, - }, - ], - }, ], }, { @@ -291,7 +277,29 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace2', label: 'Workspace 2', isActive: false, - onClick: e => { + onClick: () => { + alert('Selected workspace 2') + }, + }, + ], + }, + { + id: 'account2a', + label: 'Account 2a', + workspaces: [ + { + id: 'workspace2a', + label: 'Workspace 2a', + isActive: false, + onClick: () => { + alert('Selected workspace 2') + }, + }, + { + id: 'workspace2ab', + label: '_Workspace 2ab', + isActive: true, + onClick: () => { alert('Selected workspace 2') }, }, @@ -311,7 +319,7 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace3', label: 'Workspace 3', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 3') }, }, @@ -331,7 +339,7 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace4', label: 'Workspace 4', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 4') }, }, @@ -351,7 +359,7 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace5', label: 'Workspace 5', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 5') }, }, @@ -371,7 +379,7 @@ const mpOrgs: INavigationOrg[] = [ id: 'workspace6', label: 'Workspace 6', isActive: false, - onClick: e => { + onClick: () => { alert('Selected workspace 6') }, }, @@ -390,8 +398,8 @@ const mpOrgs: INavigationOrg[] = [ { id: 'workspace7', label: 'Workspace 7', - isActive: true, - onClick: e => { + isActive: false, + onClick: () => { alert('Selected workspace 7') }, }, @@ -412,28 +420,59 @@ export const MP: Story = { onMpHomeClick: () => { alert('going to overview map') }, + avatarOptions: { + // src: "https://static-qa1.qa.corp.mparticle.com/appimg/logo_af_916397d2-9732-8de6-77cc-80e3bba120ca.png", + alt: 'avatar', + }, + }, +} + +const thousandOrgs = generateOrgs(1000, 4, 4) + +export const MPThousandOrgs: Story = { + render: props => { + return ( +
+ { + alert('Searching!') + }} + logo={mpLogo} + tools={mpTools} + management={mpManagement} + orgs={thousandOrgs} + onMpHomeClick={() => { + alert('going to overview map') + }} + /> +
+ ) }, } const indLogo: IGlobalNavigationLogo = { label: 'Analytics', - icon: , + icon: , + onSuiteLogoClick: () => { + alert('Going to Analytics Home!') + }, } const indTools: IGlobalNavigationTool[] = [ { label: 'My Hub', - icon: , + icon: , type: 'link', isActive: true, }, { label: 'Saved', - icon: , + icon: , type: 'link', }, { label: 'Manage Data', - icon: , + icon: , type: 'link', }, ] @@ -441,14 +480,14 @@ const indManagement: IGlobalNavigationManagement[] = [ { label: 'Support', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, { label: 'Settings', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, @@ -581,7 +620,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 1', label: 'Project 1', isActive: false, - onClick: e => { + onClick: () => { alert('Selected project 1') }, }, @@ -601,7 +640,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 2', label: 'Project 2', isActive: true, - onClick: e => { + onClick: () => { alert('Selected project 2') }, }, @@ -621,7 +660,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 3', label: 'Project 3', isActive: false, - onClick: e => { + onClick: () => { alert('Selected project 3') }, }, @@ -641,7 +680,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 4', label: 'Project 4', isActive: false, - onClick: e => { + onClick: () => { alert('Selected project 4') }, }, @@ -661,7 +700,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 5', label: 'Project 5', isActive: false, - onClick: e => { + onClick: () => { alert('Selected project 5') }, }, @@ -681,7 +720,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 6', label: 'Project 6', isActive: false, - onClick: e => { + onClick: () => { alert('Selected project 6') }, }, @@ -701,7 +740,7 @@ const indOrgs: INavigationOrg[] = [ id: 'project 7', label: 'Project 7', isActive: false, - onClick: e => { + onClick: () => { alert('Selected project 7') }, }, @@ -732,33 +771,36 @@ export const Indicative: Story = { const cortexLogo: IGlobalNavigationLogo = { label: 'Predictions', - icon: , + icon: , + onSuiteLogoClick: () => { + alert('Going to Predictions Home!') + }, } const cortexTools: IGlobalNavigationTool[] = [ { label: 'Pipelines', - icon: , + icon: , type: 'link', }, { label: 'Projects', - icon: , + icon: , type: 'link', isActive: true, }, { label: 'Data', - icon: , + icon: , type: 'link', }, { label: 'API', - icon: , + icon: , type: 'link', }, { label: 'Insights', - icon: , + icon: , type: 'link', }, ] @@ -766,14 +808,14 @@ const cortexManagement: IGlobalNavigationManagement[] = [ { label: 'Support', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, { label: 'Settings', hideLabel: true, - icon: , + icon: , type: 'menu', children: [{ label: 'option 1' }, { label: 'option 2' }, { label: 'option 3' }], }, @@ -872,4 +914,4 @@ export const Cortex: Story = { alert('going to overview map') }, }, -} \ No newline at end of file +} diff --git a/src/components/navigation/GlobalNavigation/GlobalNavigation.tsx b/src/components/navigation/GlobalNavigation/GlobalNavigation.tsx index 3ea004726..6c5672e9c 100644 --- a/src/components/navigation/GlobalNavigation/GlobalNavigation.tsx +++ b/src/components/navigation/GlobalNavigation/GlobalNavigation.tsx @@ -1,6 +1,6 @@ import 'src/styles/_variables.css' import './global-navigation.css' -import { Layout } from 'src/components' +import { type IAvatarProps, Layout } from 'src/components' import { Flex } from 'src/components' import { Center } from 'src/components' import { type INavigationCreateProps } from 'src/components' @@ -10,23 +10,28 @@ import { NavigationSearch } from 'src/components/navigation/GlobalNavigation/Nav import { NavigationList } from 'src/components/navigation/GlobalNavigation/NavigationList' import { NavigationCreate } from 'src/components/navigation/GlobalNavigation/NavigationCreate' import { WorkspaceSelector } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector' -import { type INavigationOrg } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type IGlobalNavigationLogo } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' import { type IGlobalNavigationManagement } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' import { type IGlobalNavigationTool } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' +import { type INavigationOrg } from 'src/components' import MpLogo from 'src/assets/svg/mpLogo.svg?react' +import SignoutIcon from 'src/assets/svg/signout.svg?react' +import { type IGlobalNavigationLogo } from 'src/components' +import { NavigationItem } from 'src/components/navigation/GlobalNavigation/NavigationItem' export interface IGlobalNavigationProps { logo: IGlobalNavigationLogo tools: IGlobalNavigationTool[] management: IGlobalNavigationManagement[] + // eslint-disable-next-line no-undef orgs?: INavigationOrg[] createItems?: INavigationCreateProps['createItems'] onSearchClick?: () => void + onSuiteLogoClick?: () => void onMpHomeClick: () => void hideMpHome?: boolean + avatarOptions?: IAvatarProps signoutOptions?: { label?: string onSignout: () => void @@ -43,6 +48,8 @@ export const GlobalNavigation = (props: IGlobalNavigationProps) => {
+
+
{props.onSearchClick && } {props.createItems && } @@ -54,7 +61,23 @@ export const GlobalNavigation = (props: IGlobalNavigationProps) => {
- {props.orgs && } + {props.orgs ? ( + + ) : ( + !!props.signoutOptions?.onSignout && ( + } + label="Sign Out" + hideLabel + onClick={props.signoutOptions?.onSignout} + /> + ) + )} {!props.hideMpHome && ( diff --git a/src/components/navigation/GlobalNavigation/GlobalNavigationItems.d.ts b/src/components/navigation/GlobalNavigation/GlobalNavigationItems.d.ts index 0a6bb8f9e..9c8c36505 100644 --- a/src/components/navigation/GlobalNavigation/GlobalNavigationItems.d.ts +++ b/src/components/navigation/GlobalNavigation/GlobalNavigationItems.d.ts @@ -9,13 +9,16 @@ export interface IBaseGlobalNavigationItem { isActive?: boolean } -export interface IGlobalNavigationLogo extends IBaseGlobalNavigationItem {} +export interface IGlobalNavigationLogo extends IBaseGlobalNavigationItem { + onSuiteLogoClick: () => void +} export interface IGlobalNavigationMenu extends IBaseGlobalNavigationItem { type: 'menu' isNestedMenu?: boolean children?: IGlobalNavigationMenuItem[] } + interface IGlobalNavigationMenuItem extends Omit { type?: 'menu' isNestedMenu?: boolean diff --git a/src/components/navigation/GlobalNavigation/NavigationCreate.tsx b/src/components/navigation/GlobalNavigation/NavigationCreate.tsx index 437faba97..ebf19c84d 100644 --- a/src/components/navigation/GlobalNavigation/NavigationCreate.tsx +++ b/src/components/navigation/GlobalNavigation/NavigationCreate.tsx @@ -9,6 +9,7 @@ import { Tooltip } from 'src/components' import { Spin } from 'src/components' import LockIcon from 'src/assets/svg/lock.svg?react' import AddIcon from 'src/assets/svg/add.svg?react' +import { type IMenuInfo } from 'src/components' export interface INavigationCreateProps { createItems: Array @@ -38,26 +39,28 @@ export function NavigationCreate(props: INavigationCreateProps) { const isDisabled = item.disabled let itemClassName = 'navigationCreate__item' - if (isDisabled ?? isLocked) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (isDisabled || isLocked || item.isLoading) { itemClassName += ' navigationCreate__item--disabled' } return { key: item.description, className: itemClassName, disabled: item.disabled, - onClick: menuInfo => { - if (item.disabled) return + onClick: (menuInfo: IMenuInfo): void => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (item.disabled || item.isLoading) return item.onClick?.() menuInfo.domEvent.stopPropagation() menuInfo.domEvent.preventDefault() }, label: ( - + {item.title} {item.isLoading && } - {isLocked && } + {isLocked && } {item.description} @@ -65,15 +68,18 @@ export function NavigationCreate(props: INavigationCreateProps) { ), } - }); - + }) + const items: IMenuProps['items'] = [ { key: 'NavigationCreate', popupClassName: 'globalNavigation__popup globalNavigation__popup--navigationCreate', icon: (
-
), @@ -91,4 +97,4 @@ export function NavigationCreate(props: INavigationCreateProps) { />
) -} \ No newline at end of file +} diff --git a/src/components/navigation/GlobalNavigation/NavigationSearch.tsx b/src/components/navigation/GlobalNavigation/NavigationSearch.tsx index 5bf5bd582..fc25cbde4 100644 --- a/src/components/navigation/GlobalNavigation/NavigationSearch.tsx +++ b/src/components/navigation/GlobalNavigation/NavigationSearch.tsx @@ -3,6 +3,7 @@ import { Space } from 'src/components' import { Center } from 'src/components' import { Button } from 'src/components' import SearchIcon from 'src/assets/svg/search.svg?react' +import { getOS } from 'src/utils/utils' interface INavigationSearchProps { onClick: () => void @@ -16,14 +17,18 @@ export function NavigationSearch(props: INavigationSearchProps) { title={ <>Search - <>Ctrl + K + <>{getOS() === 'Macintosh' ? 'Cmd' : 'Ctrl'} + K } >
-
) -} \ No newline at end of file +} diff --git a/src/components/navigation/GlobalNavigation/SuiteLogo.tsx b/src/components/navigation/GlobalNavigation/SuiteLogo.tsx index 91f772955..2ddbb8272 100644 --- a/src/components/navigation/GlobalNavigation/SuiteLogo.tsx +++ b/src/components/navigation/GlobalNavigation/SuiteLogo.tsx @@ -1,13 +1,12 @@ import { Center } from 'src/components' import { NavigationIcon } from 'src/components/navigation/GlobalNavigation/NavigationIcon' -import { type IGlobalNavigationLogo } from "src/components/navigation/GlobalNavigation/GlobalNavigationItems"; +import { type IGlobalNavigationLogo } from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' export function SuiteLogo(props: IGlobalNavigationLogo) { return ( -
- +
+ {props.label} -
) } \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceInputLabel.tsx b/src/components/navigation/GlobalNavigation/WorkspaceInputLabel.tsx deleted file mode 100644 index 027739612..000000000 --- a/src/components/navigation/GlobalNavigation/WorkspaceInputLabel.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Input } from 'src/components' - -export const WorkspaceInputLabel = ({ - onSearch, - searchTerm, -}: { - onSearch: (e: React.ChangeEvent) => void - searchTerm: string -}) => ( - <> - { - e.preventDefault() - e.stopPropagation() - }} - /> - -) \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSearchLabel.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSearchLabel.tsx deleted file mode 100644 index e615e01fa..000000000 --- a/src/components/navigation/GlobalNavigation/WorkspaceSearchLabel.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { Center } from "src/components"; -import { Empty } from "src/components"; - -export const WorkspaceSearchLabel = () => ( -
- -
-); \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSelector.tsx deleted file mode 100644 index f3b6f75b2..000000000 --- a/src/components/navigation/GlobalNavigation/WorkspaceSelector.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import 'src/utils/utils.css' -import './workspace-selector.css' -import { Avatar } from 'src/components' -import { Menu } from 'src/components' -import { type IMenuProps } from 'src/components' -import { type INavigationOrg } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type IWorkspaceSelectorDisplayItem } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type INavigationAccount } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type INavigationWorkspace } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type MenuItemType } from 'src/components/navigation/Menu/Menu' -import { useState } from 'react' -import { useCallback } from 'react' -import { useEffect } from 'react' -import { useMemo } from 'react' -import { useRef } from 'react' -import { debounce } from 'src/utils/utils' -import { getInitials } from 'src/utils/utils' -import { WorkspaceSearchLabel } from 'src/components/navigation/GlobalNavigation/WorkspaceSearchLabel' -import { WorkspaceSignoutLabel } from 'src/components/navigation/GlobalNavigation/WorkspaceSignoutLabel' -import { WorkspaceInputLabel } from 'src/components/navigation/GlobalNavigation/WorkspaceInputLabel' - -export interface IWorkspaceSelectorProps { - orgs: INavigationOrg[] - signoutOptions?: { - label?: string - onSignout: () => void - } -} - -export function WorkspaceSelector(props: IWorkspaceSelectorProps) { - const [searchTerm, setSearchTerm] = useState('') - - const [currentFilteredOrgs, setCurrentFilteredOrgs] = useState(props.orgs) - useEffect(() => { - // since we are setting state from props, when the props change be sure to update the state - setCurrentFilteredOrgs(props.orgs) - }, props.orgs) - - const setCurrentFilteredOrgsDebounced = useCallback(debounce(setCurrentFilteredOrgs, 200), []) - - const menuItems: IWorkspaceSelectorDisplayItem[] = useMemo( - () => generateDisplayItems(/* currentFilteredOrgs */), - currentFilteredOrgs, - ) - - // todo: this probably doesnt need to be calculated on every render - const activeWorkspace: INavigationWorkspace = props.orgs - .flatMap(org => { - let flattenedSelectors: INavigationWorkspace[] = [] - - const { accounts } = org - if (accounts) { - const workspaces = accounts.flatMap(({ workspaces }) => workspaces) - flattenedSelectors = flattenedSelectors.concat(workspaces) - } - - return flattenedSelectors - }) - .find(workspaceCandidate => (workspaceCandidate as INavigationWorkspace).isActive) as INavigationWorkspace - - const items: IMenuProps['items'] = [ - { - key: 'WorkspaceSelector', - icon: {getInitials(activeWorkspace?.label)}, - popupClassName: 'workspaceSelector', - children: createMenuChildren(), - }, - ] - - return ( - - ) - - function generateDisplayItems(): IWorkspaceSelectorDisplayItem[] { - return currentFilteredOrgs.reduce((total, org) => { - total.push({ - type: 'org', - className: 'workspaceSelector__orgName' + (org.label ? '' : ' u-display-none'), - label: org.label, - id: org.id, - key: org.id, - accounts: org.accounts, // todo: these are ending up in the html as attributes.. - workspaces: org.accounts.flatMap(account => account.workspaces), - }) - - org.accounts.forEach(account => { - total.push({ - type: 'account', - className: 'workspaceSelector__accountName' + (account.label ? '' : ' u-display-none'), - label: account.label, - id: account.id, - key: account.id, - workspaces: account.workspaces, - }) - - account.workspaces.forEach(workspace => { - total.push({ - type: 'workspace', - className: - 'workspaceSelector__workspaceName' + - (workspace.isActive ? ' workspaceSelector__workspaceName--active' : ''), - label: workspace.label, - id: workspace.id, - key: workspace.id, - onClick: workspace.onClick, - }) - }) - }) - - return total - }, []) - } - - function onSearch(e: React.ChangeEvent): void { - const newSearchTerm = e.target.value.toLowerCase() - setSearchTerm(newSearchTerm) - - if (newSearchTerm) { - const filteredOrgs = getFilteredOrgs() - setCurrentFilteredOrgsDebounced(filteredOrgs) - } else { - // reset list immediately so it feels faster - setCurrentFilteredOrgs(props.orgs) - } - - function getFilteredOrgs(): INavigationOrg[] { - return props.orgs.reduce((total, org) => { - if (isHit(org)) { - total.push(org) - } else { - const workingOrg: INavigationOrg = { ...org } - workingOrg.accounts = [] - org.accounts.forEach(account => { - const workingAccount = { ...account } - workingAccount.workspaces = [] - - if (isHit(account)) { - workingOrg.accounts.push(account) - } else { - account.workspaces.forEach(workspace => { - if (isHit(workspace)) { - workingAccount.workspaces.push(workspace) - } - }) - if (workingAccount.workspaces.length) { - workingOrg.accounts.push(workingAccount) - } - } - }) - - if (workingOrg.accounts.length) total.push(workingOrg) - } - - return total - }, []) - - function isHit(item: INavigationOrg | INavigationAccount | INavigationWorkspace): boolean { - return ( - (!!item.label && item.label.toString().toLowerCase().includes(newSearchTerm)) || - (!!item.id && item.id.toString().toLowerCase().includes(newSearchTerm)) - ) - } - } - } - - function clearSearch(): void { - setSearchTerm('') - setCurrentFilteredOrgs(props.orgs) - } - - function createMenuChildren(): (MenuItemType | null)[] { - const searchInput: MenuItemType = { - key: 'search', - className: 'workspaceSelector__search', - label: , - } - - const signoutButton = useRef({ - key: 'signout', - className: 'workspaceSelector__signout', - label: , - }) - - const noResultsEl: MenuItemType = { - key: 'no-results', - className: 'workspaceSelector__noResults', - label: , - } - - const hasNoResults = !!searchTerm && !currentFilteredOrgs.length - - return [ - ...(hasNoResults ? [noResultsEl] : menuItems), - searchInput, - props.signoutOptions ? signoutButton.current : null, - ] - } -} \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceNoResults.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceNoResults.tsx new file mode 100644 index 000000000..471577180 --- /dev/null +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceNoResults.tsx @@ -0,0 +1,7 @@ +import { Center, Empty } from 'src/components' + +export const WorkspaceNoResults = () => ( +
+ +
+) diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector.tsx index 4a3b65723..727e1ad88 100644 --- a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector.tsx +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector.tsx @@ -1,150 +1,161 @@ import 'src/utils/utils.css' import './workspace-selector.css' -import { Avatar } from 'src/components' -import { Input } from 'src/components' -import { Menu } from 'src/components' -import { type IMenuProps } from 'src/components' -import { Center } from 'src/components' -import { Button } from 'src/components' -import { Empty } from 'src/components' -import { type INavigationOrg } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type IWorkspaceSelectorDisplayItem } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type INavigationAccount } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type INavigationWorkspace } from 'src/components/navigation/GlobalNavigation/WorkspaceSelectorItems' -import { type MenuItemType } from 'src/components/navigation/Menu/Menu' -import { useState } from 'react' +import { + Avatar, + type IAvatarProps, + type INavigationAccount, + type INavigationOrg, + type INavigationWorkspace, + type IWorkspaceSelectorDisplayItem, + Popover, +} from 'src/components' +import React, { type ChangeEvent, useRef, useState } from 'react' import { useCallback } from 'react' import { useEffect } from 'react' import { useMemo } from 'react' -import { useRef } from 'react' -import { debounce } from 'src/utils/utils' +import { debounce, hasImageAtSrc } from 'src/utils/utils' import { getInitials } from 'src/utils/utils' +// TODO: Need to make our Input component comply with forwardRef to be able to import it from src/components +// As soon as https://github.com/mParticle/aquarium/pull/123 is merged +import { type InputRef } from 'antd' +import { WorkspaceSelectorContent } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContent' +import { useMount } from 'src/hooks/useMount' + export interface IWorkspaceSelectorProps { orgs: INavigationOrg[] + avatarOptions?: IAvatarProps signoutOptions?: { label?: string onSignout: () => void } } -const WorkspaceSearchLabel = () => ( - -
- -
-) -const WorkspaceSignoutLabel = ({ signoutOptions }: { signoutOptions: IWorkspaceSelectorProps['signoutOptions'] }) => ( - -) - -const WorkspaceInputLabel = ({ - onSearch, - searchTerm, -}: { - onSearch: (e: React.ChangeEvent) => void - searchTerm: string -}) => ( - <> - { - e.preventDefault() - e.stopPropagation() - }} - /> - -) +function moveToTheTop(array: T[], index: number): T[] { + return [array[index], ...array.slice(0, index), ...array.slice(index + 1)] +} + +function sortOrgsByActiveWorkspace(orgs: INavigationOrg[]): INavigationOrg[] { + const activeOrgIndex = orgs.findIndex(org => + org.accounts.find(account => account.workspaces.find(workspace => workspace.isActive)), + ) + + if (activeOrgIndex >= 0) { + const activeOrg = orgs[activeOrgIndex] + const activeAccountIndex = activeOrg.accounts.findIndex(account => + account.workspaces.find(workspace => workspace.isActive), + ) + if (activeAccountIndex >= 0) { + const activeAccount = activeOrg.accounts[activeAccountIndex] + activeOrg.accounts = moveToTheTop(activeOrg.accounts, activeAccountIndex) + + const activeWorkspaceIndex = activeAccount.workspaces.findIndex(workspace => workspace.isActive) + activeAccount.workspaces = moveToTheTop(activeAccount.workspaces, activeWorkspaceIndex) + + return moveToTheTop(orgs, activeOrgIndex) + } + } + + return orgs +} export function WorkspaceSelector(props: IWorkspaceSelectorProps) { const [searchTerm, setSearchTerm] = useState('') + const inputRef = useRef(null) - const [currentFilteredOrgs, setCurrentFilteredOrgs] = useState(props.orgs) - useEffect(() => { - // since we are setting state from props, when the props change be sure to update the state - setCurrentFilteredOrgs(props.orgs) - }, props.orgs) + const sortedOrgs = useMemo(() => { + return sortOrgsByActiveWorkspace(props.orgs) + }, [props.orgs]) - const setCurrentFilteredOrgsDebounced = useCallback(debounce(setCurrentFilteredOrgs, 200), []) + const [currentFilteredOrgs, setCurrentFilteredOrgs] = useState(sortedOrgs) - const menuItems: IWorkspaceSelectorDisplayItem[] = useMemo( - () => generateDisplayItems(/* currentFilteredOrgs */), - currentFilteredOrgs, - ) + const [hasImage, setHasImage] = useState(false) - const searchInput: MenuItemType = { - key: 'search', - className: 'workspaceSelector__search', - label: , - } + useEffect(() => { + // since we are setting state from props, when the props change be sure to update the state + setCurrentFilteredOrgs(sortedOrgs) + }, [sortedOrgs]) - const signoutButton = useRef({ - key: 'signout', - className: 'workspaceSelector__signout', - label: , + useMount(() => { + const avatarImageSrc = props.avatarOptions?.src ?? props.avatarOptions?.srcSet + if (typeof avatarImageSrc === 'string') { + void hasImageAtSrc(avatarImageSrc, setHasImage) + } }) - const noResultsEl: MenuItemType = { - key: 'no-results', - className: 'workspaceSelector__noResults', - label: , - } + const setCurrentFilteredOrgsDebounced = useCallback(debounce(setCurrentFilteredOrgs, 200), []) const hasNoResults = !!searchTerm && !currentFilteredOrgs.length - const menuChildren = [ - ...(hasNoResults ? [noResultsEl] : menuItems), - searchInput, - props.signoutOptions ? signoutButton.current : null, - ] - - // todo: this probably doesnt need to be calculated on every render - const activeWorkspace: INavigationWorkspace = props.orgs - .flatMap(org => { - let flattenedSelectors: INavigationWorkspace[] = [] - - const { accounts } = org - if (accounts) { - const workspaces = accounts.flatMap(({ workspaces }) => workspaces) - flattenedSelectors = flattenedSelectors.concat(workspaces) - } + const menuItems: IWorkspaceSelectorDisplayItem[] = useMemo( + () => generateDisplayItems(/* currentFilteredOrgs */), + [currentFilteredOrgs], + ) - return flattenedSelectors - }) - .find(workspaceCandidate => (workspaceCandidate as INavigationWorkspace).isActive) as INavigationWorkspace + const activeWorkspace = useMemo(() => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return sortedOrgs + .flatMap(org => { + let flattenedSelectors: INavigationWorkspace[] = [] - const items: IMenuProps['items'] = [ - { - key: 'WorkspaceSelector', - icon: {getInitials(activeWorkspace?.label)}, - popupClassName: 'workspaceSelector', - children: menuChildren, - }, - ] + const { accounts } = org + if (accounts) { + const workspaces = accounts.flatMap(({ workspaces }) => workspaces) + flattenedSelectors = flattenedSelectors.concat(workspaces) + } + return flattenedSelectors + }) + .find(workspaceCandidate => workspaceCandidate.isActive)! + }, [sortedOrgs]) + + const workspaceInitials = getInitials(activeWorkspace?.label) + + // This seems to be the only way of consistently focusing the input on the first open + // We should find a better way to do this and not rely on setTimout + const focusOnInput = (open: boolean) => { + if (open) { + setTimeout(() => { + inputRef.current?.focus({ + cursor: 'all', + }) + }, 0) + } + } return ( - + + } + > +
+ + {getInitialsIfNoImage(hasImage, workspaceInitials)} + +
+
) + function getInitialsIfNoImage(hasImage: boolean, initials: string): string { + return hasImage ? '' : initials + } + function generateDisplayItems(): IWorkspaceSelectorDisplayItem[] { return currentFilteredOrgs.reduce((total, org) => { total.push({ @@ -152,8 +163,8 @@ export function WorkspaceSelector(props: IWorkspaceSelectorProps) { className: 'workspaceSelector__orgName' + (org.label ? '' : ' u-display-none'), label: org.label, id: org.id, - key: org.id, - accounts: org.accounts, // todo: these are ending up in the html as attributes.. + key: `${org.id}_${org.label}`, + accounts: org.accounts, workspaces: org.accounts.flatMap(account => account.workspaces), }) @@ -163,7 +174,7 @@ export function WorkspaceSelector(props: IWorkspaceSelectorProps) { className: 'workspaceSelector__accountName' + (account.label ? '' : ' u-display-none'), label: account.label, id: account.id, - key: account.id, + key: `${account.id}_${account.label}`, workspaces: account.workspaces, }) @@ -175,8 +186,9 @@ export function WorkspaceSelector(props: IWorkspaceSelectorProps) { (workspace.isActive ? ' workspaceSelector__workspaceName--active' : ''), label: workspace.label, id: workspace.id, - key: workspace.id, + key: `${workspace.id}_${workspace.label}`, onClick: workspace.onClick, + isActive: workspace.isActive, }) }) }) @@ -185,7 +197,7 @@ export function WorkspaceSelector(props: IWorkspaceSelectorProps) { }, []) } - function onSearch(e: React.ChangeEvent): void { + function onSearch(e: ChangeEvent): void { const newSearchTerm = e.target.value.toLowerCase() setSearchTerm(newSearchTerm) @@ -194,11 +206,11 @@ export function WorkspaceSelector(props: IWorkspaceSelectorProps) { setCurrentFilteredOrgsDebounced(filteredOrgs) } else { // reset list immediately so it feels faster - setCurrentFilteredOrgs(props.orgs) + setCurrentFilteredOrgs(sortedOrgs) } function getFilteredOrgs(): INavigationOrg[] { - return props.orgs.reduce((total, org) => { + return sortedOrgs.reduce((total, org) => { if (isHit(org)) { total.push(org) } else { @@ -236,9 +248,4 @@ export function WorkspaceSelector(props: IWorkspaceSelectorProps) { } } } - - function clearSearch(): void { - setSearchTerm('') - setCurrentFilteredOrgs(props.orgs) - } -} \ No newline at end of file +} diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContent.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContent.tsx new file mode 100644 index 000000000..649519fe8 --- /dev/null +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContent.tsx @@ -0,0 +1,42 @@ +import { type ChangeEvent, type RefObject } from 'react' +import { Input, type InputRef } from 'antd' +import type { IWorkspaceSelectorProps } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector' +import type { IWorkspaceSelectorDisplayItem } from 'src/components' +import { WorkspaceSelectorContentItems } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContentItems' +import { WorkspaceNoResults } from "src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceNoResults"; +import { WorkspaceSignout } from "src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSignout"; + +type WorkspaceSelectorContentProps = { + onSearch: (e: ChangeEvent) => void + searchTerm: string + inputRef: RefObject + hasNoResults: boolean + menuItems: IWorkspaceSelectorDisplayItem[] + signoutOptions?: IWorkspaceSelectorProps['signoutOptions'] +} + +export function WorkspaceSelectorContent(props: WorkspaceSelectorContentProps) { + const { onSearch, searchTerm, inputRef, hasNoResults, menuItems, signoutOptions } = props + + return ( +
+
+ { + e.preventDefault() + e.stopPropagation() + }} + /> +
+ + {hasNoResults ? : } + + +
+ ) +} \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContentItems.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContentItems.tsx new file mode 100644 index 000000000..d3edde178 --- /dev/null +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorContentItems.tsx @@ -0,0 +1,16 @@ +import { type IWorkspaceSelectorDisplayItem } from 'src/components' + +type WorkspaceSelectorContentItemsProps = { + menuItems: IWorkspaceSelectorDisplayItem[] +} +export function WorkspaceSelectorContentItems({ menuItems }: WorkspaceSelectorContentItemsProps) { + return ( +
    + {menuItems.map(item => ( +
  • + {item.label} +
  • + ))} +
+ ) +} diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems.d.ts b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems.d.ts index d296d6f5e..45269146c 100644 --- a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems.d.ts +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems.d.ts @@ -1,5 +1,4 @@ import { type MenuItemType } from 'src/components/navigation/Menu/Menu' -import { type MenuInfo as RCMenuInfo } from 'rc-menu/lib/interface' interface IWorkspaceSelectorItem { label: string @@ -7,18 +6,18 @@ interface IWorkspaceSelectorItem { } export interface INavigationOrg extends IWorkspaceSelectorItem { - accounts: INavigationAccount[]; - onClick?: (info: IMenuInfo) => void; + accounts: INavigationAccount[] + onClick?: () => void } export interface INavigationAccount extends IWorkspaceSelectorItem { - workspaces: INavigationWorkspace[]; - onClick?: (info: IMenuInfo) => void; + workspaces: INavigationWorkspace[] + onClick?: () => void } export interface INavigationWorkspace extends IWorkspaceSelectorItem { isActive: boolean - onClick?: (info: IMenuInfo) => void + onClick?: () => void } export interface IWorkspaceSelectorDisplayItem extends MenuItemType { @@ -29,8 +28,5 @@ export interface IWorkspaceSelectorDisplayItem extends MenuItemType { accounts?: INavigationAccount[] workspaces?: INavigationWorkspace[] + isActive?: boolean } - -export interface IMenuInfo extends RCMenuInfo { - -} \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSignout.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSignout.tsx new file mode 100644 index 000000000..cc06b4f22 --- /dev/null +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSignout.tsx @@ -0,0 +1,16 @@ +import { Button } from 'src/components' +import { type IWorkspaceSelectorProps } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelector' + +export const WorkspaceSignout = ({ signoutOptions }: { signoutOptions: IWorkspaceSelectorProps['signoutOptions'] }) => ( +
+ +
+) diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelector/workspace-selector.css b/src/components/navigation/GlobalNavigation/WorkspaceSelector/workspace-selector.css index 5b2e9cad4..183cda3fa 100644 --- a/src/components/navigation/GlobalNavigation/WorkspaceSelector/workspace-selector.css +++ b/src/components/navigation/GlobalNavigation/WorkspaceSelector/workspace-selector.css @@ -1,91 +1,122 @@ -.workspaceSelector .ant-menu { - max-height: 500px !important; +:root { + --workspace-selector-height: 400px; + --workspace-selector-search-height: 36px; + --workspace-selector-signout-height: 40px; + --workspace-selector-items-height: calc( + var(--workspace-selector-height) - var(--workspace-selector-search-height) - + var(--workspace-selector-signout-height) + ); } - .workspaceSelector__search { - position: sticky !important; - bottom: 40px; - z-index: 1; - - width: 100% !important; - padding: 0 var(--padding-xxs) !important; - margin: 0 !important; - - background-color: white !important; + position: sticky !important; + bottom: var(--workspace-selector-search-height); + z-index: 1; + width: 100% !important; + background-color: white !important; + margin-bottom: var(--margin-xxs); } .workspaceSelector__noResults { - height: 100% !important; - width: 180px !important; - pointer-events: none; + height: var(--workspace-selector-items-height); + pointer-events: none; } -.workspaceSelector__noResults .ant-menu-title-content { - height: 100% !important; +.workspaceSelector__noResults .ant-result-title { + font-size: var(--font-size); } -.workspaceSelector__noResults .ant-result-title { - font-size: var(--font-size); +.workspaceSelector__menuItem { + display: flex; + justify-content: center; + align-items: center; } .workspaceSelector__avatar { - color: white !important; + color: white !important; +} + +.workspaceSelector__popover { + padding: var(--padding-xxs) !important; +} + +.workspaceSelector__popoverContent { + height: var(--workspace-selector-height); + width: 200px; +} + +.workspaceSelector__itemsList { + list-style: none; + padding-left: 0; + margin-left: 0; + margin-block-start: 0; + overflow: auto; + height: var(--workspace-selector-items-height); + margin-bottom: var(--margin-xxs); } .workspaceSelector__orgName { - color: var(--color-primary); - pointer-events: none; - font-weight: 500; - padding: var(--padding-xxs) var(--control-padding-horizontal) !important; + color: var(--color-primary); + pointer-events: none; + padding: var(--padding-xs) var(--padding) 0; + font-weight: var(--font-weight-strong); } -.workspaceSelector__orgName:not(:nth-child(2)) { - padding-left: var(--padding-xs); - padding-right: var(--padding-xs); - border-top: 1px solid var(--color-border-secondary); +.workspaceSelector__orgName:not(:first-child) { + border-top: 1px solid var(--color-border-secondary); } .workspaceSelector__accountName { - height: var(--control-height); - padding: 0 var(--control-padding-horizontal) !important; - pointer-events: none; + pointer-events: none; + padding: var(--padding-xs) var(--padding-xs) var(--padding-xs) var(--padding); } .workspaceSelector__workspaceName { - padding-left: calc(var(--padding-sm) + var(--padding)) !important; + padding-top: var(--padding-xs); + padding-bottom: var(--padding-xs); + cursor: pointer; + padding-left: calc(var(--padding-sm) + var(--padding)) !important; } -.workspaceSelector__workspaceName.workspaceSelector__workspaceName--active { - border-radius: 4px; - background: var(--control-item-bg-active) !important; +.workspaceSelector__workspaceName:hover { + background-color: var(--color-bg-text-hover); } +.workspaceSelector__workspaceName.workspaceSelector__workspaceName--active { + border-radius: var(--border-radius-sm); + background: var(--control-item-bg-active) !important; +} .workspaceSelector__orgName, .workspaceSelector__accountName { - pointer-events: none; /* only workspaces are clickable */ + pointer-events: none; /* only workspaces are clickable */ } .workspaceSelector__orgName, .workspaceSelector__accountName, .workspaceSelector__workspaceName { - margin-top: 0 !important; - margin-bottom: 0 !important; + margin-top: 0 !important; + margin-bottom: 0 !important; } .workspaceSelector__signout { - position: sticky !important; - bottom: 0; - - width: 100% !important; - padding: 0 var(--padding-xxs) !important; - margin: 0 !important; + position: sticky !important; + bottom: 0; + width: 100% !important; + padding: 0 var(--padding-xxs) !important; + margin: 0 !important; + background-color: white !important; + height: var(--workspace-selector-signout-height); +} - background-color: white !important; +.workspaceSelector__signoutButtonContainer { + width: calc(100% - var(--padding-xs)); + position: absolute; + bottom: 0; + left: 0; + padding: var(--padding-xxs); } .workspaceSelector__signoutButton { - padding: 0 !important; - width: 100% !important; -} \ No newline at end of file + width: 100%; +} diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSelectorItems.d.ts b/src/components/navigation/GlobalNavigation/WorkspaceSelectorItems.d.ts deleted file mode 100644 index c7bb2155f..000000000 --- a/src/components/navigation/GlobalNavigation/WorkspaceSelectorItems.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { type MenuItemType } from 'src/components/navigation/Menu/Menu' - -interface IWorkspaceSelectorItem { - label: string - id: string -} - -export interface INavigationOrg extends IWorkspaceSelectorItem { - accounts: INavigationAccount[]; -} - -export interface INavigationAccount extends IWorkspaceSelectorItem { - workspaces: INavigationWorkspace[]; -} - -export interface INavigationWorkspace extends IWorkspaceSelectorItem { - isActive: boolean - onClick?: (info: IMenuInfo) => void -} - -export interface IWorkspaceSelectorDisplayItem extends MenuItemType { - type: 'org' | 'account' | 'workspace' - className: string - label: string - id: string - - accounts?: INavigationAccount[] - workspaces?: INavigationWorkspace[] -} \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/WorkspaceSignoutLabel.tsx b/src/components/navigation/GlobalNavigation/WorkspaceSignoutLabel.tsx deleted file mode 100644 index a330bc9fc..000000000 --- a/src/components/navigation/GlobalNavigation/WorkspaceSignoutLabel.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Button } from "src/components"; -import { IWorkspaceSelectorProps } from "src/components/navigation/GlobalNavigation/WorkspaceSelector"; - -export const WorkspaceSignoutLabel = ({ - signoutOptions, - }: { - signoutOptions: IWorkspaceSelectorProps["signoutOptions"] -}) => ( - -); \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/global-navigation.css b/src/components/navigation/GlobalNavigation/global-navigation.css index 4ab6fdcd4..36cdd605c 100644 --- a/src/components/navigation/GlobalNavigation/global-navigation.css +++ b/src/components/navigation/GlobalNavigation/global-navigation.css @@ -1,286 +1,282 @@ :root { - --nav-item-height: 56px; - --nav-item-width: 82px; - --nav-width: 90px; - --suite-logo-height: 82px; + --nav-item-height: 56px; + --nav-item-width: 82px; + --nav-width: 90px; + --suite-logo-height: 82px; } .globalNavigation { - width: var(--nav-width); - min-height: 100%; - background-color: white !important; - border-right: 1px solid var(--color-border-secondary); - box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.02), 0px 1px 6px -1px rgba(0, 0, 0, 0.02), 0px 1px 2px 0px rgba(0, 0, 0, 0.03); - - /* allow vertical scroll */ - position: absolute; - top: 0; - bottom: 0; - overflow: hidden auto; + width: var(--nav-width); + min-height: 100%; + background-color: white !important; + border-right: 1px solid var(--color-border-secondary); + box-shadow: + 0 2px 4px 0 rgb(0 0 0 / 2%), + 0 1px 6px -1px rgb(0 0 0 / 2%), + 0 1px 2px 0 rgb(0 0 0 / 3%); + + /* allow vertical scroll */ + position: absolute; + top: 0; + bottom: 0; + overflow: hidden auto; } .globalNavigation__sider { - min-height: 100%; - background-color: white !important; + min-height: 100%; + background-color: white !important; } .globalNavigation__item { - height: var(--nav-item-height) !important; - width: var(--nav-width); - - margin: 0; - padding: 0; - gap: var(--margin-xxs); - - border-radius: 0 !important; - cursor: pointer; - - transition: none !important; + height: var(--nav-item-height) !important; + width: var(--nav-width); + margin: 0; + padding: 0; + gap: var(--margin-xxs); + border-radius: 0 !important; + border-left: solid 3px transparent; + border-right: solid 3px transparent; + cursor: pointer; + transition: none !important; } .globalNavigation__item:hover { - background-color: var(--control-item-bg-hover) !important; + background-color: var(--control-item-bg-hover) !important; } .globalNavigation__item:focus, .globalNavigation__item:active { - background-color: var(--control-item-bg-active); + background-color: var(--control-item-bg-active); } - .globalNavigation__item .ant-menu-submenu-title { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; - - height: var(--nav-item-height) !important; - padding: 0 !important; - margin: 0 !important; - - background-color: transparent !important; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: var(--nav-item-height) !important; + padding: 0 !important; + margin: 0 !important; + background-color: transparent !important; } .globalNavigation__item .ant-menu-title-content { - text-wrap: normal; - margin-inline-start: 0 !important; - opacity: 1 !important; + text-wrap: normal; + margin-inline-start: 0 !important; + opacity: 1 !important; } .globalNavigation__item.globalNavigation__item--workspaceSelector:hover { - background-color: initial; + background-color: initial; } .globalNavigation__item.globalNavigation__item--createNew { - border: none !important; + border: none !important; } .globalNavigation__item.globalNavigation__item--createNew:hover { - background-color: initial !important; + background-color: initial !important; } .globalNavigation__item.globalNavigation__item--createNew .ant-menu-item-icon { - pointer-events: initial !important; + pointer-events: initial !important; } .globalNavigation__item.globalNavigation__item--createNew .ant-button:hover { - border-color: var(--color-primary-hover) !important; + border-color: var(--color-primary-hover) !important; } .globalNavigation__item.globalNavigation__item--active { - border-left: solid 3px var(--color-primary); - background-color: var(--color-bg-text-hover); + border-left-color: var(--color-primary); + background-color: var(--color-bg-text-hover); } - .globalNavigation__search { - width: 100%; + width: 100%; } .globalNavigation__searchButtonWrapper, .navigationCreate__popupButtonWrapper { - height: var(--nav-item-height); + height: var(--nav-item-height); } .globalNavigation__searchButton, .navigationCreate__popupButton { - box-shadow: 0 2px 0 0 rgba(54, 0, 209, 0.10); + box-shadow: 0 2px 0 0 rgb(54 0 209 / 10%); } .navigationCreate__popupIcon, .globalNavigation__searchIcon { - width: var(--size-lg) !important; - height: var(--size-lg) !important; + width: var(--size-lg) !important; + height: var(--size-lg) !important; } .navigationCreate__lockIcon { - padding-left: var(--padding-xs); - width: var(--size-sm) !important; - height: var(--size-sm) !important; + margin-left: var(--padding-xs); + width: var(--size-sm) !important; + height: var(--size-sm) !important; } .globalNavigation__searchButton { - padding-inline: var(--padding-xs) var(--padding-xs) !important; + padding-inline: var(--padding-xs) var(--padding-xs) !important; } - .globalNavigation__popup .ant-menu-item-group-title { - margin: 0 var(--margin-xxs) !important; - padding: var(--padding-xs) var(--padding) 0 !important; - - user-select: none; - color: var(--color-primary-text) !important; - font-size: 12px !important; - font-weight: 500; - line-height: 20px; + margin: 0 var(--margin-xxs) !important; + padding: var(--padding-xs) var(--padding) 0 !important; + user-select: none; + color: var(--color-primary-text) !important; + font-size: 12px !important; + font-weight: 500; + line-height: 20px; } .globalNavigation__popup.globalNavigation__popup--navigationCreate { - width: 290px !important; + width: 290px !important; } .globalNavigation__popup.globalNavigation__popup--navigationCreate .ant-menu-item-group-title { - border-top: 1px solid var(--color-border-secondary); - color: var(--color-primary-text) !important; + border-top: 1px solid var(--color-border-secondary); + color: var(--color-primary-text) !important; } - .navigationCreate__item { - height: 100% !important; - min-height: 100% !important; + height: 100% !important; + min-height: 100% !important; + padding: var(--padding-xxs) 0; } .navigationCreate__item .ant-flex { - gap: 0; + gap: 0; +} + +.navigationCreate__item.navigationCreate__item--disabled { + cursor: default !important; +} + +.navigationCreate__item.navigationCreate__item--disabled:hover { + background-color: initial !important; } .navigationCreate__item.navigationCreate__item--disabled .navigationCreate__itemTitle, .navigationCreate__item.navigationCreate__item--disabled .navigationCreate__itemDescription { - color: var(--color-text-disabled) !important; + color: var(--color-text-disabled) !important; } - .navigationCreate__itemTitle { - color: var(--color-text-heading); - font-size: 14px; - font-weight: 500; - line-height: 22px; + color: var(--color-text-heading); + font-size: 14px; + font-weight: 400; + line-height: 22px; } .navigationCreate__itemDescription { - color: var(--color-text-description); - font-size: 12px; - line-height: 20px; - white-space: normal !important; + color: var(--color-text-description); + font-size: 12px; + line-height: 20px; + white-space: normal !important; + padding: var(--padding-xs) 0; } .navigationCreate__itemLoading, .navigationCreate__itemLock { - padding-left: var(--padding-sm); + padding-left: var(--padding-sm); } .navigationCreate__itemLock { - width: var(--size-sm); - height: var(--size-sm); + width: var(--size-sm); + height: var(--size-sm); } .globalNavigation__menu { - height: var(--nav-item-height) !important; - width: 100%; - - border-inline-end: initial !important; + height: var(--nav-item-height) !important; + width: 100%; + border-inline-end: initial !important; } .globalNavigation__menu .globalNavigation__icon { - height: 100%; - width: 20px; + height: 100%; + width: 20px; } .globalNavigation__icon.globalNavigation__icon--suiteLogo { - padding-bottom: var(--padding-xxs); + padding-bottom: var(--padding-xxs); } .globalNavigation__icon.globalNavigation__icon--suiteLogo svg { - width: 20px; - height: 20px; + width: 20px; + height: 20px; } .globalNavigation__menu .globalNavigation__iconLabel { - margin-top: var(--margin-xxs); + margin-top: var(--margin-xxs); } .globalNavigation__iconLabel { - color: var(--color-text); - font-size: 10px; + color: var(--color-text); + font-size: 10px; } - .globalNavigation__badge { - border: solid 1px var(--color-border); - border-radius: var(--border-radius-sm); - padding: 1px var(--padding-content-vertical-sm); - box-shadow: none !important; + border: solid 1px var(--color-border); + border-radius: var(--border-radius-sm); + padding: 1px var(--padding-content-vertical-sm); + box-shadow: none !important; } .globalNavigation__badge .ant-badge-count { - color: var(--color-text) !important; - background: transparent !important; - box-shadow: none !important; + color: var(--color-text) !important; + background: transparent !important; + box-shadow: none !important; } - .ant-badge-color-red { - color: var(--color-error) !important; - background: var(--color-error) !important; + color: var(--color-error) !important; + background: var(--color-error) !important; } .ant-menu-item-selected { - background-color: revert !important; - color: revert !important; + background-color: revert !important; + color: revert !important; } - .globalNavigation__headerItem { - width: var(--control-height-lg); - height: var(--control-height-lg) !important; - padding: 0 var(--padding-sm); - - border-radius: var(--border-radius-lg); - border: 1px solid var(--color-border, #c3aeff); + width: var(--control-height-lg); + height: var(--control-height-lg) !important; + padding: 0 var(--padding-sm); + border-radius: var(--border-radius-lg); + border: 1px solid var(--color-border, #c3aeff); } - .globalNavigation__suiteLogo { - min-height: var(--suite-logo-height); - min-width: var(--nav-width); - padding-top: var(--padding-lg); - color: black; - font-size: var(--font-size-sm); - font-weight: 400; - cursor: default; + min-height: var(--suite-logo-height); + min-width: var(--nav-width); + padding: var(--padding-md) 0; + color: black; + font-size: var(--font-size-sm); + font-weight: 400; + cursor: pointer; } .globalNavigation__divider { - border-bottom: 1px solid var(--color-border-secondary); - width: 80%; - margin-top: var(--margin-md); - margin-bottom: var(--margin-md); + border-bottom: 1px solid var(--color-border-secondary); + margin-right: var(--margin-sm); + margin-left: var(--margin-sm); + margin-bottom: var(--margin-md); } - .globalNavigation__mpHome { - padding: var(--padding-lg, 20px); /* TODO: dependency between padding-lg/md and 20 from figma... */ - margin-top: var(--margin-xs); - width: var(--nav-width); - height: var(--nav-item-height); - background-color: black; - - color: white; - cursor: pointer; + padding: var(--padding-lg, 20px); /* TODO: dependency between padding-lg/md and 20 from figma... */ + margin-top: var(--margin-xs); + width: var(--nav-width); + height: var(--nav-item-height); + background-color: black; + color: white; + cursor: pointer; } .globalNavigation__mpSvg { - width: 28px; - height: var(--size-lg); + width: 28px; + height: var(--size-lg); } \ No newline at end of file diff --git a/src/components/navigation/GlobalNavigation/stories-utils.ts b/src/components/navigation/GlobalNavigation/stories-utils.ts new file mode 100644 index 000000000..1bea5391a --- /dev/null +++ b/src/components/navigation/GlobalNavigation/stories-utils.ts @@ -0,0 +1,38 @@ +import { type INavigationAccount, type INavigationOrg } from 'src/components' + +export function generateOrgs(orgs: number, accounts: number, workspaces: number): INavigationOrg[] { + const finalOrgs: INavigationOrg[] = [] + + for (let i = 0; i < orgs; i += 1) { + const newOrg: INavigationOrg = { + id: `org-${i}`, + label: `Org ${i}`, + accounts: [], + } + + for (let j = 0; j < accounts; j += 1) { + const newAccount: INavigationAccount = { + id: `account-${i}-${j}`, + label: `Account ${i}-${j}`, + workspaces: [], + } + + newOrg.accounts.push(newAccount) + + for (let k = 0; k < workspaces; k += 1) { + newAccount.workspaces.push({ + id: `workspace-${i}-${j}-${k}`, + label: `Workspace ${i}-${j}-${k}`, + isActive: i === 0 && j === 0 && k === 0, + onClick: () => { + alert(`Selected Workspace ${i}-${j}-${k}`) + }, + }) + } + } + + finalOrgs.push(newOrg) + } + + return finalOrgs +} diff --git a/src/styles/_variables.css b/src/styles/_variables.css index 4f6505a35..246976859 100644 --- a/src/styles/_variables.css +++ b/src/styles/_variables.css @@ -35,7 +35,7 @@ --motion-ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); --motion-ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); --motion-ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); - --border-radius: 6px; + --border-radius: 8px; --size-unit: 4px; --size-step: 4px; --size-popup-arrow: 16px; @@ -47,6 +47,8 @@ --motion: true; --color-link-hover: #ab8eff; --control-outline: rgba(0.21176470816135406, 0, 0.8196078538894653, 0.10000000149011612); + --color-warning-outline: #fffbe6; + --color-error-outline: #fff1f0; --control-item-bg-hover: #f8f6fb; --control-item-bg-active: #ebe8f8; --control-item-bg-active-hover: #c3aeff; @@ -63,7 +65,34 @@ --color-border: #c3aeff; --color-border-secondary: #eceae9; --color-split: #eceae9; + --color-primary-bg: #f8f6fb; + --color-primary-bg-hover: #ebe8f8; + --color-primary-border: #c3aeff; + --color-primary-border-hover: #ab8eff; + --color-primary-hover: #ab8eff; + --color-primary-active: #8255ff; + --color-primary-text-hover: #5f29f8; + --color-primary-text: #2c00aa; + --color-primary-text-active: #20007a; + --color-success-hover: #73d13d; + --color-success-text-hover: #237804; + --color-success-text: #135200; + --color-success-text-active: #092b00; + --color-warning-hover: #ffc53d; + --color-warning-text-hover: #ad6800; + --color-warning-text: #874d00; + --color-warning-text-active: #613400; + --color-error-bg: #fff1f0; + --color-error-bg-hover: #ffccc7; + --color-error-border: #ffa39e; + --color-error-border-hover: #ff7875; + --color-error-hover: #ff4d4f; + --color-error-active: #cf1322; + --color-error-text-hover: #a8071a; + --color-error-text: #820014; + --color-error-text-active: #5c0011; --color-bg-mask: #babbb5; + --border-radius-lg: 16px; --mp-brand-primary-1: #f8f6fb; --mp-brand-primary-2: #ebe8f8; --mp-brand-primary-3: #dbceff; @@ -348,42 +377,16 @@ --color-bg-container: #ffffff; --color-bg-elevated: #ffffff; --color-bg-blur: transparent; - --color-primary-bg: #f1e6ff; - --color-primary-bg-hover: #c8a3ff; - --color-primary-border: #a677f7; - --color-primary-border-hover: #804beb; - --color-primary-hover: #5b23de; - --color-primary-active: #2800ab; - --color-primary-text-hover: #5b23de; - --color-primary-text: #3600d1; - --color-primary-text-active: #2800ab; --color-success-bg: #f6ffed; --color-success-bg-hover: #d9f7be; --color-success-border: #b7eb8f; --color-success-border-hover: #95de64; - --color-success-hover: #95de64; --color-success-active: #389e0d; - --color-success-text-hover: #73d13d; - --color-success-text: #52c41a; - --color-success-text-active: #389e0d; - --color-error-bg: #fff1f0; - --color-error-bg-hover: #ffccc7; - --color-error-border: #ffa39e; - --color-error-border-hover: #ff7875; - --color-error-hover: #ff4d4f; - --color-error-active: #cf1322; - --color-error-text-hover: #ff4d4f; - --color-error-text: #f5222d; - --color-error-text-active: #cf1322; --color-warning-bg: #fffbe6; --color-warning-bg-hover: #fff1b8; --color-warning-border: #ffe58f; --color-warning-border-hover: #ffd666; - --color-warning-hover: #ffd666; --color-warning-active: #d48806; - --color-warning-text-hover: #ffc53d; - --color-warning-text: #faad14; - --color-warning-text-active: #d48806; --color-info-bg: #e6f4ff; --color-info-bg-hover: #bae0ff; --color-info-border: #91caff; @@ -431,9 +434,8 @@ --motion-duration-slow: 0.3s; --line-width-bold: 2px; --border-radius-xs: 2px; - --border-radius-sm: 4px; - --border-radius-lg: 8px; - --border-radius-outer: 4px; + --border-radius-sm: 6px; + --border-radius-outer: 6px; --color-fill-content: #ebe8f8; --color-fill-content-hover: #dcdcd8; --color-fill-alter: #f8f6fb; @@ -450,8 +452,6 @@ --color-bg-text-active: #dcdcd8; --color-icon: #2c2d2b; --color-icon-hover: #0f0e0e; - --color-error-outline: rgba(255, 22, 5, 0.06); - --color-warning-outline: rgba(255, 215, 5, 0.1); --font-size-icon: 12px; --line-width-focus: 4px; --control-outline-width: 2px; diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts index b0438ed3a..f04ffde64 100644 --- a/src/utils/debounce.ts +++ b/src/utils/debounce.ts @@ -1,11 +1,11 @@ -export const debounce = (callback: (...args: any[]) => void, wait: number): ((...args: any[]) => void) => { +export const debounce = (callback: (...args: unknown[]) => void, wait: number): ((...args: unknown[]) => void) => { let timeoutId: number - return (...args: any[]) => { + return (...args: unknown[]) => { window.clearTimeout(timeoutId) timeoutId = window.setTimeout(() => { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument callback(...args) }, wait) } -} \ No newline at end of file +} diff --git a/src/utils/global.d.ts b/src/utils/global.d.ts index 3baa1ee54..b3d173f66 100644 --- a/src/utils/global.d.ts +++ b/src/utils/global.d.ts @@ -1,6 +1,7 @@ +// eslint-disable-next-line @typescript-eslint/triple-slash-reference /// -//for importing svg files... +// for importing svg files... declare module '*.svg' { const value: any export default value -} \ No newline at end of file +} diff --git a/src/utils/utils.spec.ts b/src/utils/utils.spec.ts index 2bf08ba16..936a13a91 100644 --- a/src/utils/utils.spec.ts +++ b/src/utils/utils.spec.ts @@ -1,21 +1,53 @@ -import { getInitials } from './utils' - -describe('Testing getInitials', () => { - it.each([ - ['Ren & Stimpy', 'RS'], - ['Ren & Stimpy-Wein', 'RS'], - ['Ren & Stimpy- Wein', 'RW'], - ['Ren & Stimpy - Wein', 'RW'], - ['R. N. Stimpy', 'RS'], - ['1Ren Stimpy', 'RS'], - ['Ren', 'R'], - ['* Ren & Stimpy', 'RS'], - ['234* Ren & Stimpy', 'RS'], - ])('it should take "%s" and return "%s"', (words, expectedInitials) => { - // act - const actualInitials = getInitials(words) - - // assert - expect(actualInitials).toBe(expectedInitials) +import { getInitials, getOS } from './utils' + +describe('Testing utils', () => { + describe('Testing getInitials', () => { + it.each([ + ['Ren & Stimpy', 'RS'], + ['Ren & Stimpy-Wein', 'RS'], + ['Ren & Stimpy- Wein', 'RW'], + ['Ren & Stimpy - Wein', 'RW'], + ['R. N. Stimpy', 'RS'], + ['1Ren Stimpy', 'RS'], + ['Ren', 'R'], + ['* Ren & Stimpy', 'RS'], + ['234* Ren & Stimpy', 'RS'], + ])('it should take "%s" and return "%s"', (words, expectedInitials) => { + // act + const actualInitials = getInitials(words) + + // assert + expect(actualInitials).toBe(expectedInitials) + }) + }) + + describe('Testing getOS', () => { + it('it should return "Windows" when the user agent includes "Win"', () => { + // arrange + Object.defineProperty(navigator, 'userAgent', { + value: 'Windows', + configurable: true, + }) + + // act + const actualOS = getOS() + + // assert + expect(actualOS).toBe('Windows') + }) + + it('it should return "Macintosh" when the user agent includes "Mac"', () => { + // arrange + Object.defineProperty(navigator, 'userAgent', { + value: 'Macintosh', + configurable: true, + }) + + // act + const actualOS = getOS() + + // assert + expect(actualOS).toBe('Macintosh') + }) }) -}) \ No newline at end of file +}) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index d21ecb218..4002aa358 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,13 +1,14 @@ export function getInitials(str: string = ''): string { const getInitialsRegex = new RegExp( - "(?:[\\W\\d]*\\b)*" + // Ignore non-word abd number characters that may exist at the beginning of the word - "([A-Za-z])\\w*\\b" + // Get the first alpha character of the first word - "(?:" + // Conditionally capture a second initial candidate - ".*" + // Ignore everything in between - "\\s(\\w)[\\w-]*$" + // Until the last word, where we include the first letter of a hyphenated word - ")?" // Ignore second candidate if missing it and capture a single initial - , "i"); - return str.replace(getInitialsRegex, "$1$2")?.toUpperCase(); + '(?:[\\W\\d]*\\b)*' + // Ignore non-word abd number characters that may exist at the beginning of the word + '([A-Za-z])\\w*\\b' + // Get the first alpha character of the first word + '(?:' + // Conditionally capture a second initial candidate + '.*' + // Ignore everything in between + '\\s(\\w)[\\w-]*$' + // Until the last word, where we include the first letter of a hyphenated word + ')?', // Ignore second candidate if missing it and capture a single initial + 'i', + ) + return str.replace(getInitialsRegex, '$1$2')?.toUpperCase() } export const debounce = (callback: (...args: any[]) => void, wait: number): ((...args: unknown[]) => void) => { @@ -19,4 +20,31 @@ export const debounce = (callback: (...args: any[]) => void, wait: number): ((.. callback(...args) }, wait) } -} \ No newline at end of file +} + +type OSNames = 'Windows' | 'Macintosh' | 'Linux' | 'Android' | 'iOS' | 'Unknown OS' + +export const getOS = (): OSNames => { + if (navigator.userAgent.includes('Win')) return 'Windows' + if (navigator.userAgent.includes('Mac')) return 'Macintosh' + if (navigator.userAgent.includes('Linux')) return 'Linux' + if (navigator.userAgent.includes('Android')) return 'Android' + if (navigator.userAgent.includes('like Mac')) return 'iOS' + + return 'Unknown OS' +} + +export function hasImageAtSrc(src: string, hasImageSetter?: (hasImage: boolean) => void): Promise { + return new Promise(resolve => { + const img = new Image() + img.onload = () => { + hasImageSetter?.(true) + resolve(true) + } + img.onerror = () => { + hasImageSetter?.(false) + resolve(false) + } + img.src = src + }) +}