Merge branch 'master' into canon-searchfield
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-graph': patch
|
||||
---
|
||||
|
||||
Catalog graph plugin support i18n
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/canon': patch
|
||||
---
|
||||
|
||||
We are consolidating all css files into a single styles.css in Canon.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/canon': patch
|
||||
---
|
||||
|
||||
Add new `RadioGroup` + `Radio` component to Canon
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/canon': patch
|
||||
---
|
||||
|
||||
Added placeholder prop to TextField component.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
---
|
||||
|
||||
Fixed bug with error message since ResponseError is now thrown from CatalogClient
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/integration-react': patch
|
||||
---
|
||||
|
||||
Separated gitlab `write_repository` and `api` scope to pass checks in `RefreshingAuthSessionManager`
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-defaults': patch
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Fixed bug where the GitLab user token and GitLab integration token were being merged together
|
||||
@@ -52,14 +52,14 @@ jobs:
|
||||
working-directory: ./example-app
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@next/mdx": "15.3.3",
|
||||
"@next/mdx": "15.3.4",
|
||||
"@storybook/react": "^8.6.8",
|
||||
"@uiw/codemirror-themes": "^4.23.7",
|
||||
"@uiw/react-codemirror": "^4.23.7",
|
||||
"html-react-parser": "^5.2.5",
|
||||
"motion": "^12.4.1",
|
||||
"next": "15.3.3",
|
||||
"next": "15.3.4",
|
||||
"next-mdx-remote-client": "^2.1.2",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
@@ -37,7 +37,7 @@
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.3.3",
|
||||
"eslint-config-next": "15.3.4",
|
||||
"lightningcss": "^1.28.2",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,10 +5,8 @@ const { bundle } = require('lightningcss');
|
||||
const source = '../../packages/canon/src/css';
|
||||
const destination = '../public';
|
||||
|
||||
const source1 = path.join(__dirname, `${source}/core.css`);
|
||||
const destination1 = path.join(__dirname, `${destination}/core.css`);
|
||||
const source2 = path.join(__dirname, `${source}/components.css`);
|
||||
const destination2 = path.join(__dirname, `${destination}/components.css`);
|
||||
const source1 = path.join(__dirname, `${source}/styles.css`);
|
||||
const destination1 = path.join(__dirname, `${destination}/styles.css`);
|
||||
|
||||
// Function to bundle and copy the CSS file
|
||||
const bundleAndCopyFile = async (source, destination) => {
|
||||
@@ -26,10 +24,7 @@ const bundleAndCopyFile = async (source, destination) => {
|
||||
};
|
||||
|
||||
// Initial bundle and copy
|
||||
Promise.all([
|
||||
bundleAndCopyFile(source1, destination1),
|
||||
bundleAndCopyFile(source2, destination2),
|
||||
])
|
||||
Promise.all([bundleAndCopyFile(source1, destination1)])
|
||||
.then(() => {
|
||||
// Add an empty line after all operations are complete - It looks better in the terminal :)
|
||||
console.log('');
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { RadioGroupSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
radioGroupPropDefs,
|
||||
radioGroupUsageSnippet,
|
||||
radioGroupDefaultSnippet,
|
||||
radioGroupDescriptionSnippet,
|
||||
radioGroupHorizontalSnippet,
|
||||
radioGroupDisabledSnippet,
|
||||
radioGroupDisabledSingleSnippet,
|
||||
radioGroupValidationSnippet,
|
||||
radioGroupReadOnlySnippet,
|
||||
} from './radio-group.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# RadioGroup
|
||||
|
||||
A radio group allows a user to select a single item from a list of mutually exclusive options.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<RadioGroupSnippet story="Default" />}
|
||||
code={radioGroupDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="radio-group"
|
||||
classNames={['canon-RadioGroup', 'canon-RadioGroupContent']}
|
||||
usageCode={radioGroupUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={radioGroupPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Horizontal
|
||||
|
||||
Here's a simple TextField with a description.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<RadioGroupSnippet story="Horizontal" />}
|
||||
code={radioGroupHorizontalSnippet}
|
||||
/>
|
||||
|
||||
### Disabled
|
||||
|
||||
You can disable the entire radio group by adding the `isDisabled` prop to the `RadioGroup` component.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<RadioGroupSnippet story="Disabled" />}
|
||||
code={radioGroupDisabledSnippet}
|
||||
/>
|
||||
|
||||
### Disabled Single radio
|
||||
|
||||
You can disable a single radio by adding the `isDisabled` prop to the `Radio` component.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<RadioGroupSnippet story="DisabledSingle" />}
|
||||
code={radioGroupDisabledSingleSnippet}
|
||||
/>
|
||||
|
||||
### Validation
|
||||
|
||||
Here's an example of a radio group with errors.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<RadioGroupSnippet story="Validation" />}
|
||||
code={radioGroupValidationSnippet}
|
||||
/>
|
||||
|
||||
### Read only
|
||||
|
||||
You can make the radio group read only by adding the `isReadOnly` prop to the `RadioGroup` component.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<RadioGroupSnippet story="ReadOnly" />}
|
||||
code={radioGroupReadOnlySnippet}
|
||||
/>
|
||||
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const radioGroupPropDefs: Record<string, PropDef> = {
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'small',
|
||||
responsive: true,
|
||||
},
|
||||
label: {
|
||||
type: 'string',
|
||||
},
|
||||
icon: {
|
||||
type: 'enum',
|
||||
values: ['ReactNode'],
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const radioGroupUsageSnippet = `import { RadioGroup } from '@backstage/canon';
|
||||
|
||||
<RadioGroup />`;
|
||||
|
||||
export const radioGroupDefaultSnippet = `<RadioGroup label="Label" />`;
|
||||
|
||||
export const radioGroupDescriptionSnippet = `<TextField label="Label" description="Description" placeholder="Enter a URL" />`;
|
||||
|
||||
export const radioGroupHorizontalSnippet = `<RadioGroup label="Label" orientation="horizontal" />`;
|
||||
|
||||
export const radioGroupDisabledSnippet = `<RadioGroup label="Label" isDisabled>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>`;
|
||||
|
||||
export const radioGroupDisabledSingleSnippet = `<RadioGroup label="Label">
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>`;
|
||||
|
||||
export const radioGroupValidationSnippet = `<RadioGroup validate: value => (value === \'charmander\' ? \'Nice try!\' : null)>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>`;
|
||||
|
||||
export const radioGroupReadOnlySnippet = `<RadioGroup label="Label" isReadOnly>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>`;
|
||||
@@ -18,6 +18,7 @@ import * as MenuStories from '../../../packages/canon/src/components/Menu/Menu.s
|
||||
import * as LinkStories from '../../../packages/canon/src/components/Link/Link.stories';
|
||||
import * as AvatarStories from '../../../packages/canon/src/components/Avatar/Avatar.stories';
|
||||
import * as CollapsibleStories from '../../../packages/canon/src/components/Collapsible/Collapsible.stories';
|
||||
import * as RadioGroupStories from '../../../packages/canon/src/components/RadioGroup/RadioGroup.stories';
|
||||
import * as TabsStories from '../../../packages/canon/src/components/Tabs/Tabs.stories';
|
||||
import * as SwitchStories from '../../../packages/canon/src/components/Switch/Switch.stories';
|
||||
|
||||
@@ -197,3 +198,14 @@ export const SwitchSnippet = ({
|
||||
|
||||
return StoryComponent ? <StoryComponent /> : null;
|
||||
};
|
||||
|
||||
export const RadioGroupSnippet = ({
|
||||
story,
|
||||
}: {
|
||||
story: keyof typeof RadioGroupStories;
|
||||
}) => {
|
||||
const stories = composeStories(RadioGroupStories);
|
||||
const StoryComponent = stories[story as keyof typeof stories];
|
||||
|
||||
return StoryComponent ? <StoryComponent /> : null;
|
||||
};
|
||||
|
||||
@@ -116,6 +116,11 @@ export const components: Page[] = [
|
||||
slug: 'menu',
|
||||
status: 'alpha',
|
||||
},
|
||||
{
|
||||
title: 'RadioGroup',
|
||||
slug: 'radio-group',
|
||||
status: 'alpha',
|
||||
},
|
||||
{
|
||||
title: 'Select',
|
||||
slug: 'select',
|
||||
|
||||
+57
-57
@@ -732,25 +732,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/env@npm:15.3.3"
|
||||
checksum: 10/f71fd8b397c60b80ee2ba836152d2c8bc772f4f840b976bfd82ca0c1452539b4832a1ce6702a90da1d4edb874383944ea2662add5c0729423cd4d1cb2e58fc3d
|
||||
"@next/env@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/env@npm:15.3.4"
|
||||
checksum: 10/40ea0bee2eca72dce6102d30ac50029309bf68a281585270e38f920ae47043f240352ad250058d462169a436dea3d8f78a935406ee61088bd4a614524b4a315b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/eslint-plugin-next@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/eslint-plugin-next@npm:15.3.3"
|
||||
"@next/eslint-plugin-next@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/eslint-plugin-next@npm:15.3.4"
|
||||
dependencies:
|
||||
fast-glob: "npm:3.3.1"
|
||||
checksum: 10/08b19a39fa01ac69c7b117a29ebdb193353a29cb3d51b2e3f72fabd7f2b014d08e37d819aed8e440a8a0a6e1acd9053dbf939b5f76603e6a87de0042fbf0bd4b
|
||||
checksum: 10/8a473bd32a06f62c16f60f9c40b7b8149cf91170ce4c1546cda57e9c85ac8481c7ad3aa4a77e8c3c7000e80d3de809d2db7df6cb79e13fd258fff382729abf60
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/mdx@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/mdx@npm:15.3.3"
|
||||
"@next/mdx@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/mdx@npm:15.3.4"
|
||||
dependencies:
|
||||
source-map: "npm:^0.7.0"
|
||||
peerDependencies:
|
||||
@@ -761,62 +761,62 @@ __metadata:
|
||||
optional: true
|
||||
"@mdx-js/react":
|
||||
optional: true
|
||||
checksum: 10/5583f01e986322bee6eae1052fce27964b33796b8fbd2ea360340a65ccf60cd348c614524bcbf8323be178cace1da5c74f45f8a111cf9e62682aad3a0a9d12e3
|
||||
checksum: 10/07904beda049317e43857f9dfe659adb6e57c4417475de1d21a7605f8ace5d9aa992a06465d1a94fe4b62331901765b15659555e8aadedbd410f86df1bebd1bd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-darwin-arm64@npm:15.3.3"
|
||||
"@next/swc-darwin-arm64@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-darwin-arm64@npm:15.3.4"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-darwin-x64@npm:15.3.3"
|
||||
"@next/swc-darwin-x64@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-darwin-x64@npm:15.3.4"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:15.3.3"
|
||||
"@next/swc-linux-arm64-gnu@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:15.3.4"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:15.3.3"
|
||||
"@next/swc-linux-arm64-musl@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:15.3.4"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:15.3.3"
|
||||
"@next/swc-linux-x64-gnu@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:15.3.4"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-linux-x64-musl@npm:15.3.3"
|
||||
"@next/swc-linux-x64-musl@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-linux-x64-musl@npm:15.3.4"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:15.3.3"
|
||||
"@next/swc-win32-arm64-msvc@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:15.3.4"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:15.3.3"
|
||||
"@next/swc-win32-x64-msvc@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:15.3.4"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@@ -1839,7 +1839,7 @@ __metadata:
|
||||
"@lezer/highlight": "npm:^1.2.1"
|
||||
"@mdx-js/loader": "npm:^3.1.0"
|
||||
"@mdx-js/react": "npm:^3.1.0"
|
||||
"@next/mdx": "npm:15.3.3"
|
||||
"@next/mdx": "npm:15.3.4"
|
||||
"@storybook/react": "npm:^8.6.8"
|
||||
"@types/mdx": "npm:^2.0.13"
|
||||
"@types/node": "npm:^20"
|
||||
@@ -1848,11 +1848,11 @@ __metadata:
|
||||
"@uiw/codemirror-themes": "npm:^4.23.7"
|
||||
"@uiw/react-codemirror": "npm:^4.23.7"
|
||||
eslint: "npm:^8"
|
||||
eslint-config-next: "npm:15.3.3"
|
||||
eslint-config-next: "npm:15.3.4"
|
||||
html-react-parser: "npm:^5.2.5"
|
||||
lightningcss: "npm:^1.28.2"
|
||||
motion: "npm:^12.4.1"
|
||||
next: "npm:15.3.3"
|
||||
next: "npm:15.3.4"
|
||||
next-mdx-remote-client: "npm:^2.1.2"
|
||||
react: "npm:19.1.0"
|
||||
react-dom: "npm:19.1.0"
|
||||
@@ -2505,11 +2505,11 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-config-next@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "eslint-config-next@npm:15.3.3"
|
||||
"eslint-config-next@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "eslint-config-next@npm:15.3.4"
|
||||
dependencies:
|
||||
"@next/eslint-plugin-next": "npm:15.3.3"
|
||||
"@next/eslint-plugin-next": "npm:15.3.4"
|
||||
"@rushstack/eslint-patch": "npm:^1.10.3"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
"@typescript-eslint/parser": "npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
@@ -2525,7 +2525,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: 10/63c51a9e4cc3f54073d15aff85b1088459439169721c379af1202df62c3a757c3849a194f46d4ec95a9c202322aa25d1ddab24159addcca290532a09afda3532
|
||||
checksum: 10/6c21254d3383b9158ff5f3b2881cc702bee3d2635b4326757965945691f6e65e25fdfef4f2964382fb4b2f52d9f03b929cb71d267709727df7365e7da80c8c3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4623,19 +4623,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "next@npm:15.3.3"
|
||||
"next@npm:15.3.4":
|
||||
version: 15.3.4
|
||||
resolution: "next@npm:15.3.4"
|
||||
dependencies:
|
||||
"@next/env": "npm:15.3.3"
|
||||
"@next/swc-darwin-arm64": "npm:15.3.3"
|
||||
"@next/swc-darwin-x64": "npm:15.3.3"
|
||||
"@next/swc-linux-arm64-gnu": "npm:15.3.3"
|
||||
"@next/swc-linux-arm64-musl": "npm:15.3.3"
|
||||
"@next/swc-linux-x64-gnu": "npm:15.3.3"
|
||||
"@next/swc-linux-x64-musl": "npm:15.3.3"
|
||||
"@next/swc-win32-arm64-msvc": "npm:15.3.3"
|
||||
"@next/swc-win32-x64-msvc": "npm:15.3.3"
|
||||
"@next/env": "npm:15.3.4"
|
||||
"@next/swc-darwin-arm64": "npm:15.3.4"
|
||||
"@next/swc-darwin-x64": "npm:15.3.4"
|
||||
"@next/swc-linux-arm64-gnu": "npm:15.3.4"
|
||||
"@next/swc-linux-arm64-musl": "npm:15.3.4"
|
||||
"@next/swc-linux-x64-gnu": "npm:15.3.4"
|
||||
"@next/swc-linux-x64-musl": "npm:15.3.4"
|
||||
"@next/swc-win32-arm64-msvc": "npm:15.3.4"
|
||||
"@next/swc-win32-x64-msvc": "npm:15.3.4"
|
||||
"@swc/counter": "npm:0.1.3"
|
||||
"@swc/helpers": "npm:0.5.15"
|
||||
busboy: "npm:1.6.0"
|
||||
@@ -4680,7 +4680,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: 10/287e3b24aade1763b13f95246d7df0e23d5fdde2d8c4b170360b22fabfa38184e102eb64886260e0034f4fc6979a1d47929e423d7946f5da57d306034645f6c7
|
||||
checksum: 10/bcc781ca5abba6a29408431f81b57598708871796fe4c70d1187cc92ca4905467a6a3cde32840cb7911099d54a93c1543c130e4dea2b59dbf9753f5850a8efdf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@yarnpkg/plugin-npm@npm:^3.1.0": "patch:@yarnpkg/plugin-npm@npm%3A3.1.0#~/.yarn/patches/@yarnpkg-plugin-npm-npm-3.1.0-6533d0f5a1.patch",
|
||||
"GendocuPublicApis": "npm:gendocu-public-apis@^1.0.0",
|
||||
"ast-types@0.14.2": "patch:ast-types@npm%3A0.14.2#./.yarn/patches/ast-types-npm-0.14.2-43c4ac4b0d.patch",
|
||||
"ast-types@^0.14.1": "patch:ast-types@npm%3A0.14.2#./.yarn/patches/ast-types-npm-0.14.2-43c4ac4b0d.patch",
|
||||
"csstype@npm:^3.0.2": "3.0.9",
|
||||
|
||||
@@ -340,10 +340,7 @@ export class GitlabUrlReader implements UrlReaderService {
|
||||
);
|
||||
}
|
||||
// Default to the old behavior of assuming the url is for a file
|
||||
return getGitLabFileFetchUrl(target, {
|
||||
...this.integration.config,
|
||||
...(token && { token }),
|
||||
});
|
||||
return getGitLabFileFetchUrl(target, this.integration.config, token);
|
||||
}
|
||||
|
||||
// convert urls of the form:
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
.canon-AvatarRoot {
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
color: var(--canon-fg-primary);
|
||||
background-color: var(--canon-bg-surface-2);
|
||||
border-radius: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
display: inline-flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.canon-AvatarRoot[data-size="small"] {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.canon-AvatarRoot[data-size="medium"] {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.canon-AvatarRoot[data-size="large"] {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.canon-AvatarImage {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.canon-AvatarFallback {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: var(--canon-font-size-3);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border);
|
||||
border-radius: var(--canon-radius-full);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
.canon-Box {
|
||||
font-family: var(--canon-font-regular);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
.canon-Button {
|
||||
user-select: none;
|
||||
font-family: var(--canon-font-regular);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
cursor: pointer;
|
||||
border-radius: var(--canon-radius-2);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-1_5);
|
||||
border: none;
|
||||
padding: 0;
|
||||
display: inline-flex;
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-Button[data-variant="primary"] {
|
||||
background-color: var(--canon-bg-solid);
|
||||
color: var(--canon-fg-solid);
|
||||
transition: background-color .15s, box-shadow .15s;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--canon-bg-solid-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--canon-bg-solid-pressed);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: var(--canon-bg-solid-disabled);
|
||||
color: var(--canon-fg-solid-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-Button[data-variant="secondary"] {
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border);
|
||||
color: var(--canon-fg-primary);
|
||||
transition: box-shadow .15s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-pressed);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: inset 0 0 0 2px var(--canon-ring);
|
||||
outline: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-disabled);
|
||||
color: var(--canon-fg-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-Button[data-size="medium"] {
|
||||
font-size: var(--canon-font-size-4);
|
||||
padding: 0 var(--canon-space-3);
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.canon-Button[data-size="small"] {
|
||||
font-size: var(--canon-font-size-3);
|
||||
padding: 0 var(--canon-space-2);
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.canon-Button[data-size="small"] svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.canon-Button[data-size="medium"] svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
.canon-ButtonIcon {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.canon-ButtonIcon[data-size="small"] {
|
||||
width: 2rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.canon-ButtonIcon[data-size="medium"] {
|
||||
width: 2.5rem;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
.canon-CheckboxRoot {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border);
|
||||
cursor: pointer;
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
transition: background-color .2s ease-in-out;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-CheckboxRoot:focus-visible {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.canon-CheckboxRoot[data-checked] {
|
||||
background-color: var(--canon-bg-solid);
|
||||
box-shadow: none;
|
||||
color: var(--canon-fg-solid);
|
||||
}
|
||||
|
||||
.canon-CheckboxLabel {
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-3);
|
||||
font-family: var(--canon-font-regular);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
user-select: none;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
|
||||
&:hover {
|
||||
& .canon-CheckboxRoot:not([data-checked]) {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canon-CheckboxIndicator {
|
||||
color: var(--canon-fg-solid);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
.canon-CollapsiblePanel {
|
||||
height: var(--collapsible-panel-height);
|
||||
transition: all .15s ease-out;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&[data-starting-style], &[data-ending-style] {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
.canon-Container {
|
||||
max-width: 120rem;
|
||||
padding-inline: var(--canon-space-4);
|
||||
margin-inline: auto;
|
||||
transition: padding .2s ease-in-out;
|
||||
}
|
||||
|
||||
@media (width >= 640px) {
|
||||
.canon-Container {
|
||||
padding-inline: var(--canon-space-8);
|
||||
}
|
||||
}
|
||||
|
||||
@media (width >= 1024px) {
|
||||
.canon-Container {
|
||||
padding-inline: var(--canon-space-12);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
.canon-DataTablePagination {
|
||||
padding-top: var(--canon-space-5);
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-DataTablePagination--left {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-DataTablePagination--right {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-DataTablePagination--select {
|
||||
min-width: 10.5rem;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
.canon-FieldLabel {
|
||||
margin-bottom: var(--canon-space-3);
|
||||
gap: var(--canon-space-1);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-FieldLabelLabel {
|
||||
color: var(--canon-fg-primary);
|
||||
cursor: pointer;
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
font-size: var(--canon-font-size-2);
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.canon-FieldLabelSecondaryLabel {
|
||||
color: var(--canon-fg-secondary);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-left: var(--canon-space-1);
|
||||
}
|
||||
|
||||
.canon-FieldLabelDescription {
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
.canon-Flex {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
.canon-Grid {
|
||||
display: grid;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
.canon-Heading {
|
||||
font-family: var(--canon-font-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.canon-Heading[data-variant="display"] {
|
||||
font-size: var(--canon-font-size-10);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Heading[data-variant="title1"] {
|
||||
font-size: var(--canon-font-size-9);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Heading[data-variant="title2"] {
|
||||
font-size: var(--canon-font-size-8);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Heading[data-variant="title3"] {
|
||||
font-size: var(--canon-font-size-7);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Heading[data-variant="title4"] {
|
||||
font-size: var(--canon-font-size-6);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Heading[data-variant="title5"] {
|
||||
font-size: var(--canon-font-size-5);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Heading[data-color="primary"] {
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
|
||||
.canon-Heading[data-color="secondary"] {
|
||||
color: var(--canon-fg-secondary);
|
||||
}
|
||||
|
||||
.canon-Heading[data-truncate] {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
.canon-Icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
.canon-IconButton {
|
||||
user-select: none;
|
||||
font-family: var(--canon-font-regular);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
cursor: pointer;
|
||||
border-radius: var(--canon-radius-2);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-1_5);
|
||||
border: none;
|
||||
padding: 0;
|
||||
display: inline-flex;
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-IconButton[data-variant="primary"] {
|
||||
background-color: var(--canon-bg-solid);
|
||||
color: var(--canon-fg-solid);
|
||||
transition: background-color .15s, box-shadow .15s;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--canon-bg-solid-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--canon-bg-solid-pressed);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: var(--canon-bg-solid-disabled);
|
||||
color: var(--canon-fg-solid-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-IconButton[data-variant="secondary"] {
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border);
|
||||
color: var(--canon-fg-primary);
|
||||
transition: box-shadow .15s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-pressed);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: inset 0 0 0 2px var(--canon-ring);
|
||||
outline: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
box-shadow: inset 0 0 0 1px var(--canon-border-disabled);
|
||||
color: var(--canon-fg-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-IconButton[data-size="medium"] {
|
||||
font-size: var(--canon-font-size-4);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.canon-IconButton[data-size="small"] {
|
||||
font-size: var(--canon-font-size-3);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.canon-IconButtonIcon[data-size="small"], .canon-IconButtonIcon[data-size="small"] svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.canon-IconButtonIcon[data-size="medium"], .canon-IconButtonIcon[data-size="medium"] svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
.canon-Link {
|
||||
font-family: var(--canon-font-regular);
|
||||
color: var(--canon-fg-link);
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-decoration-line: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--canon-fg-link-hover);
|
||||
text-underline-offset: calc(.025em + 2px);
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: solid;
|
||||
text-decoration-thickness: min(2px, max(1px, .05em));
|
||||
text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-Link[data-variant="body"] {
|
||||
font-size: var(--canon-font-size-3);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link[data-variant="subtitle"] {
|
||||
font-size: var(--canon-font-size-4);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link[data-variant="caption"] {
|
||||
font-size: var(--canon-font-size-2);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link[data-variant="label"] {
|
||||
font-size: var(--canon-font-size-1);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Link[data-weight="regular"] {
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
}
|
||||
|
||||
.canon-Link[data-weight="bold"] {
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
.canon-MenuPositioner {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.canon-MenuPopup {
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
border: 1px solid var(--canon-border);
|
||||
color: var(--canon-fg-primary);
|
||||
transform-origin: var(--transform-origin);
|
||||
max-width: min(var(--available-width), 340px);
|
||||
max-height: min(var(--available-height), 500px);
|
||||
padding-bottom: var(--canon-space-1);
|
||||
border-radius: .375rem;
|
||||
outline: none;
|
||||
flex-direction: column;
|
||||
transition: transform .15s, opacity .15s;
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
|
||||
&[data-starting-style], &[data-ending-style] {
|
||||
opacity: 0;
|
||||
transform: scale(.9);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-MenuItem {
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
height: 32px;
|
||||
color: var(--canon-fg-primary);
|
||||
border-radius: var(--canon-radius-2);
|
||||
margin-inline: var(--canon-space-1);
|
||||
padding-inline: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-3);
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
flex-shrink: 0;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
|
||||
&:first-child {
|
||||
margin-top: var(--canon-space-1);
|
||||
}
|
||||
|
||||
&[data-highlighted] {
|
||||
background-color: var(--canon-gray-3);
|
||||
}
|
||||
}
|
||||
|
||||
.canon-MenuSubmenuTrigger {
|
||||
user-select: none;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
height: 32px;
|
||||
color: var(--canon-fg-primary);
|
||||
border-radius: var(--canon-radius-2);
|
||||
margin-inline: var(--canon-space-1);
|
||||
padding-inline: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-3);
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
flex-shrink: 0;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
|
||||
& .canon-Icon {
|
||||
color: var(--canon-fg-secondary);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: var(--canon-space-1);
|
||||
}
|
||||
|
||||
&[data-popup-open], &[data-highlighted] {
|
||||
background-color: var(--canon-gray-3);
|
||||
|
||||
& .canon-Icon {
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canon-MenuSeparator {
|
||||
background-color: var(--color-gray-200);
|
||||
height: 1px;
|
||||
margin: .375rem 1rem;
|
||||
}
|
||||
|
||||
.canon-SubmenuComboboxSearch {
|
||||
padding-inline: var(--canon-space-3);
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--canon-border);
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
color: var(--canon-fg-primary);
|
||||
line-height: 140%;
|
||||
font-size: var(--canon-font-size-3);
|
||||
z-index: 1;
|
||||
outline: none;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--canon-fg-secondary);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: .6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-SubmenuComboboxItems {
|
||||
padding-top: var(--canon-space-2);
|
||||
outline: none;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.canon-SubmenuComboboxNoResults {
|
||||
padding-inline: var(--canon-space-3);
|
||||
padding-top: var(--canon-space-2);
|
||||
padding-bottom: var(--canon-space-4);
|
||||
color: var(--canon-fg-secondary);
|
||||
font-size: var(--canon-font-size-3);
|
||||
}
|
||||
|
||||
.canon-SubmenuComboboxItem {
|
||||
user-select: none;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
height: 32px;
|
||||
color: var(--canon-fg-primary);
|
||||
border-radius: var(--canon-radius-2);
|
||||
margin-inline: var(--canon-space-1);
|
||||
padding-inline: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-3);
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
flex-shrink: 0;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
|
||||
&[data-highlighted] {
|
||||
background-color: var(--canon-gray-3);
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
opacity: .5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-SubmenuComboboxItemCheckbox {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--canon-fg-primary);
|
||||
border-radius: var(--canon-radius-2);
|
||||
border: 1px solid var(--canon-border);
|
||||
background: var(--canon-bg-surface-1);
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-SubmenuComboboxItemLabel {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
.canon-ScrollAreaRoot {
|
||||
box-sizing: border-box;
|
||||
width: 24rem;
|
||||
max-width: calc(100vw - 8rem);
|
||||
height: 8.5rem;
|
||||
}
|
||||
|
||||
.canon-ScrollAreaViewport {
|
||||
overscroll-behavior: contain;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.canon-ScrollAreaContent {
|
||||
padding-block: .75rem;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1.5rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-ScrollAreaScrollbar {
|
||||
background-color: var(--canon-scrollbar);
|
||||
opacity: 0;
|
||||
border-radius: .375rem;
|
||||
justify-content: center;
|
||||
width: .25rem;
|
||||
margin: .5rem;
|
||||
transition: opacity .15s .3s;
|
||||
display: flex;
|
||||
|
||||
&[data-hovering], &[data-scrolling] {
|
||||
opacity: 1;
|
||||
transition-duration: 75ms;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
width: 1.25rem;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-ScrollAreaThumb {
|
||||
border-radius: inherit;
|
||||
background-color: var(--canon-scrollbar-thumb);
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
.canon-Select {
|
||||
font-family: var(--canon-font-regular);
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-SelectLabel {
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-SelectLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-SelectDescription {
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-secondary);
|
||||
padding-top: var(--canon-space-1_5);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.canon-SelectError {
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-danger);
|
||||
padding-top: var(--canon-space-1_5);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.canon-SelectTrigger {
|
||||
box-sizing: border-box;
|
||||
border-radius: var(--canon-radius-3);
|
||||
border: 1px solid var(--canon-border);
|
||||
padding: 0 var(--canon-space-4);
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
font-size: var(--canon-font-size-3);
|
||||
font-family: var(--canon-font-regular);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
cursor: pointer;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
width: 100%;
|
||||
transition: border-color .2s ease-in-out, outline-color .2s ease-in-out;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-SelectTrigger::placeholder {
|
||||
color: var(--canon-fg-secondary);
|
||||
}
|
||||
|
||||
.canon-SelectTrigger:hover {
|
||||
border-color: var(--canon-border-hover);
|
||||
}
|
||||
|
||||
.canon-SelectTrigger:focus-visible {
|
||||
border-color: var(--canon-border-pressed);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.canon-SelectTrigger[data-invalid] {
|
||||
border-color: var(--canon-fg-danger);
|
||||
}
|
||||
|
||||
.canon-SelectTrigger[data-invalid]:hover, .canon-SelectTrigger[data-invalid]:focus-visible {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.canon-SelectTrigger[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
border-color: var(--canon-border-disabled);
|
||||
color: var(--canon-fg-disabled);
|
||||
}
|
||||
|
||||
.canon-SelectTrigger[data-size="small"] {
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.canon-SelectTrigger[data-size="medium"] {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.canon-SelectIcon {
|
||||
margin-left: var(--canon-space-5);
|
||||
transition: transform .2s;
|
||||
}
|
||||
|
||||
.canon-SelectTrigger[data-popup-open] .canon-SelectIcon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.canon-SelectPopup {
|
||||
box-sizing: border-box;
|
||||
max-height: var(--available-height);
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
border: 1px solid var(--canon-border);
|
||||
border-radius: var(--canon-radius-3);
|
||||
padding-block: var(--canon-space-1);
|
||||
z-index: 1;
|
||||
transform-origin: var(--transform-origin);
|
||||
outline: 0;
|
||||
transition: transform .15s, opacity .15s;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 4px 12px #0003;
|
||||
}
|
||||
|
||||
.canon-SelectPopup[data-starting-style], .canon-SelectPopup[data-ending-style] {
|
||||
opacity: 0;
|
||||
transform: scale(.9);
|
||||
}
|
||||
|
||||
.canon-SelectItem {
|
||||
width: var(--anchor-width);
|
||||
padding-block: var(--canon-space-2);
|
||||
padding-inline: var(--canon-space-4);
|
||||
color: var(--canon-fg-primary);
|
||||
border-radius: var(--canon-radius-3);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: var(--canon-font-size-3);
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
outline: none;
|
||||
grid-template-columns: 1rem 1fr;
|
||||
grid-template-areas: "icon text";
|
||||
display: grid;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.canon-SelectItem[data-highlighted] {
|
||||
z-index: 0;
|
||||
color: var(--canon-fg-primary);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.canon-SelectItem[data-highlighted]:before {
|
||||
content: "";
|
||||
z-index: -1;
|
||||
background-color: var(--canon-bg-tint-hover);
|
||||
border-radius: .25rem;
|
||||
position: absolute;
|
||||
inset-block: 0;
|
||||
inset-inline: .25rem;
|
||||
}
|
||||
|
||||
.canon-SelectItem[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
}
|
||||
|
||||
.canon-SelectItemIndicator {
|
||||
grid-area: icon;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-SelectItemText {
|
||||
flex: 1;
|
||||
grid-area: text;
|
||||
}
|
||||
|
||||
.canon-SelectRequired {
|
||||
color: var(--canon-fg-secondary);
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-left: var(--canon-space-1);
|
||||
}
|
||||
|
||||
.canon-SelectIcon {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-SelectValue {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -9496,6 +9496,13 @@
|
||||
min-width: 10.5rem;
|
||||
}
|
||||
|
||||
.canon-FieldError {
|
||||
color: var(--canon-fg-danger);
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-top: var(--canon-space-2);
|
||||
}
|
||||
|
||||
.canon-FieldLabel {
|
||||
margin-bottom: var(--canon-space-3);
|
||||
gap: var(--canon-space-1);
|
||||
@@ -9815,6 +9822,96 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.canon-RadioGroup {
|
||||
color: var(--canon-fg-primary);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-RadioGroup[data-orientation="horizontal"] .canon-RadioGroupContent {
|
||||
gap: var(--canon-space-4);
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.canon-RadioGroupContent {
|
||||
gap: var(--canon-space-2);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-Radio {
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-primary);
|
||||
forced-color-adjust: none;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
border: .125rem solid var(--canon-border);
|
||||
background: var(--canon-gray-1);
|
||||
border-radius: var(--canon-radius-full);
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
transition: all .2s;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-border);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
&:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
border-width: .25rem;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible]:before {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-invalid]:before, &[data-invalid][data-selected]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
&[data-disabled][data-invalid] {
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canon-TableRoot {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
@@ -10119,13 +10216,6 @@
|
||||
border: 1px solid var(--canon-border-disabled);
|
||||
}
|
||||
|
||||
.canon-TextFieldError {
|
||||
color: var(--canon-fg-danger);
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-top: var(--canon-space-2);
|
||||
}
|
||||
|
||||
.canon-TooltipPopup {
|
||||
box-sizing: border-box;
|
||||
transform-origin: var(--transform-origin);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
.canon-Switch {
|
||||
align-items: center;
|
||||
gap: var(--canon-space-3);
|
||||
font-size: var(--canon-font-size-3);
|
||||
color: var(--canon-fg-primary);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&[data-pressed] .canon-SwitchIndicator {
|
||||
&:before {
|
||||
background: var(--canon-fg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
& .canon-SwitchIndicator {
|
||||
background: var(--canon-bg-solid);
|
||||
|
||||
&:before {
|
||||
background: var(--canon-fg-solid);
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-pressed] {
|
||||
& .indicator {
|
||||
background: var(--canon-gray-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible] .canon-SwitchIndicator {
|
||||
outline-offset: 2px;
|
||||
outline: 2px solid;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-SwitchIndicator {
|
||||
background: var(--canon-gray-3);
|
||||
border: 2px;
|
||||
border-radius: 1.143rem;
|
||||
width: 2rem;
|
||||
height: 1.143rem;
|
||||
transition: all .2s;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
background: var(--canon-fg-solid);
|
||||
border-radius: 16px;
|
||||
width: .857rem;
|
||||
height: .857rem;
|
||||
margin: .143rem;
|
||||
transition: all .2s;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
.canon-TableCell {
|
||||
padding: var(--canon-space-3);
|
||||
font-size: var(--canon-font-size-3);
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
.canon-TabsRoot {
|
||||
border: 1px solid var(--color-gray-200);
|
||||
border-radius: .375rem;
|
||||
}
|
||||
|
||||
.canon-TabsList {
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.canon-TabsTab {
|
||||
appearance: none;
|
||||
color: var(--canon-fg-secondary);
|
||||
user-select: none;
|
||||
padding-inline: var(--canon-space-3);
|
||||
height: 2rem;
|
||||
font-family: inherit;
|
||||
font-size: .875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem;
|
||||
font-size: var(--canon-font-size-2);
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding-block: 0;
|
||||
transition: color .2s ease-in-out;
|
||||
display: flex;
|
||||
|
||||
&[data-selected] {
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
&:hover {
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
outline: 1px solid var(--canon-ring);
|
||||
outline-offset: -1px;
|
||||
border-radius: .25rem;
|
||||
position: absolute;
|
||||
inset: .25rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canon-TabsIndicator {
|
||||
z-index: -1;
|
||||
translate: var(--active-tab-left) -50%;
|
||||
width: var(--active-tab-width);
|
||||
background-color: var(--canon-bg-solid);
|
||||
height: 1px;
|
||||
transition-property: translate, width;
|
||||
transition-duration: .2s;
|
||||
transition-timing-function: ease-in-out;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.canon-TabsPanel {
|
||||
&[hidden] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
.canon-Text {
|
||||
font-family: var(--canon-font-regular);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.canon-Text[data-variant="body"] {
|
||||
font-size: var(--canon-font-size-3);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Text[data-variant="subtitle"] {
|
||||
font-size: var(--canon-font-size-4);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Text[data-variant="caption"] {
|
||||
font-size: var(--canon-font-size-2);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Text[data-variant="label"] {
|
||||
font-size: var(--canon-font-size-1);
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.canon-Text[data-weight="regular"] {
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
}
|
||||
|
||||
.canon-Text[data-weight="bold"] {
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
}
|
||||
|
||||
.canon-Text[data-color="primary"] {
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
|
||||
.canon-Text[data-color="secondary"] {
|
||||
color: var(--canon-fg-secondary);
|
||||
}
|
||||
|
||||
.canon-Text[data-color="danger"] {
|
||||
color: var(--canon-fg-danger);
|
||||
}
|
||||
|
||||
.canon-Text[data-color="warning"] {
|
||||
color: var(--canon-fg-warning);
|
||||
}
|
||||
|
||||
.canon-Text[data-color="success"] {
|
||||
color: var(--canon-fg-success);
|
||||
}
|
||||
|
||||
.canon-Text[data-truncate] {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
.canon-TextField {
|
||||
font-family: var(--canon-font-regular);
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-TextFieldInputWrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.canon-TextFieldInputWrapper[data-size="small"] {
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.canon-TextFieldInputWrapper[data-size="medium"] {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.canon-TextFieldIcon {
|
||||
left: var(--canon-space-3);
|
||||
margin-right: var(--canon-space-1);
|
||||
color: var(--canon-fg-primary);
|
||||
flex-shrink: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.canon-TextFieldIcon[data-size="small"], .canon-TextFieldIcon[data-size="small"] svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.canon-TextFieldIcon[data-size="medium"], .canon-TextFieldIcon[data-size="medium"] svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.canon-TextFieldInput {
|
||||
padding: 0 var(--canon-space-3);
|
||||
border-radius: var(--canon-radius-3);
|
||||
border: 1px solid var(--canon-border);
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
font-size: var(--canon-font-size-3);
|
||||
font-family: var(--canon-font-regular);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: inherit;
|
||||
align-items: center;
|
||||
transition: border-color .2s ease-in-out, outline-color .2s ease-in-out;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-TextFieldInput::placeholder {
|
||||
color: var(--canon-fg-secondary);
|
||||
}
|
||||
|
||||
.canon-TextFieldInput[data-icon] {
|
||||
padding-left: var(--canon-space-8);
|
||||
}
|
||||
|
||||
.canon-TextFieldInput[data-focused] {
|
||||
outline-color: var(--canon-border-pressed);
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
.canon-TextFieldInput[data-hovered] {
|
||||
border-color: var(--canon-border-hover);
|
||||
}
|
||||
|
||||
.canon-TextFieldInput[data-focused] {
|
||||
border-color: var(--canon-border-pressed);
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
.canon-TextFieldInput[data-invalid] {
|
||||
border-color: var(--canon-fg-danger);
|
||||
}
|
||||
|
||||
.canon-TextFieldInput[data-disabled] {
|
||||
opacity: .5;
|
||||
cursor: not-allowed;
|
||||
border: 1px solid var(--canon-border-disabled);
|
||||
}
|
||||
|
||||
.canon-TextFieldError {
|
||||
color: var(--canon-fg-danger);
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-top: var(--canon-space-2);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
.canon-TooltipPopup {
|
||||
box-sizing: border-box;
|
||||
transform-origin: var(--transform-origin);
|
||||
background-color: canvas;
|
||||
background-color: var(--canon-bg-surface-1);
|
||||
color: var(--canon-fg-primary);
|
||||
outline: 1px solid var(--canon-border);
|
||||
box-shadow: 0 10px 15px -3px var(--canon-border), 0 4px 6px -4px var(--canon-border);
|
||||
border-radius: .375rem;
|
||||
flex-direction: column;
|
||||
padding: .25rem .5rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1.25rem;
|
||||
transition: transform .15s, opacity .15s;
|
||||
display: flex;
|
||||
|
||||
&[data-starting-style], &[data-ending-style] {
|
||||
opacity: 0;
|
||||
transform: scale(.9);
|
||||
}
|
||||
|
||||
&[data-instant] {
|
||||
transition-duration: 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-TooltipArrow {
|
||||
display: flex;
|
||||
|
||||
&[data-side="top"] {
|
||||
bottom: -8px;
|
||||
rotate: 180deg;
|
||||
}
|
||||
|
||||
&[data-side="bottom"] {
|
||||
top: -8px;
|
||||
rotate: none;
|
||||
}
|
||||
|
||||
&[data-side="left"] {
|
||||
right: -13px;
|
||||
rotate: 90deg;
|
||||
}
|
||||
|
||||
&[data-side="right"] {
|
||||
left: -13px;
|
||||
rotate: -90deg;
|
||||
}
|
||||
}
|
||||
|
||||
.canon-TooltipArrow-fill {
|
||||
fill: var(--canon-bg-surface-1);
|
||||
}
|
||||
|
||||
.canon-TooltipArrow-outer-stroke {
|
||||
@media (prefers-color-scheme: light) {
|
||||
& {
|
||||
fill: var(--canon-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import { HTMLAttributes } from 'react';
|
||||
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
||||
import { LinkProps as LinkProps_2 } from 'react-aria-components';
|
||||
import { Menu as Menu_2 } from '@base-ui-components/react/menu';
|
||||
import type { RadioGroupProps as RadioGroupProps_2 } from 'react-aria-components';
|
||||
import type { RadioProps as RadioProps_2 } from 'react-aria-components';
|
||||
import { ReactElement } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RefAttributes } from 'react';
|
||||
@@ -1032,6 +1034,27 @@ export type PositionProps = GetPropDefTypes<typeof positionPropDefs>;
|
||||
// @public (undocumented)
|
||||
export type PropDef<T = any> = RegularPropDef<T> | ResponsivePropDef<T>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const Radio: ForwardRefExoticComponent<
|
||||
RadioProps & RefAttributes<HTMLLabelElement>
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const RadioGroup: ForwardRefExoticComponent<
|
||||
RadioGroupProps & RefAttributes<HTMLDivElement>
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RadioGroupProps
|
||||
extends Omit<RadioGroupProps_2, 'children'>,
|
||||
Omit<FieldLabelProps, 'htmlFor' | 'id'> {
|
||||
// (undocumented)
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RadioProps extends RadioProps_2 {}
|
||||
|
||||
// @public (undocumented)
|
||||
export type ReactNodePropDef = {
|
||||
type: 'ReactNode';
|
||||
@@ -1299,6 +1322,7 @@ export interface TextFieldProps
|
||||
extends TextFieldProps_2,
|
||||
Omit<FieldLabelProps, 'htmlFor' | 'id'> {
|
||||
icon?: ReactNode;
|
||||
placeholder?: string;
|
||||
size?: 'small' | 'medium' | Partial<Record<Breakpoint, 'small' | 'medium'>>;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,89 +17,55 @@
|
||||
/* eslint-disable no-restricted-imports */
|
||||
import { transform, bundle } from 'lightningcss';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import { glob } from 'glob';
|
||||
/* eslint-enable no-restricted-imports */
|
||||
|
||||
// Check if core.css and components.css exist
|
||||
const cssDir = 'src/css';
|
||||
const srcFile = 'src/css/styles.css';
|
||||
const distDir = 'css';
|
||||
const componentsDir = 'src/components';
|
||||
const distFile = `${distDir}/styles.css`;
|
||||
|
||||
// Core files
|
||||
const cssFiles = [
|
||||
{ path: `${cssDir}/core.css`, newName: 'core.css' },
|
||||
{ path: `${cssDir}/components.css`, newName: 'components.css' },
|
||||
{ path: `${cssDir}/styles.css`, newName: 'styles.css' },
|
||||
];
|
||||
|
||||
// Components files
|
||||
const componentsFiles = glob
|
||||
.sync('**/*.css', { cwd: componentsDir })
|
||||
.map(file => {
|
||||
const folderName = file.split('/')[0].toLocaleLowerCase('en-US');
|
||||
return { path: `${componentsDir}/${file}`, newName: `${folderName}.css` };
|
||||
});
|
||||
|
||||
// Combine core and components files
|
||||
cssFiles.push(...componentsFiles);
|
||||
|
||||
// Check if files exist
|
||||
cssFiles.forEach(file => {
|
||||
if (!fs.existsSync(file.path)) {
|
||||
console.error(`${file.originalName} does not exist`);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
// Check if styles.css exists
|
||||
if (!fs.existsSync(srcFile)) {
|
||||
console.error(`${srcFile} does not exist`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Ensure the dist/css directory exists
|
||||
if (!fs.existsSync(distDir)) {
|
||||
fs.mkdirSync(distDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Add watch mode support
|
||||
const args = process.argv.slice(2);
|
||||
const watchMode = args.includes('--watch');
|
||||
|
||||
async function buildCSS(logs = true) {
|
||||
// Bundle and transform files
|
||||
cssFiles.forEach(file => {
|
||||
let { code: bundleCode } = bundle({
|
||||
filename: file.path,
|
||||
});
|
||||
const css = fs.readFileSync(srcFile);
|
||||
|
||||
let { code } = transform({
|
||||
filename: `${distDir}/${file.newName}`,
|
||||
code: bundleCode,
|
||||
});
|
||||
|
||||
fs.writeFileSync(`${distDir}/${file.newName}`, code);
|
||||
|
||||
if (logs) {
|
||||
console.log(chalk.blue('CSS bundled: ') + file.newName);
|
||||
}
|
||||
let { code: bundleCode } = bundle({
|
||||
filename: srcFile,
|
||||
});
|
||||
|
||||
const { code } = transform({
|
||||
filename: distFile,
|
||||
code: bundleCode,
|
||||
minify: false,
|
||||
});
|
||||
fs.writeFileSync(distFile, code);
|
||||
if (logs) {
|
||||
console.log(chalk.green('CSS files bundled successfully!'));
|
||||
console.log(chalk.blue('CSS transformed and minified: ') + 'styles.css');
|
||||
console.log(chalk.green('CSS file built successfully!'));
|
||||
}
|
||||
}
|
||||
|
||||
if (watchMode) {
|
||||
// Watch both directories for changes
|
||||
[cssDir, componentsDir].forEach(dir => {
|
||||
fs.watch(dir, { recursive: true }, (eventType, filename) => {
|
||||
if (filename?.endsWith('.css')) {
|
||||
console.log(
|
||||
chalk.yellow(`Changes detected in ${filename}, rebuilding...`),
|
||||
);
|
||||
buildCSS(false).catch(console.error);
|
||||
}
|
||||
});
|
||||
fs.watch('src/css', { recursive: true }, (eventType, filename) => {
|
||||
if (filename === 'styles.css') {
|
||||
console.log(
|
||||
chalk.yellow(`Changes detected in ${filename}, rebuilding...`),
|
||||
);
|
||||
buildCSS(false).catch(console.error);
|
||||
}
|
||||
});
|
||||
|
||||
// Initial build
|
||||
buildCSS().catch(console.error);
|
||||
console.log(chalk.yellow('Watching for CSS changes...'));
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { TextField, Input, Form } from 'react-aria-components';
|
||||
import { FieldError } from './FieldError';
|
||||
|
||||
const meta = {
|
||||
title: 'Forms/FieldError',
|
||||
component: FieldError,
|
||||
} satisfies Meta<typeof FieldError>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
// Show error with server validation using Form component
|
||||
export const WithServerValidation: Story = {
|
||||
render: () => (
|
||||
<Form validationErrors={{ demo: 'This is a server validation error.' }}>
|
||||
<TextField
|
||||
name="demo"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<Input />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
</Form>
|
||||
),
|
||||
};
|
||||
|
||||
// Show error using children
|
||||
export const WithCustomMessage: Story = {
|
||||
render: () => (
|
||||
<TextField
|
||||
isInvalid
|
||||
validationBehavior="aria"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<Input />
|
||||
<FieldError>This is a custom error message.</FieldError>
|
||||
</TextField>
|
||||
),
|
||||
};
|
||||
|
||||
// Show error with render prop function
|
||||
export const WithRenderProp: Story = {
|
||||
render: () => (
|
||||
<TextField
|
||||
isInvalid
|
||||
validationBehavior="aria"
|
||||
validate={() => 'This field is invalid'}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<Input />
|
||||
<FieldError>
|
||||
{({ validationErrors }) =>
|
||||
validationErrors.length > 0 ? validationErrors[0] : 'Field is invalid'
|
||||
}
|
||||
</FieldError>
|
||||
</TextField>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
.canon-FieldError {
|
||||
color: var(--canon-fg-danger);
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-top: var(--canon-space-2);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { forwardRef } from 'react';
|
||||
import {
|
||||
FieldError as AriaFieldError,
|
||||
type FieldErrorProps,
|
||||
} from 'react-aria-components';
|
||||
import clsx from 'clsx';
|
||||
|
||||
/** @public */
|
||||
export const FieldError = forwardRef<HTMLDivElement, FieldErrorProps>(
|
||||
(props: FieldErrorProps, ref) => {
|
||||
const { className, ...rest } = props;
|
||||
|
||||
return (
|
||||
<AriaFieldError
|
||||
className={clsx('canon-FieldError', className)}
|
||||
ref={ref}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
FieldError.displayName = 'FieldError';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './FieldError';
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { RadioGroup, Radio } from './RadioGroup';
|
||||
|
||||
const meta = {
|
||||
title: 'Forms/RadioGroup',
|
||||
component: RadioGroup,
|
||||
} satisfies Meta<typeof RadioGroup>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: 'What is your favorite pokemon?',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Horizontal: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
orientation: 'horizontal',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
isDisabled: true,
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const DisabledSingle: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>
|
||||
Charmander
|
||||
</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const DisabledAndSelected: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
value: 'charmander',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>
|
||||
Charmander
|
||||
</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Invalid: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
name: 'pokemon',
|
||||
isInvalid: true,
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>
|
||||
Charmander
|
||||
</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Validation: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
name: 'pokemon',
|
||||
defaultValue: 'charmander',
|
||||
validationBehavior: 'aria',
|
||||
validate: value => (value === 'charmander' ? 'Nice try!' : null),
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const ReadOnly: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
isReadOnly: true,
|
||||
defaultValue: 'charmander',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
.canon-RadioGroup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
|
||||
.canon-RadioGroup[data-orientation='horizontal'] .canon-RadioGroupContent {
|
||||
flex-direction: row;
|
||||
gap: var(--canon-space-4);
|
||||
}
|
||||
|
||||
.canon-RadioGroupContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--canon-space-2);
|
||||
}
|
||||
|
||||
.canon-Radio {
|
||||
display: flex;
|
||||
/* This is needed so the HiddenInput is positioned correctly */
|
||||
position: relative;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-primary);
|
||||
forced-color-adjust: none;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
box-sizing: border-box;
|
||||
border: 0.125rem solid var(--canon-border);
|
||||
background: var(--canon-gray-1);
|
||||
border-radius: var(--canon-radius-full);
|
||||
transition: all 200ms;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-border);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
&:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
border-width: 0.25rem;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible]:before {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-invalid]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
&[data-invalid][data-selected]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
/* Ensure disabled state prevails over invalid state */
|
||||
&[data-disabled][data-invalid] {
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { forwardRef, useEffect } from 'react';
|
||||
import {
|
||||
RadioGroup as AriaRadioGroup,
|
||||
Radio as AriaRadio,
|
||||
} from 'react-aria-components';
|
||||
import clsx from 'clsx';
|
||||
import { FieldLabel } from '../FieldLabel';
|
||||
import { FieldError } from '../FieldError';
|
||||
|
||||
import type { RadioGroupProps, RadioProps } from './types';
|
||||
|
||||
/** @public */
|
||||
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
className,
|
||||
label,
|
||||
secondaryLabel,
|
||||
description,
|
||||
isRequired,
|
||||
'aria-label': ariaLabel,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
children,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (!label && !ariaLabel && !ariaLabelledBy) {
|
||||
console.warn(
|
||||
'RadioGroup requires either a visible label, aria-label, or aria-labelledby for accessibility',
|
||||
);
|
||||
}
|
||||
}, [label, ariaLabel, ariaLabelledBy]);
|
||||
|
||||
// If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required.
|
||||
const secondaryLabelText =
|
||||
secondaryLabel || (isRequired ? 'Required' : null);
|
||||
|
||||
return (
|
||||
<AriaRadioGroup
|
||||
className={clsx('canon-RadioGroup', className)}
|
||||
aria-label={ariaLabel}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
{...rest}
|
||||
ref={ref}
|
||||
>
|
||||
<FieldLabel
|
||||
label={label}
|
||||
secondaryLabel={secondaryLabelText}
|
||||
description={description}
|
||||
/>
|
||||
<div className="canon-RadioGroupContent">{children}</div>
|
||||
<FieldError />
|
||||
</AriaRadioGroup>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
RadioGroup.displayName = 'RadioGroup';
|
||||
|
||||
/** @public */
|
||||
export const Radio = forwardRef<HTMLLabelElement, RadioProps>((props, ref) => {
|
||||
const { className, ...rest } = props;
|
||||
|
||||
return (
|
||||
<AriaRadio className={clsx('canon-Radio', className)} {...rest} ref={ref} />
|
||||
);
|
||||
});
|
||||
|
||||
RadioGroup.displayName = 'RadioGroup';
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './RadioGroup';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type {
|
||||
RadioGroupProps as AriaRadioGroupProps,
|
||||
RadioProps as AriaRadioProps,
|
||||
} from 'react-aria-components';
|
||||
import type { FieldLabelProps } from '../FieldLabel/types';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
/** @public */
|
||||
export interface RadioGroupProps
|
||||
extends Omit<AriaRadioGroupProps, 'children'>,
|
||||
Omit<FieldLabelProps, 'htmlFor' | 'id'> {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface RadioProps extends AriaRadioProps {}
|
||||
@@ -40,7 +40,7 @@ type Story = StoryObj<typeof meta>;
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
name: 'url',
|
||||
defaultValue: 'Enter a URL',
|
||||
placeholder: 'Enter a URL',
|
||||
style: {
|
||||
maxWidth: '300px',
|
||||
},
|
||||
@@ -97,7 +97,7 @@ export const Disabled: Story = {
|
||||
export const WithIcon: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
defaultValue: 'Search...',
|
||||
placeholder: 'Search...',
|
||||
icon: <Icon name="search" />,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -109,10 +109,3 @@
|
||||
cursor: not-allowed;
|
||||
border: 1px solid var(--canon-border-disabled);
|
||||
}
|
||||
|
||||
.canon-TextFieldError {
|
||||
color: var(--canon-fg-danger);
|
||||
font-size: var(--canon-font-size-2);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
margin-top: var(--canon-space-2);
|
||||
}
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
|
||||
import { forwardRef, useEffect } from 'react';
|
||||
import {
|
||||
Input,
|
||||
TextField as AriaTextField,
|
||||
FieldError,
|
||||
} from 'react-aria-components';
|
||||
import { Input, TextField as AriaTextField } from 'react-aria-components';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import clsx from 'clsx';
|
||||
import { FieldLabel } from '../FieldLabel';
|
||||
import { FieldError } from '../FieldError';
|
||||
|
||||
import type { TextFieldProps } from './types';
|
||||
|
||||
@@ -39,6 +36,7 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
isRequired,
|
||||
'aria-label': ariaLabel,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
placeholder,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
@@ -81,9 +79,12 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
{icon}
|
||||
</div>
|
||||
)}
|
||||
<Input {...(icon && { 'data-icon': true })} />
|
||||
<Input
|
||||
{...(icon && { 'data-icon': true })}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
</div>
|
||||
<FieldError className="canon-TextFieldError" />
|
||||
<FieldError />
|
||||
</AriaTextField>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -33,4 +33,9 @@ export interface TextFieldProps
|
||||
* @defaultValue 'medium'
|
||||
*/
|
||||
size?: 'small' | 'medium' | Partial<Record<Breakpoint, 'small' | 'medium'>>;
|
||||
|
||||
/**
|
||||
* Text to display in the input when it has no value
|
||||
*/
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
@import '../components/Container/styles.css';
|
||||
@import '../components/DataTable/Root/DataTableRoot.styles.css';
|
||||
@import '../components/DataTable/Pagination/DataTablePagination.styles.css';
|
||||
@import '../components/FieldError/FieldError.styles.css';
|
||||
@import '../components/FieldLabel/FieldLabel.styles.css';
|
||||
@import '../components/Flex/styles.css';
|
||||
@import '../components/Grid/styles.css';
|
||||
@@ -30,6 +31,7 @@
|
||||
@import '../components/Icon/styles.css';
|
||||
@import '../components/Link/styles.css';
|
||||
@import '../components/Menu/Menu.styles.css';
|
||||
@import '../components/RadioGroup/RadioGroup.styles.css';
|
||||
@import '../components/Table/styles.css';
|
||||
@import '../components/Table/TableCell/TableCell.styles.css';
|
||||
@import '../components/Table/TableCellText/TableCellText.styles.css';
|
||||
|
||||
@@ -41,6 +41,7 @@ export * from './components/Icon';
|
||||
export * from './components/ButtonIcon';
|
||||
export * from './components/ButtonLink';
|
||||
export * from './components/Checkbox';
|
||||
export * from './components/RadioGroup';
|
||||
export * from './components/Table';
|
||||
export * from './components/Tabs';
|
||||
export * from './components/TextField';
|
||||
|
||||
@@ -173,7 +173,7 @@ export class ScmAuth implements ScmAuthApi {
|
||||
const host = options?.host ?? 'gitlab.com';
|
||||
return new ScmAuth('gitlab', gitlabAuthApi, host, {
|
||||
default: ['read_user', 'read_api', 'read_repository'],
|
||||
repoWrite: ['write_repository api'],
|
||||
repoWrite: ['write_repository', 'api'],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -588,6 +588,7 @@ export function getGitilesAuthenticationUrl(
|
||||
export function getGitLabFileFetchUrl(
|
||||
url: string,
|
||||
config: GitLabIntegrationConfig,
|
||||
token?: string,
|
||||
): Promise<string>;
|
||||
|
||||
// @public
|
||||
|
||||
@@ -40,8 +40,9 @@ import {
|
||||
export async function getGitLabFileFetchUrl(
|
||||
url: string,
|
||||
config: GitLabIntegrationConfig,
|
||||
token?: string,
|
||||
): Promise<string> {
|
||||
const projectID = await getProjectId(url, config);
|
||||
const projectID = await getProjectId(url, config, token);
|
||||
return buildProjectUrl(url, projectID, config).toString();
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ export function buildProjectUrl(
|
||||
export async function getProjectId(
|
||||
target: string,
|
||||
config: GitLabIntegrationConfig,
|
||||
token?: string,
|
||||
): Promise<number> {
|
||||
const url = new URL(target);
|
||||
|
||||
@@ -143,7 +145,7 @@ export async function getProjectId(
|
||||
|
||||
const response = await fetch(
|
||||
repoIDLookup.toString(),
|
||||
getGitLabRequestOptions(config),
|
||||
getGitLabRequestOptions(config, token),
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
@@ -16,6 +16,35 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { TranslationRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const catalogGraphTranslationRef: TranslationRef<
|
||||
'catalog-graph',
|
||||
{
|
||||
readonly 'catalogGraphCard.title': 'Relations';
|
||||
readonly 'catalogGraphCard.deepLinkTitle': 'View graph';
|
||||
readonly 'catalogGraphPage.title': 'Catalog Graph';
|
||||
readonly 'catalogGraphPage.filterToggleButtonTitle': 'Filters';
|
||||
readonly 'catalogGraphPage.supportButtonDescription': 'Start tracking your component in by adding it to the software catalog.';
|
||||
readonly 'catalogGraphPage.simplifiedSwitchLabel': 'Simplified';
|
||||
readonly 'catalogGraphPage.mergeRelationsSwitchLabel': 'Merge relations';
|
||||
readonly 'catalogGraphPage.zoomOutDescription': 'Use pinch & zoom to move around the diagram. Click to change active node, shift click to navigate to entity.';
|
||||
readonly 'catalogGraphPage.curveFilter.title': 'Curve';
|
||||
readonly 'catalogGraphPage.curveFilter.curveStepBefore': 'Step Before';
|
||||
readonly 'catalogGraphPage.curveFilter.curveMonotoneX': 'Monotone X';
|
||||
readonly 'catalogGraphPage.directionFilter.title': 'Direction';
|
||||
readonly 'catalogGraphPage.directionFilter.leftToRight': 'Left to right';
|
||||
readonly 'catalogGraphPage.directionFilter.rightToLeft': 'Right to left';
|
||||
readonly 'catalogGraphPage.directionFilter.topToBottom': 'Top to bottom';
|
||||
readonly 'catalogGraphPage.directionFilter.bottomToTop': 'Bottom to top';
|
||||
readonly 'catalogGraphPage.maxDepthFilter.title': 'Max depth';
|
||||
readonly 'catalogGraphPage.maxDepthFilter.inputPlaceholder': '∞ Infinite';
|
||||
readonly 'catalogGraphPage.maxDepthFilter.clearButtonAriaLabel': 'clear max depth';
|
||||
readonly 'catalogGraphPage.selectedKindsFilter.title': 'Kinds';
|
||||
readonly 'catalogGraphPage.selectedRelationsFilter.title': 'Relations';
|
||||
}
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
const _default: FrontendPlugin<
|
||||
|
||||
@@ -96,3 +96,5 @@ export default createFrontendPlugin({
|
||||
},
|
||||
extensions: [CatalogGraphPage, CatalogGraphEntityCard],
|
||||
});
|
||||
|
||||
export { catalogGraphTranslationRef } from './translation';
|
||||
|
||||
@@ -34,6 +34,7 @@ import userEvent from '@testing-library/user-event';
|
||||
import { catalogGraphRouteRef } from '../../routes';
|
||||
import { CatalogGraphCard } from './CatalogGraphCard';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { translationApiRef } from '@backstage/core-plugin-api/alpha';
|
||||
|
||||
describe('<CatalogGraphCard/>', () => {
|
||||
let entity: Entity;
|
||||
@@ -52,7 +53,10 @@ describe('<CatalogGraphCard/>', () => {
|
||||
namespace: 'd',
|
||||
},
|
||||
};
|
||||
apis = TestApiRegistry.from([catalogApiRef, catalog]);
|
||||
apis = TestApiRegistry.from(
|
||||
[catalogApiRef, catalog],
|
||||
[translationApiRef, mockApis.translation()],
|
||||
);
|
||||
|
||||
wrapper = (
|
||||
<ApiProvider apis={apis}>
|
||||
@@ -213,7 +217,12 @@ describe('<CatalogGraphCard/>', () => {
|
||||
|
||||
const analyticsApi = mockApis.analytics();
|
||||
await renderInTestApp(
|
||||
<TestApiProvider apis={[[analyticsApiRef, analyticsApi]]}>
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[analyticsApiRef, analyticsApi],
|
||||
[translationApiRef, mockApis.translation()],
|
||||
]}
|
||||
>
|
||||
{wrapper}
|
||||
</TestApiProvider>,
|
||||
{
|
||||
|
||||
@@ -38,6 +38,8 @@ import {
|
||||
EntityRelationsGraph,
|
||||
EntityRelationsGraphProps,
|
||||
} from '../EntityRelationsGraph';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
|
||||
/** @public */
|
||||
export type CatalogGraphCardClassKey = 'card' | 'graph';
|
||||
@@ -66,6 +68,7 @@ export const CatalogGraphCard = (
|
||||
action?: ReactNode;
|
||||
},
|
||||
) => {
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
const {
|
||||
variant = 'gridItem',
|
||||
relationPairs = ALL_RELATION_PAIRS,
|
||||
@@ -81,7 +84,7 @@ export const CatalogGraphCard = (
|
||||
action,
|
||||
rootEntityNames,
|
||||
onNodeClick,
|
||||
title = 'Relations',
|
||||
title = t('catalogGraphCard.title'),
|
||||
zoom = 'enable-on-click',
|
||||
} = props;
|
||||
|
||||
@@ -133,7 +136,7 @@ export const CatalogGraphCard = (
|
||||
variant={variant}
|
||||
noPadding
|
||||
deepLink={{
|
||||
title: 'View graph',
|
||||
title: t('catalogGraphCard.deepLinkTitle'),
|
||||
link: catalogGraphUrl,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -50,6 +50,8 @@ import { SelectedKindsFilter } from './SelectedKindsFilter';
|
||||
import { SelectedRelationsFilter } from './SelectedRelationsFilter';
|
||||
import { SwitchFilter } from './SwitchFilter';
|
||||
import { useCatalogGraphPage } from './useCatalogGraphPage';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
|
||||
/** @public */
|
||||
export type CatalogGraphPageClassKey =
|
||||
@@ -136,7 +138,7 @@ export const CatalogGraphPage = (
|
||||
initialState,
|
||||
entityFilter,
|
||||
} = props;
|
||||
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
const navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
const catalogEntityRoute = useRouteRef(entityRouteRef);
|
||||
@@ -192,7 +194,7 @@ export const CatalogGraphPage = (
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header
|
||||
title="Catalog Graph"
|
||||
title={t('catalogGraphPage.title')}
|
||||
subtitle={rootEntityNames.map(e => humanizeEntityRef(e)).join(', ')}
|
||||
/>
|
||||
<Content stretch className={classes.content}>
|
||||
@@ -203,13 +205,12 @@ export const CatalogGraphPage = (
|
||||
selected={showFilters}
|
||||
onChange={() => toggleShowFilters()}
|
||||
>
|
||||
<FilterListIcon /> Filters
|
||||
<FilterListIcon /> {t('catalogGraphPage.filterToggleButtonTitle')}
|
||||
</ToggleButton>
|
||||
}
|
||||
>
|
||||
<SupportButton>
|
||||
Start tracking your component in by adding it to the software
|
||||
catalog.
|
||||
{t('catalogGraphPage.supportButtonDescription')}
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<Grid container alignItems="stretch" className={classes.container}>
|
||||
@@ -230,12 +231,12 @@ export const CatalogGraphPage = (
|
||||
<SwitchFilter
|
||||
value={unidirectional}
|
||||
onChange={setUnidirectional}
|
||||
label="Simplified"
|
||||
label={t('catalogGraphPage.simplifiedSwitchLabel')}
|
||||
/>
|
||||
<SwitchFilter
|
||||
value={mergeRelations}
|
||||
onChange={setMergeRelations}
|
||||
label="Merge Relations"
|
||||
label={t('catalogGraphPage.mergeRelationsSwitchLabel')}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
@@ -247,9 +248,8 @@ export const CatalogGraphPage = (
|
||||
display="block"
|
||||
className={classes.legend}
|
||||
>
|
||||
<ZoomOutMap className="icon" /> Use pinch & zoom to move
|
||||
around the diagram. Click to change active node, shift click to
|
||||
navigate to entity.
|
||||
<ZoomOutMap className="icon" />{' '}
|
||||
{t('catalogGraphPage.zoomOutDescription')}
|
||||
</Typography>
|
||||
<EntityRelationsGraph
|
||||
{...props}
|
||||
|
||||
@@ -14,21 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, waitFor, screen, within } from '@testing-library/react';
|
||||
import { waitFor, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { CurveFilter } from './CurveFilter';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('<CurveFilter/>', () => {
|
||||
test('should display current curve label', () => {
|
||||
test('should display current curve label', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(<CurveFilter value="curveMonotoneX" onChange={onChange} />);
|
||||
await renderInTestApp(
|
||||
<CurveFilter value="curveMonotoneX" onChange={onChange} />,
|
||||
);
|
||||
|
||||
expect(screen.getByText('Monotone X')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should select an alternative curve factory', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(<CurveFilter value="curveStepBefore" onChange={onChange} />);
|
||||
await renderInTestApp(
|
||||
<CurveFilter value="curveStepBefore" onChange={onChange} />,
|
||||
);
|
||||
|
||||
expect(screen.getByText('Step Before')).toBeInTheDocument();
|
||||
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
import { Select, SelectedItems } from '@backstage/core-components';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { useCallback } from 'react';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
type Curve = 'curveStepBefore' | 'curveMonotoneX';
|
||||
const CURVE_DISPLAY_NAMES: Record<Curve, string> = {
|
||||
curveMonotoneX: 'Monotone X',
|
||||
curveStepBefore: 'Step Before',
|
||||
};
|
||||
|
||||
export type Props = {
|
||||
value: Curve;
|
||||
@@ -31,6 +29,12 @@ export type Props = {
|
||||
const curves: Array<Curve> = ['curveMonotoneX', 'curveStepBefore'];
|
||||
|
||||
export const CurveFilter = ({ value, onChange }: Props) => {
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
const CURVE_DISPLAY_NAMES: Record<Curve, string> = {
|
||||
curveMonotoneX: t('catalogGraphPage.curveFilter.curveMonotoneX'),
|
||||
curveStepBefore: t('catalogGraphPage.curveFilter.curveStepBefore'),
|
||||
};
|
||||
|
||||
const handleChange = useCallback(
|
||||
(v: SelectedItems) => onChange(v as Curve),
|
||||
[onChange],
|
||||
@@ -39,7 +43,7 @@ export const CurveFilter = ({ value, onChange }: Props) => {
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Select
|
||||
label="Curve"
|
||||
label={t('catalogGraphPage.curveFilter.title')}
|
||||
selected={value}
|
||||
items={curves.map(v => ({
|
||||
label: CURVE_DISPLAY_NAMES[v],
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, waitFor, screen, within } from '@testing-library/react';
|
||||
import { waitFor, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { Direction } from '../EntityRelationsGraph';
|
||||
import { DirectionFilter } from './DirectionFilter';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('<DirectionFilter/>', () => {
|
||||
test('should display current value', () => {
|
||||
render(
|
||||
test('should display current value', async () => {
|
||||
await renderInTestApp(
|
||||
<DirectionFilter value={Direction.LEFT_RIGHT} onChange={() => {}} />,
|
||||
);
|
||||
|
||||
@@ -30,7 +31,7 @@ describe('<DirectionFilter/>', () => {
|
||||
|
||||
test('should select direction', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
await renderInTestApp(
|
||||
<DirectionFilter value={Direction.RIGHT_LEFT} onChange={onChange} />,
|
||||
);
|
||||
|
||||
|
||||
@@ -17,13 +17,8 @@ import { Select, SelectedItems } from '@backstage/core-components';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { useCallback } from 'react';
|
||||
import { Direction } from '../EntityRelationsGraph';
|
||||
|
||||
const DIRECTION_DISPLAY_NAMES = {
|
||||
[Direction.LEFT_RIGHT]: 'Left to right',
|
||||
[Direction.RIGHT_LEFT]: 'Right to left',
|
||||
[Direction.TOP_BOTTOM]: 'Top to bottom',
|
||||
[Direction.BOTTOM_TOP]: 'Bottom to top',
|
||||
};
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
|
||||
export type Props = {
|
||||
value: Direction;
|
||||
@@ -31,6 +26,13 @@ export type Props = {
|
||||
};
|
||||
|
||||
export const DirectionFilter = ({ value, onChange }: Props) => {
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
const DIRECTION_DISPLAY_NAMES = {
|
||||
[Direction.LEFT_RIGHT]: t('catalogGraphPage.directionFilter.leftToRight'),
|
||||
[Direction.RIGHT_LEFT]: t('catalogGraphPage.directionFilter.rightToLeft'),
|
||||
[Direction.TOP_BOTTOM]: t('catalogGraphPage.directionFilter.topToBottom'),
|
||||
[Direction.BOTTOM_TOP]: t('catalogGraphPage.directionFilter.bottomToTop'),
|
||||
};
|
||||
const handleChange = useCallback(
|
||||
(v: SelectedItems) => onChange(v as Direction),
|
||||
[onChange],
|
||||
@@ -39,7 +41,7 @@ export const DirectionFilter = ({ value, onChange }: Props) => {
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Select
|
||||
label="Direction"
|
||||
label={t('catalogGraphPage.directionFilter.title')}
|
||||
selected={value}
|
||||
items={Object.values(Direction).map(v => ({
|
||||
label: DIRECTION_DISPLAY_NAMES[v],
|
||||
|
||||
@@ -14,20 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import user from '@testing-library/user-event';
|
||||
import { MaxDepthFilter } from './MaxDepthFilter';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('<MaxDepthFilter/>', () => {
|
||||
test('should display current value', () => {
|
||||
render(<MaxDepthFilter value={5} onChange={() => {}} />);
|
||||
test('should display current value', async () => {
|
||||
await renderInTestApp(<MaxDepthFilter value={5} onChange={() => {}} />);
|
||||
|
||||
expect(screen.getByLabelText('maxp')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('maxp')).toHaveValue(5);
|
||||
});
|
||||
|
||||
test('should display infinite if non finite', () => {
|
||||
render(
|
||||
test('should display infinite if non finite', async () => {
|
||||
await renderInTestApp(
|
||||
<MaxDepthFilter value={Number.POSITIVE_INFINITY} onChange={() => {}} />,
|
||||
);
|
||||
|
||||
@@ -37,7 +38,7 @@ describe('<MaxDepthFilter/>', () => {
|
||||
|
||||
test('should clear max depth', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(<MaxDepthFilter value={10} onChange={onChange} />);
|
||||
await renderInTestApp(<MaxDepthFilter value={10} onChange={onChange} />);
|
||||
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
await user.click(screen.getByLabelText('clear max depth'));
|
||||
@@ -46,7 +47,7 @@ describe('<MaxDepthFilter/>', () => {
|
||||
|
||||
test('should set max depth to undefined if below one', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(<MaxDepthFilter value={1} onChange={onChange} />);
|
||||
await renderInTestApp(<MaxDepthFilter value={1} onChange={onChange} />);
|
||||
|
||||
await user.clear(screen.getByLabelText('maxp'));
|
||||
await user.type(screen.getByLabelText('maxp'), '0');
|
||||
@@ -56,7 +57,7 @@ describe('<MaxDepthFilter/>', () => {
|
||||
|
||||
test('should select direction', async () => {
|
||||
let value = 5;
|
||||
render(
|
||||
await renderInTestApp(
|
||||
<MaxDepthFilter
|
||||
value={value}
|
||||
onChange={v => {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
@@ -22,6 +23,7 @@ import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ClearIcon from '@material-ui/icons/Clear';
|
||||
import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
|
||||
export type Props = {
|
||||
value: number;
|
||||
@@ -45,6 +47,7 @@ export const MaxDepthFilter = ({ value, onChange }: Props) => {
|
||||
const classes = useStyles();
|
||||
const onChangeRef = useRef(onChange);
|
||||
const [currentValue, setCurrentValue] = useState(value);
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
|
||||
// Keep a fresh reference to the latest callback
|
||||
useEffect(() => {
|
||||
@@ -75,16 +78,20 @@ export const MaxDepthFilter = ({ value, onChange }: Props) => {
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<FormControl variant="outlined" className={classes.formControl}>
|
||||
<Typography variant="button">Max Depth</Typography>
|
||||
<Typography variant="button">
|
||||
{t('catalogGraphPage.maxDepthFilter.title')}
|
||||
</Typography>
|
||||
<OutlinedInput
|
||||
type="number"
|
||||
placeholder="∞ Infinite"
|
||||
placeholder={t('catalogGraphPage.maxDepthFilter.inputPlaceholder')}
|
||||
value={Number.isFinite(currentValue) ? String(currentValue) : ''}
|
||||
onChange={handleChange}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
aria-label="clear max depth"
|
||||
aria-label={t(
|
||||
'catalogGraphPage.maxDepthFilter.clearButtonAriaLabel',
|
||||
)}
|
||||
onClick={reset}
|
||||
edge="end"
|
||||
>
|
||||
|
||||
@@ -15,13 +15,18 @@
|
||||
*/
|
||||
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { AlertApi, alertApiRef } from '@backstage/core-plugin-api';
|
||||
import { AlertApi, alertApiRef, errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils';
|
||||
import {
|
||||
mockApis,
|
||||
renderWithEffects,
|
||||
TestApiRegistry,
|
||||
} from '@backstage/test-utils';
|
||||
import { waitFor, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { SelectedKindsFilter } from './SelectedKindsFilter';
|
||||
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
|
||||
import { translationApiRef } from '@backstage/core-plugin-api/alpha';
|
||||
|
||||
const catalogApi = catalogApiMock.mock({
|
||||
getEntityFacets: jest.fn().mockResolvedValue({
|
||||
@@ -38,6 +43,8 @@ const catalogApi = catalogApiMock.mock({
|
||||
const apis = TestApiRegistry.from(
|
||||
[catalogApiRef, catalogApi],
|
||||
[alertApiRef, {} as AlertApi],
|
||||
[translationApiRef, mockApis.translation()],
|
||||
[errorApiRef, { post: jest.fn() }],
|
||||
);
|
||||
|
||||
describe('<SelectedKindsFilter/>', () => {
|
||||
|
||||
@@ -27,6 +27,8 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import useAsync from 'react-use/esm/useAsync';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export type SelectedKindsFilterClassKey = 'formControl';
|
||||
@@ -49,6 +51,7 @@ export const SelectedKindsFilter = ({ value, onChange }: Props) => {
|
||||
const classes = useStyles();
|
||||
const alertApi = useApi(alertApiRef);
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
|
||||
const { error, value: kinds } = useAsync(async () => {
|
||||
return await catalogApi
|
||||
@@ -91,13 +94,15 @@ export const SelectedKindsFilter = ({ value, onChange }: Props) => {
|
||||
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Typography variant="button">Kinds</Typography>
|
||||
<Typography variant="button">
|
||||
{t('catalogGraphPage.selectedKindsFilter.title')}
|
||||
</Typography>
|
||||
<Autocomplete
|
||||
className={classes.formControl}
|
||||
multiple
|
||||
limitTags={4}
|
||||
disableCloseOnSelect
|
||||
aria-label="Kinds"
|
||||
aria-label={t('catalogGraphPage.selectedKindsFilter.title')}
|
||||
options={normalizedKinds}
|
||||
value={value ?? normalizedKinds}
|
||||
getOptionLabel={k => kinds[normalizedKinds.indexOf(k)] ?? k}
|
||||
|
||||
+7
-6
@@ -19,14 +19,15 @@ import {
|
||||
RELATION_HAS_MEMBER,
|
||||
RELATION_OWNED_BY,
|
||||
} from '@backstage/catalog-model';
|
||||
import { render, waitFor, screen } from '@testing-library/react';
|
||||
import { waitFor, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { ALL_RELATION_PAIRS } from '../EntityRelationsGraph';
|
||||
import { SelectedRelationsFilter } from './SelectedRelationsFilter';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('<SelectedRelationsFilter/>', () => {
|
||||
test('should render current value', () => {
|
||||
render(
|
||||
test('should render current value', async () => {
|
||||
await renderInTestApp(
|
||||
<SelectedRelationsFilter
|
||||
relationPairs={ALL_RELATION_PAIRS}
|
||||
value={[RELATION_OWNED_BY, RELATION_CHILD_OF]}
|
||||
@@ -40,7 +41,7 @@ describe('<SelectedRelationsFilter/>', () => {
|
||||
|
||||
test('should select value', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
await renderInTestApp(
|
||||
<SelectedRelationsFilter
|
||||
relationPairs={ALL_RELATION_PAIRS}
|
||||
value={[RELATION_OWNED_BY, RELATION_CHILD_OF]}
|
||||
@@ -67,7 +68,7 @@ describe('<SelectedRelationsFilter/>', () => {
|
||||
|
||||
test('should return undefined if all values are selected', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
await renderInTestApp(
|
||||
<SelectedRelationsFilter
|
||||
relationPairs={ALL_RELATION_PAIRS}
|
||||
value={ALL_RELATION_PAIRS.flatMap(p => p).filter(
|
||||
@@ -92,7 +93,7 @@ describe('<SelectedRelationsFilter/>', () => {
|
||||
|
||||
test('should return all values when cleared', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
await renderInTestApp(
|
||||
<SelectedRelationsFilter
|
||||
relationPairs={ALL_RELATION_PAIRS}
|
||||
value={[]}
|
||||
|
||||
@@ -25,6 +25,8 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { RelationPairs } from '../EntityRelationsGraph';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { catalogGraphTranslationRef } from '../../translation';
|
||||
|
||||
/** @public */
|
||||
export type SelectedRelationsFilterClassKey = 'formControl';
|
||||
@@ -51,6 +53,7 @@ export const SelectedRelationsFilter = ({
|
||||
}: Props) => {
|
||||
const classes = useStyles();
|
||||
const relations = useMemo(() => relationPairs.flat(), [relationPairs]);
|
||||
const { t } = useTranslationRef(catalogGraphTranslationRef);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(_: unknown, v: string[]) => {
|
||||
@@ -65,13 +68,15 @@ export const SelectedRelationsFilter = ({
|
||||
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Typography variant="button">Relations</Typography>
|
||||
<Typography variant="button">
|
||||
{t('catalogGraphPage.selectedRelationsFilter.title')}
|
||||
</Typography>
|
||||
<Autocomplete
|
||||
className={classes.formControl}
|
||||
multiple
|
||||
limitTags={4}
|
||||
disableCloseOnSelect
|
||||
aria-label="Relations"
|
||||
aria-label={t('catalogGraphPage.selectedRelationsFilter.title')}
|
||||
options={relations}
|
||||
value={value ?? relations}
|
||||
onChange={handleChange}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
/** @alpha */
|
||||
export const catalogGraphTranslationRef = createTranslationRef({
|
||||
id: 'catalog-graph',
|
||||
messages: {
|
||||
catalogGraphCard: {
|
||||
title: 'Relations',
|
||||
deepLinkTitle: 'View graph',
|
||||
},
|
||||
catalogGraphPage: {
|
||||
title: 'Catalog Graph',
|
||||
filterToggleButtonTitle: 'Filters',
|
||||
supportButtonDescription:
|
||||
'Start tracking your component in by adding it to the software catalog.',
|
||||
simplifiedSwitchLabel: 'Simplified',
|
||||
mergeRelationsSwitchLabel: 'Merge relations',
|
||||
zoomOutDescription:
|
||||
'Use pinch & zoom to move around the diagram. Click to change active node, shift click to navigate to entity.',
|
||||
curveFilter: {
|
||||
title: 'Curve',
|
||||
curveMonotoneX: 'Monotone X',
|
||||
curveStepBefore: 'Step Before',
|
||||
},
|
||||
directionFilter: {
|
||||
title: 'Direction',
|
||||
leftToRight: 'Left to right',
|
||||
rightToLeft: 'Right to left',
|
||||
topToBottom: 'Top to bottom',
|
||||
bottomToTop: 'Bottom to top',
|
||||
},
|
||||
maxDepthFilter: {
|
||||
title: 'Max depth',
|
||||
inputPlaceholder: '∞ Infinite',
|
||||
clearButtonAriaLabel: 'clear max depth',
|
||||
},
|
||||
selectedKindsFilter: {
|
||||
title: 'Kinds',
|
||||
},
|
||||
selectedRelationsFilter: {
|
||||
title: 'Relations',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -130,7 +130,7 @@ export const StepInitAnalyzeUrl = (props: StepInitAnalyzeUrlProps) => {
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
setError(e?.data?.error?.message ?? e.message);
|
||||
setError(e?.body?.error?.message ?? e.message);
|
||||
setSubmitted(false);
|
||||
}
|
||||
},
|
||||
|
||||
+59
-600
File diff suppressed because it is too large
Load Diff
@@ -11251,14 +11251,14 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@keyv/redis@npm:^4.0.1":
|
||||
version: 4.4.0
|
||||
resolution: "@keyv/redis@npm:4.4.0"
|
||||
version: 4.4.1
|
||||
resolution: "@keyv/redis@npm:4.4.1"
|
||||
dependencies:
|
||||
"@redis/client": "npm:^1.6.0"
|
||||
cluster-key-slot: "npm:^1.1.2"
|
||||
peerDependencies:
|
||||
keyv: ^5.3.3
|
||||
checksum: 10/61ad0a026f1ee8bbd0f09bb1b3c731619b37dc4bba0d5f2111cb5249e643e6a776816786090c53d5ac1fa62a43e1b43d406dae06cfb119abcb47b6ac837eebb0
|
||||
keyv: ^5.3.4
|
||||
checksum: 10/85bf5830d5a19f45fbba864f7eb830cff0059f3f7c59c711a65b439821008a3321a94fb06c4d1f09295f0f233422586458652d266696c0925b5c8d1d695700ec
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -11272,11 +11272,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@keyv/valkey@npm:^1.0.1":
|
||||
version: 1.0.4
|
||||
resolution: "@keyv/valkey@npm:1.0.4"
|
||||
version: 1.0.6
|
||||
resolution: "@keyv/valkey@npm:1.0.6"
|
||||
dependencies:
|
||||
iovalkey: "npm:^0.3.1"
|
||||
checksum: 10/93362c51c14bb8e515a9af8df4a22e028fcec5a09931eb68f854698676cb16cecad691330c75c1dca8b6a986a4763cac9f1b2fd4e5b8216f06648d9379f55cc6
|
||||
iovalkey: "npm:^0.3.3"
|
||||
checksum: 10/36e48930928845e6a14dfb4f9f8069851ff10d3aeef62277f78c8dcea735f8dca5faf4399f67fc2730231b24270d9ab6be77a46e122e9006d3f6e55cc5c0b97a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -21406,19 +21406,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/express-serve-static-core@npm:*":
|
||||
version: 5.0.0
|
||||
resolution: "@types/express-serve-static-core@npm:5.0.0"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
"@types/qs": "npm:*"
|
||||
"@types/range-parser": "npm:*"
|
||||
"@types/send": "npm:*"
|
||||
checksum: 10/fc40cdeae61113d8b2335f4b0f9334a7a64388a0931f2e98f8fc9bdadd0b13b501a70da14c256ae4aa140db49bd2eff75a99a683266d561e62540784a61dc489
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/express-serve-static-core@npm:^4.17.21, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5":
|
||||
"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.21, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5":
|
||||
version: 4.19.6
|
||||
resolution: "@types/express-serve-static-core@npm:4.19.6"
|
||||
dependencies:
|
||||
@@ -21440,14 +21428,14 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@types/express@npm:*, @types/express@npm:^4.16.1, @types/express@npm:^4.17.21, @types/express@npm:^4.17.6":
|
||||
version: 4.17.21
|
||||
resolution: "@types/express@npm:4.17.21"
|
||||
version: 4.17.23
|
||||
resolution: "@types/express@npm:4.17.23"
|
||||
dependencies:
|
||||
"@types/body-parser": "npm:*"
|
||||
"@types/express-serve-static-core": "npm:^4.17.33"
|
||||
"@types/qs": "npm:*"
|
||||
"@types/serve-static": "npm:*"
|
||||
checksum: 10/7a6d26cf6f43d3151caf4fec66ea11c9d23166e4f3102edfe45a94170654a54ea08cf3103d26b3928d7ebcc24162c90488e33986b7e3a5f8941225edd5eb18c7
|
||||
checksum: 10/cf4d540bbd90801cdc79a46107b8873404698a7fd0c3e8dd42989d52d3bd7f5b8768672e54c20835e41e27349c319bb47a404ad14c0f8db0e9d055ba1cb8a05b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -24384,13 +24372,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"GendocuPublicApis@https://git.gendocu.com/gendocu/GendocuPublicApis.git#master":
|
||||
version: 1.0.0
|
||||
resolution: "GendocuPublicApis@https://git.gendocu.com/gendocu/GendocuPublicApis.git#commit=6e8d4c1d2342556a2e8e719f19385b266001ebae"
|
||||
"GendocuPublicApis@npm:gendocu-public-apis@^1.0.0":
|
||||
version: 1.0.3
|
||||
resolution: "gendocu-public-apis@npm:1.0.3"
|
||||
dependencies:
|
||||
"@improbable-eng/grpc-web": "npm:^0.14.0"
|
||||
google-protobuf: "npm:^3.15.8"
|
||||
checksum: 10/a34386a6137d92f392121305fb899f63ba1631a1b60c80781f6e56e160c1d462a8ce4b3ee93cb67c73c079b53c6de57ba19f514f29dd11c9783cd0d8227c6968
|
||||
checksum: 10/261a5cc97b599a7dfb492ac048e6bfce3f3bf64627f2b80ef195d5b6cefdbd4668d2b2ccd10676f01eb4f7862a5d19da567dd6ade9fc39a15268e81862308f7c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -31221,11 +31209,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"express-rate-limit@npm:^7.5.0":
|
||||
version: 7.5.0
|
||||
resolution: "express-rate-limit@npm:7.5.0"
|
||||
version: 7.5.1
|
||||
resolution: "express-rate-limit@npm:7.5.1"
|
||||
peerDependencies:
|
||||
express: ^4.11 || 5 || ^5.0.0-beta.1
|
||||
checksum: 10/eff34c83bf586789933a332a339b66649e2cca95c8e977d193aa8bead577d3182ac9f0e9c26f39389287539b8038890ff023f910b54ebb506a26a2ce135b92ca
|
||||
express: ">= 4.11"
|
||||
checksum: 10/357c3398450144ab7bbce2841d0bf4f93a0f3fd9d1d5ed9a0ee331b557af969cc790941dc37b47f8d9b5672964aa0e31666f770e1f48b334dc7d1e69f6433040
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -34282,9 +34270,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iovalkey@npm:^0.3.1":
|
||||
version: 0.3.1
|
||||
resolution: "iovalkey@npm:0.3.1"
|
||||
"iovalkey@npm:^0.3.3":
|
||||
version: 0.3.3
|
||||
resolution: "iovalkey@npm:0.3.3"
|
||||
dependencies:
|
||||
"@iovalkey/commands": "npm:^0.1.0"
|
||||
cluster-key-slot: "npm:^1.1.0"
|
||||
@@ -34295,7 +34283,7 @@ __metadata:
|
||||
redis-errors: "npm:^1.2.0"
|
||||
redis-parser: "npm:^3.0.0"
|
||||
standard-as-callback: "npm:^2.1.0"
|
||||
checksum: 10/afe5e0218810d902263dca2b22dd4501fb74698111f1850804d0948bd6a97793a7f5006757f9b6e8c8131bac6bd532d07ad971e7776bed7f6dc1f6e471706c53
|
||||
checksum: 10/39368842e6a9dbc85e92dfcd4c1c917a76240bac5c4210e19a0bd3bc7984af9b567dce5de7c560c4517d5d4cb03af229f38582c1dd055c6fd452060774318e8c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user