├── .nvmrc ├── src ├── components │ ├── cc-button │ │ └── cc-button.types.d.ts │ ├── cc-product-card │ │ └── cc-product-card.types.d.ts │ ├── cc-datetime-relative │ │ └── cc-datetime-relative.types.d.ts │ ├── cc-icon │ │ └── cc-icon.types.d.ts │ ├── cc-overview │ │ └── cc-overview.types.d.ts │ ├── cc-block │ │ └── cc-block.types.d.ts │ ├── cc-env-var-input │ │ ├── cc-env-var-input.types.d.ts │ │ └── cc-env-var-input.events.js │ ├── cc-notice │ │ ├── cc-notice.types.d.ts │ │ └── cc-notice.events.js │ ├── cc-picker-option │ │ └── cc-picker-option.types.d.ts │ ├── cc-select │ │ └── cc-select.types.d.ts │ ├── cc-beta │ │ └── cc-beta.types.d.ts │ ├── cc-map-marker-server │ │ ├── cc-map-marker-server.types.d.ts │ │ └── cc-map-marker-server.stories.js │ ├── cc-popover │ │ └── cc-popover.types.d.ts │ ├── cc-logs │ │ ├── date-display.types.d.ts │ │ ├── cc-logs.events.js │ │ ├── cc-logs.types.d.ts │ │ └── animation-runner.js │ ├── cc-toggle │ │ └── cc-toggle.types.d.ts │ ├── cc-logsmap │ │ ├── cc-logsmap.types.d.ts │ │ └── cc-logsmap.events.js │ ├── cc-picker │ │ └── cc-picker.types.d.ts │ ├── cc-badge │ │ └── cc-badge.types.d.ts │ ├── cc-logs-app-access │ │ └── cc-logs-app-access.types.d.ts │ ├── cc-logs-addon-runtime │ │ └── cc-logs-addon-runtime.types.d.ts │ ├── cc-logs-message-filter │ │ ├── cc-logs-message-filter.types.d.ts │ │ └── cc-logs-message-filter.events.js │ ├── cc-warning-payment │ │ └── cc-warning-payment.types.d.ts │ ├── cc-html-frame │ │ └── cc-html-frame.types.d.ts │ ├── cc-addon-credentials │ │ └── cc-addon-credentials.types.d.ts │ ├── cc-pricing-page │ │ └── cc-pricing-page.types.d.ts │ ├── cc-toast │ │ └── cc-toast.events.js │ ├── cc-zone │ │ └── cc-zone.types.d.ts │ ├── cc-invoice-table │ │ └── cc-invoice-table.types.d.ts │ ├── cc-order-summary │ │ ├── cc-order-summary.events.js │ │ └── cc-order-summary.types.d.ts │ ├── cc-doc-card │ │ └── cc-doc-card.types.d.ts │ ├── cc-input-text │ │ └── cc-input-text.events.js │ ├── cc-doc-list │ │ └── cc-doc-list.types.d.ts │ ├── cc-input-date │ │ └── cc-input-date.types.d.ts │ ├── cc-addon-option │ │ └── cc-addon-option.events.js │ ├── cc-product-list │ │ └── cc-product-list.types.d.ts │ ├── cc-article-card │ │ └── cc-article-card.types.d.ts │ ├── cc-addon-info │ │ └── cc-addon-info.events.js │ ├── cc-invoice-list │ │ ├── cc-invoice-list.types.d.ts │ │ └── cc-invoice-list.smart.js │ ├── cc-matomo-info │ │ └── cc-matomo-info.types.d.ts │ ├── cc-pricing-header │ │ └── cc-pricing-header.types.d.ts │ ├── cc-header-orga │ │ └── cc-header-orga.types.d.ts │ ├── cc-kv-string-editor │ │ ├── cc-kv-string-editor.events.js │ │ └── cc-kv-string-editor.types.d.ts │ ├── cc-env-var-create │ │ ├── cc-env-var-create.events.js │ │ └── cc-env-var-create.stories.js │ ├── cc-article-list │ │ └── cc-article-list.types.d.ts │ ├── cc-tile-scalability │ │ └── cc-tile-scalability.types.d.ts │ ├── cc-logs-instances │ │ ├── cc-logs-instances.events.js │ │ └── cc-logs-instances.types.d.ts │ ├── cc-map │ │ ├── cc-map.types.d.ts │ │ └── cc-map.events.js │ ├── cc-feature-list │ │ ├── cc-feature-list.events.js │ │ └── cc-feature-list.types.d.ts │ ├── cc-pricing-product │ │ └── cc-pricing-product.types.d.ts │ ├── cc-token-api-creation-form │ │ └── cc-token-api-creation-form.events.js │ ├── cc-invoice │ │ └── cc-invoice.types.d.ts │ ├── cc-jenkins-info │ │ └── cc-jenkins-info.types.d.ts │ ├── cc-tile-instances │ │ └── cc-tile-instances.types.d.ts │ ├── cc-addon-option-form │ │ └── cc-addon-option-form.events.js │ ├── cc-plan-picker │ │ └── cc-plan-picker.types.d.ts │ ├── cc-tile-deployments │ │ └── cc-tile-deployments.types.d.ts │ ├── cc-logs-control │ │ ├── cc-logs-control.events.js │ │ └── cc-logs-control.types.d.ts │ ├── cc-clipboard │ │ └── cc-clipboard.stories.js │ ├── cc-zone-picker │ │ └── cc-zone-picker.types.d.ts │ ├── cc-addon-header │ │ └── cc-addon-header.events.js │ ├── cc-header-app │ │ ├── cc-header-app.types.d.ts │ │ └── cc-header-app.events.js │ ├── cc-addon-credentials-content │ │ ├── cc-addon-credentials-content.events.js │ │ └── cc-addon-credentials-content.types.d.ts │ ├── cc-toaster │ │ └── cc-toaster.types.d.ts │ ├── cc-addon-features │ │ └── cc-addon-features.types.d.ts │ ├── cc-addon-linked-apps │ │ └── cc-addon-linked-apps.types.d.ts │ ├── cc-logs-date-range-selector │ │ ├── cc-logs-date-range-selector.events.js │ │ ├── cc-logs-date-range-selector.types.d.ts │ │ └── date-range-selection.js │ ├── cc-heptapod-info │ │ └── cc-heptapod-info.types.d.ts │ ├── cc-tile-requests │ │ └── cc-tile-requests.types.d.ts │ ├── cc-addon-mysql-options │ │ └── cc-addon-mysql-options.stories.js │ ├── cc-addon-redis-options │ │ └── cc-addon-redis-options.stories.js │ ├── cc-visual-tests-report-menu │ │ ├── cc-visual-tests-report-menu.types.d.ts │ │ └── cc-visual-tests-report-menu.stories.js │ ├── cc-env-var-linked-services │ │ └── cc-env-var-linked-services.types.d.ts │ ├── cc-addon-jenkins-options │ │ └── cc-addon-jenkins-options.stories.js │ ├── cc-addon-mongodb-options │ │ └── cc-addon-mongodb-options.stories.js │ ├── cc-elasticsearch-info │ │ └── cc-elasticsearch-info.types.d.ts │ ├── cc-grafana-info │ │ ├── cc-grafana-info.events.js │ │ └── cc-grafana-info.types.d.ts │ ├── cc-addon-postgresql-options │ │ └── cc-addon-postgresql-options.stories.js │ ├── cc-tcp-redirection-form │ │ └── cc-tcp-redirection-form.types.d.ts │ ├── cc-logs-app-runtime │ │ └── cc-logs-app-runtime.types.d.ts │ ├── cc-tcp-redirection │ │ ├── cc-tcp-redirection.types.d.ts │ │ └── cc-tcp-redirection.events.js │ ├── cc-header-addon │ │ └── cc-header-addon.types.d.ts │ ├── cc-token-api-update-form │ │ ├── cc-token-api-update-form.types.d.ts │ │ └── cc-token-api-update-form.events.js │ ├── cc-pricing-product-consumption │ │ └── cc-pricing-product-consumption.types.d.ts │ ├── cc-code │ │ └── cc-code.stories.js │ ├── cc-kv-terminal │ │ ├── cc-kv-terminal.events.js │ │ └── cc-kv-terminal.types.d.ts │ ├── cc-orga-member-list │ │ ├── cc-orga-member-list.types.d.ts │ │ └── cc-orga-member-list.events.js │ ├── cc-pricing-estimation │ │ └── cc-pricing-estimation.types.d.ts │ ├── cc-addon-backups │ │ └── cc-addon-backups.types.d.ts │ ├── cc-env-var-form │ │ ├── cc-env-var-form.types.d.ts │ │ └── cc-env-var-form.events.js │ ├── cc-logs-loading-progress │ │ ├── cc-logs-loading-progress.types.d.ts │ │ └── cc-logs-loading-progress.events.js │ ├── cc-zone-input │ │ └── cc-zone-input.types.d.ts │ ├── cc-addon-admin │ │ └── cc-addon-admin.types.d.ts │ ├── cc-visual-tests-report │ │ └── visual-tests-report.types.d.ts │ ├── cc-token-oauth-list │ │ └── cc-token-oauth-list.types.d.ts │ ├── cc-email-list │ │ └── cc-email-list.types.d.ts │ ├── cc-kv-explorer │ │ └── cc-kv-explorer.smart.md │ ├── cc-ssh-key-list │ │ └── cc-ssh-key-list.events.js │ ├── cc-kv-list-input │ │ └── cc-kv-list-input.stories.js │ ├── cc-token-api-list │ │ └── cc-token-api-list.types.d.ts │ ├── cc-visual-tests-report-entry │ │ └── cc-visual-tests-report-entry.stories.js │ └── cc-kv-set-explorer │ │ └── cc-kv-set-explorer.events.js ├── stories │ ├── assets │ │ ├── console.png │ │ ├── cc-domain-management-empty-mobile-diff.png │ │ ├── cc-article-list-data-loaded-desktop-diff.png │ │ ├── cc-article-list-default-story-mobile-diff.png │ │ ├── cc-domain-management-empty-desktop-actual.png │ │ ├── cc-domain-management-empty-desktop-diff.png │ │ ├── cc-domain-management-empty-mobile-actual.png │ │ ├── cc-addon-backups-default-story-desktop-diff.png │ │ ├── cc-addon-backups-default-story-mobile-diff.png │ │ ├── cc-article-list-data-loaded-desktop-actual.png │ │ ├── cc-article-list-default-story-mobile-actual.png │ │ ├── cc-addon-backups-default-story-desktop-actual.png │ │ ├── cc-addon-backups-default-story-mobile-actual.png │ │ ├── cc-domain-management-default-story-mobile-diff.png │ │ ├── cc-domain-management-empty-desktop-expectation.png │ │ ├── cc-domain-management-empty-mobile-expectation.png │ │ ├── cc-article-list-data-loaded-desktop-expectation.png │ │ ├── cc-article-list-default-story-mobile-expectation.png │ │ ├── cc-domain-management-default-story-desktop-diff.png │ │ ├── cc-domain-management-default-story-mobile-actual.png │ │ ├── cc-addon-backups-default-story-desktop-expectation.png │ │ ├── cc-addon-backups-default-story-mobile-expectation.png │ │ ├── cc-domain-management-default-story-desktop-actual.png │ │ ├── cc-domain-management-default-story-mobile-expectation.png │ │ ├── cc-domain-management-default-story-desktop-expectation.png │ │ ├── oracle.svg │ │ ├── ovh.svg │ │ ├── italic.svg │ │ ├── underline.svg │ │ ├── warning.svg │ │ ├── scaleway.svg │ │ ├── left.svg │ │ ├── right.svg │ │ ├── justify.svg │ │ └── center.svg │ ├── lib │ │ ├── sequence.js │ │ ├── dom.js │ │ ├── timers.js │ │ ├── autodocs-template.jsx │ │ └── i18n-control.js │ └── fixtures │ │ └── fake-map-data.js ├── lib │ ├── leaflet │ │ ├── tsconfig-empty.json │ │ └── leaflet-esm.js │ ├── date │ │ ├── date-range.types.d.ts │ │ └── date.types.d.ts │ ├── color.types.d.ts │ ├── smart │ │ └── smart-symbols.js │ ├── pricing.types.d.ts │ ├── immer.js │ ├── send-to-api.events.js │ ├── tokens.types.d.ts │ ├── assets-url.js │ ├── events.types.d.ts │ ├── css-custom-properties.js │ ├── ansi │ │ ├── ansi-palette-style.js │ │ ├── ansi.types.d.ts │ │ └── palettes │ │ │ ├── hyoob.js │ │ │ ├── default.js │ │ │ ├── everblush.js │ │ │ ├── night-owl.js │ │ │ ├── one-light.js │ │ │ └── tokyo-night-light.js │ ├── form │ │ ├── validation.types.d.ts │ │ ├── form.types.d.ts │ │ ├── form-error-focus-controller.js │ │ └── form.events.js │ ├── notifications.events.js │ ├── remote-assets.js │ ├── fake-strings.js │ ├── focus-helper.js │ ├── animate.js │ ├── send-to-api.types.d.ts │ ├── i18n │ │ ├── i18n.types.d.ts │ │ ├── i18n-display.js │ │ └── i18n-string.js │ ├── regex-parse.js │ ├── notifications.js │ ├── dev-hub-url.js │ ├── dom.js │ └── zone.js ├── assets │ ├── unknown.svg │ ├── mail-line.svg │ ├── start-failed.svg │ ├── running.svg │ ├── mail-star-line.svg │ ├── restarting.svg │ ├── restart-failed.svg │ ├── baseline-widely.svg │ ├── starting.svg │ ├── arrows-left.svg │ ├── arrows-right.svg │ ├── baseline-limited.svg │ ├── git.svg │ ├── baseline-newly.svg │ ├── info.svg │ └── ram.svg ├── styles │ ├── accessibility.js │ ├── waiting.js │ ├── cli-commands.js │ ├── skeleton.js │ └── undefined-components.css ├── translations │ ├── translation.js │ └── translation.types.d.ts └── templates │ └── cc-addon-encryption-at-rest-option │ └── cc-addon-encryption-at-rest-option.js ├── test ├── helpers │ ├── global-mock-random.js │ ├── global-mock-date.js │ ├── mock-now.js │ └── story-testing-utils.types.d.ts ├── dom │ ├── dom.css │ └── dom.test.html ├── smart │ └── smart-manager.test.html └── i18n │ └── i18n-string.test.js ├── .commitlintrc ├── .githooks ├── commit-msg └── pre-push ├── .npmrc ├── custom-elements.json ├── test-mocha └── cem │ └── fixtures │ ├── common.types.d.ts │ ├── cem-test-import │ └── cc-test-imports-sub.types.d.ts │ ├── test-imports.types.d.ts │ └── cc-test-component-with-import.js ├── .gitignore ├── .prettierignore ├── cdn-ui └── cors.xml ├── sandbox ├── forms │ ├── form-demo-with-smart-component.types.d.ts │ └── form-demo-with-array-type.js └── sandbox-styles.js ├── .git-blame-ignore-revs ├── docs ├── copywriting │ └── coming-soon.md ├── guidelines │ └── coming-soon.md ├── contributing │ └── tools.md ├── getting-started │ └── manual-installation.md └── adr │ ├── adr-0004-why-wrap-input-textarea.md │ └── adr-0001-why-do-we-wrap-button-clicks.md ├── eslint ├── lit-a11y │ └── eslint-config-lit-a11y-clever-cloud.js ├── lit │ └── eslint-config-lit-clever-cloud.js ├── wc │ └── eslint-config-wc-clever-cloud.js └── i18n │ └── custom-rules │ └── i18n-valid-key.js ├── .github ├── scripts │ ├── get-stories-groups.js │ └── parse-version-from-tag.js ├── ISSUE_TEMPLATE │ └── accessibility-issue.md └── workflows │ └── release.yml ├── rollup ├── rollup-cdn.config.js ├── rollup-plugin-styles-assets.js ├── rollup-cdn-preview.config.js └── rollup-plugin-index-generator.js ├── .storybook ├── .htaccess └── manager.js ├── public └── favicon.svg ├── web-test-runner ├── cem-analyzer-plugin.js ├── wds-common.js ├── esbuild-bundle-plugin.js ├── story-file-to-a11y-tests-file-plugin.js └── visual-tests │ └── story-file-to-visual-tests-file-plugin.js ├── tasks └── cdn-entry-name.js ├── tsconfig.ci.json ├── cem ├── sort-items.js ├── remove-private-members.js ├── add-github-source-in-description.js └── add-dependencies-in-description.js ├── prettier.config.js ├── custom-elements-manifest.config.mjs └── demo-smart └── index.js /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /src/components/cc-button/cc-button.types.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-product-card/cc-product-card.types.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-datetime-relative/cc-datetime-relative.types.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/helpers/global-mock-random.js: -------------------------------------------------------------------------------- 1 | Math.random = (_) => 0.5; 2 | -------------------------------------------------------------------------------- /.commitlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /.githooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | npx --no -- commitlint --edit 4 | -------------------------------------------------------------------------------- /src/components/cc-icon/cc-icon.types.d.ts: -------------------------------------------------------------------------------- 1 | export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; 2 | -------------------------------------------------------------------------------- /src/components/cc-overview/cc-overview.types.d.ts: -------------------------------------------------------------------------------- 1 | export type OverviewModeType = 'app' | 'orga'; 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix = "" 2 | message = "Upgrade to %s" 3 | preid = "beta" 4 | loglevel = "error" 5 | -------------------------------------------------------------------------------- /custom-elements.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "readme": "", 4 | "modules": [] 5 | } 6 | -------------------------------------------------------------------------------- /src/components/cc-block/cc-block.types.d.ts: -------------------------------------------------------------------------------- 1 | export type BlockToggleState = 'off' | 'open' | 'close'; 2 | -------------------------------------------------------------------------------- /src/components/cc-env-var-input/cc-env-var-input.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface EnvVarName { 2 | name: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/cc-notice/cc-notice.types.d.ts: -------------------------------------------------------------------------------- 1 | export type NoticeIntent = 'info' | 'danger' | 'success' | 'warning'; 2 | -------------------------------------------------------------------------------- /src/components/cc-picker-option/cc-picker-option.types.d.ts: -------------------------------------------------------------------------------- 1 | export type PickerOptionSelectionStyle = 'check' | 'radio'; 2 | -------------------------------------------------------------------------------- /src/components/cc-select/cc-select.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Option { 2 | label: string; 3 | value: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/stories/assets/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/console.png -------------------------------------------------------------------------------- /src/components/cc-beta/cc-beta.types.d.ts: -------------------------------------------------------------------------------- 1 | export type PositionType = 'top-left' | 'bottom-left' | 'top-right' | 'bottom-right'; 2 | -------------------------------------------------------------------------------- /src/components/cc-map-marker-server/cc-map-marker-server.types.d.ts: -------------------------------------------------------------------------------- 1 | export type MarkerStateType = 'default' | 'hovered' | 'selected'; 2 | -------------------------------------------------------------------------------- /test-mocha/cem/fixtures/common.types.d.ts: -------------------------------------------------------------------------------- 1 | interface Common { 2 | sub: SubCommon; 3 | } 4 | 5 | interface SubCommon { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/components/cc-popover/cc-popover.types.d.ts: -------------------------------------------------------------------------------- 1 | export type PopoverPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'; 2 | -------------------------------------------------------------------------------- /src/components/cc-logs/date-display.types.d.ts: -------------------------------------------------------------------------------- 1 | export type DateDisplay = 'none' | 'datetime-iso' | 'time-iso' | 'datetime-short' | 'time-short'; 2 | -------------------------------------------------------------------------------- /src/components/cc-toggle/cc-toggle.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Choice { 2 | label: string; 3 | image?: string; // Optional URL of an image 4 | value: string; 5 | } 6 | -------------------------------------------------------------------------------- /test/dom/dom.css: -------------------------------------------------------------------------------- 1 | .big { 2 | height: 5000px; 3 | } 4 | 5 | .container { 6 | height: 250px; 7 | overflow: auto; 8 | } 9 | 10 | .item { 11 | height: 100px; 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.s3cfg 3 | .env* 4 | .preview-index.html 5 | .preview-manifest.json 6 | dist 7 | dist-cdn 8 | node_modules 9 | storybook-static 10 | visual-test-reports 11 | -------------------------------------------------------------------------------- /src/components/cc-logsmap/cc-logsmap.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface PointsOptions { 2 | spreadDuration?: boolean | number; // Spread points appearance over a time window (in ms) 3 | } 4 | -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-empty-mobile-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-empty-mobile-diff.png -------------------------------------------------------------------------------- /src/components/cc-picker/cc-picker.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface PickerOption { 2 | body: string | Node; 3 | disabled?: boolean; 4 | footer?: string | Node; 5 | value?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/leaflet/tsconfig-empty.json: -------------------------------------------------------------------------------- 1 | // prevents esbuild from bundling types instead of the actual package 2 | // because of the `paths` option within the regular `tsconfig.json` file 3 | {} 4 | -------------------------------------------------------------------------------- /src/stories/assets/cc-article-list-data-loaded-desktop-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-article-list-data-loaded-desktop-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-article-list-default-story-mobile-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-article-list-default-story-mobile-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-empty-desktop-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-empty-desktop-actual.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-empty-desktop-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-empty-desktop-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-empty-mobile-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-empty-mobile-actual.png -------------------------------------------------------------------------------- /src/assets/unknown.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-badge/cc-badge.types.d.ts: -------------------------------------------------------------------------------- 1 | export type BadgeIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger'; 2 | 3 | export type BadgeWeight = 'strong' | 'dimmed' | 'outlined'; 4 | -------------------------------------------------------------------------------- /src/stories/assets/cc-addon-backups-default-story-desktop-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-addon-backups-default-story-desktop-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-addon-backups-default-story-mobile-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-addon-backups-default-story-mobile-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-article-list-data-loaded-desktop-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-article-list-data-loaded-desktop-actual.png -------------------------------------------------------------------------------- /src/stories/assets/cc-article-list-default-story-mobile-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-article-list-default-story-mobile-actual.png -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore assets 2 | src/assets 3 | src/stories/assets 4 | 5 | # Ignore fixtures 6 | src/stories/fixtures 7 | test-mocha/cem/fixtures 8 | 9 | # Ignore MD files 10 | **/*.md 11 | -------------------------------------------------------------------------------- /src/stories/assets/cc-addon-backups-default-story-desktop-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-addon-backups-default-story-desktop-actual.png -------------------------------------------------------------------------------- /src/stories/assets/cc-addon-backups-default-story-mobile-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-addon-backups-default-story-mobile-actual.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-default-story-mobile-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-default-story-mobile-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-empty-desktop-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-empty-desktop-expectation.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-empty-mobile-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-empty-mobile-expectation.png -------------------------------------------------------------------------------- /src/lib/date/date-range.types.d.ts: -------------------------------------------------------------------------------- 1 | export type DateRange = { 2 | since: string; 3 | until?: string; 4 | }; 5 | 6 | export type RawDateRange = { 7 | since: Date; 8 | until?: Date; 9 | }; 10 | -------------------------------------------------------------------------------- /src/stories/assets/cc-article-list-data-loaded-desktop-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-article-list-data-loaded-desktop-expectation.png -------------------------------------------------------------------------------- /src/stories/assets/cc-article-list-default-story-mobile-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-article-list-default-story-mobile-expectation.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-default-story-desktop-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-default-story-desktop-diff.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-default-story-mobile-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-default-story-mobile-actual.png -------------------------------------------------------------------------------- /src/stories/assets/cc-addon-backups-default-story-desktop-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-addon-backups-default-story-desktop-expectation.png -------------------------------------------------------------------------------- /src/stories/assets/cc-addon-backups-default-story-mobile-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-addon-backups-default-story-mobile-expectation.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-default-story-desktop-actual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-default-story-desktop-actual.png -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-default-story-mobile-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-default-story-mobile-expectation.png -------------------------------------------------------------------------------- /src/lib/color.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface RgbColor { 2 | r: number; 3 | g: number; 4 | b: number; 5 | } 6 | 7 | export interface HslColor { 8 | h: number; 9 | s: number; 10 | l: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/stories/assets/cc-domain-management-default-story-desktop-expectation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverCloud/clever-components/HEAD/src/stories/assets/cc-domain-management-default-story-desktop-expectation.png -------------------------------------------------------------------------------- /src/assets/mail-line.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cdn-ui/cors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GET 4 | * 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/lib/smart/smart-symbols.js: -------------------------------------------------------------------------------- 1 | export const COMPONENTS = Symbol('COMPONENTS'); 2 | export const CURRENT_CONTEXT = Symbol('CURRENT_CONTEXT'); 3 | export const LAST_CONTEXT = Symbol('LAST_CONTEXT'); 4 | export const META = Symbol('META'); 5 | -------------------------------------------------------------------------------- /test-mocha/cem/fixtures/cem-test-import/cc-test-imports-sub.types.d.ts: -------------------------------------------------------------------------------- 1 | import { ToImport } from "../test-imports.types.js"; 2 | 3 | export interface ToSubImport { 4 | 5 | } 6 | 7 | export interface ToSubImportBar { 8 | 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/components/cc-logs-app-access/cc-logs-app-access.types.d.ts: -------------------------------------------------------------------------------- 1 | import { LogsStreamState } from '../../lib/logs/logs-stream.types.js'; 2 | 3 | export interface LogsAppAccessState { 4 | type: 'loaded'; 5 | streamState: LogsStreamState; 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/pricing.types.d.ts: -------------------------------------------------------------------------------- 1 | import { PricingSection } from 'src/components/common.types.js'; 2 | 3 | export type PricingSimulatorState = Partial<{ 4 | [key in PricingSection['type']]: Omit & { quantity: number }; 5 | }>; 6 | -------------------------------------------------------------------------------- /src/stories/lib/sequence.js: -------------------------------------------------------------------------------- 1 | function wait(delay) { 2 | return new Promise((resolve) => { 3 | setTimeout(resolve, delay); 4 | }); 5 | } 6 | 7 | export function sequence(callback) { 8 | setTimeout(() => callback(wait), 50); 9 | } 10 | -------------------------------------------------------------------------------- /src/components/cc-logs-addon-runtime/cc-logs-addon-runtime.types.d.ts: -------------------------------------------------------------------------------- 1 | import { LogsStreamState } from '../../lib/logs/logs-stream.types.js'; 2 | 3 | export interface LogsAddonRuntimeState { 4 | type: 'loaded'; 5 | streamState: LogsStreamState; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/cc-logs-message-filter/cc-logs-message-filter.types.d.ts: -------------------------------------------------------------------------------- 1 | import { LogMessageFilterMode } from '../cc-logs/cc-logs.types.js'; 2 | 3 | export interface LogsMessageFilterValue { 4 | value: string; 5 | mode: LogMessageFilterMode; 6 | } 7 | -------------------------------------------------------------------------------- /test-mocha/cem/fixtures/test-imports.types.d.ts: -------------------------------------------------------------------------------- 1 | import { ToSubImport, ToSubImportBar } from "./cem-test-import/cc-test-imports-sub.types.js"; 2 | 3 | export interface ToImport { 4 | 5 | } 6 | 7 | export interface ImpExtendInterface { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/components/cc-warning-payment/cc-warning-payment.types.d.ts: -------------------------------------------------------------------------------- 1 | export type PaymentWarningModeType = 'home' | 'overview' | 'billing'; 2 | 3 | export interface PaymentMethodError { 4 | type: number; 5 | orgaName?: string; 6 | orgaBillingLink?: string; 7 | } 8 | -------------------------------------------------------------------------------- /sandbox/forms/form-demo-with-smart-component.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface FormDemoWithSmartComponentState { 2 | type: 'idle' | 'submitting'; 3 | values?: { 4 | name: string; 5 | email: string; 6 | }; 7 | errors?: { 8 | email: 'email-used'; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/immer.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | // immer uses a non-standard global property from Node.js "process" 4 | window.process = { 5 | env: { 6 | NODE_ENV: 'production', 7 | }, 8 | }; 9 | 10 | export { produce } from 'immer/dist/immer.esm.js'; 11 | // TODO: object freeze 12 | -------------------------------------------------------------------------------- /src/assets/start-failed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/running.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-html-frame/cc-html-frame.types.d.ts: -------------------------------------------------------------------------------- 1 | export type IframeSandbox = 2 | | 'allow-forms' 3 | | 'allow-modals' 4 | | 'allow-pointer-lock' 5 | | 'allow-popups' 6 | | 'allow-popups-to-escape-sandbox' 7 | | 'allow-same-origin' 8 | | 'allow-scripts' 9 | | 'allow-top-navigation'; 10 | -------------------------------------------------------------------------------- /src/stories/assets/oracle.svg: -------------------------------------------------------------------------------- 1 | Oracle -------------------------------------------------------------------------------- /src/components/cc-addon-credentials/cc-addon-credentials.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Credential { 2 | type: 'auth-token' | 'host' | 'password' | 'url' | 'user' | 'port'; 3 | value: string; 4 | secret: boolean; 5 | } 6 | 7 | export type AddonType = 'apm' | 'elasticsearch' | 'kibana' | 'pulsar' | 'materia-kv'; 8 | -------------------------------------------------------------------------------- /src/components/cc-pricing-page/cc-pricing-page.types.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CountablePlanWithQuantity, 3 | RuntimePlanWithQuantity, 4 | } from '../cc-pricing-estimation/cc-pricing-estimation.types.js'; 5 | 6 | export interface SelectedPlansById { 7 | [planId: string]: RuntimePlanWithQuantity | CountablePlanWithQuantity; 8 | } 9 | -------------------------------------------------------------------------------- /test/smart/smart-manager.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/mail-star-line.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/accessibility.js: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | // language=CSS 4 | export const accessibilityStyles = css` 5 | .visually-hidden { 6 | clip: rect(0 0 0 0); 7 | clip-path: inset(50%); 8 | height: 1px; 9 | overflow: hidden; 10 | position: absolute; 11 | white-space: nowrap; 12 | width: 1px; 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /src/components/cc-toast/cc-toast.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when a toast is dismissed. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcToastDismissEvent extends CcEvent { 8 | static TYPE = 'cc-toast-dismiss'; 9 | 10 | constructor() { 11 | super(CcToastDismissEvent.TYPE); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/cc-notice/cc-notice.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when a notice has been dismissed. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcNoticeDismissEvent extends CcEvent { 8 | static TYPE = 'cc-notice-dismiss'; 9 | 10 | constructor() { 11 | super(CcNoticeDismissEvent.TYPE); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/assets/restarting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-zone/cc-zone.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Zone } from '../common.types.js'; 2 | 3 | export type ZoneState = ZoneStateLoaded | ZoneStateLoading; 4 | 5 | export interface ZoneStateLoaded extends Zone { 6 | type: 'loaded'; 7 | } 8 | 9 | export interface ZoneStateLoading { 10 | type: 'loading'; 11 | } 12 | 13 | export type ZoneModeType = 'default' | 'small' | 'small-infra'; 14 | -------------------------------------------------------------------------------- /src/assets/restart-failed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-invoice-table/cc-invoice-table.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Invoice } from '../common.types.js'; 2 | 3 | export type InvoiceTableState = InvoiceTableStateLoaded | InvoiceTableStateLoading; 4 | 5 | export interface InvoiceTableStateLoaded { 6 | type: 'loaded'; 7 | invoices: Invoice[]; 8 | } 9 | 10 | export interface InvoiceTableStateLoading { 11 | type: 'loading'; 12 | } 13 | -------------------------------------------------------------------------------- /src/stories/assets/ovh.svg: -------------------------------------------------------------------------------- 1 | OVH -------------------------------------------------------------------------------- /src/components/cc-order-summary/cc-order-summary.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when a product creation has be requested. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcProductCreateEvent extends CcEvent { 8 | static TYPE = 'cc-product-create'; 9 | 10 | constructor() { 11 | super(CcProductCreateEvent.TYPE); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/assets/baseline-widely.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/lib/send-to-api.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from './events.js'; 2 | 3 | /** 4 | * Dispatched when an API request failed. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcApiErrorEvent extends CcEvent { 8 | static TYPE = 'cc-api-error'; 9 | 10 | /** 11 | * @param {any} detail 12 | */ 13 | constructor(detail) { 14 | super(CcApiErrorEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/tokens.types.d.ts: -------------------------------------------------------------------------------- 1 | export type ExpirationWarningThresholds = Array<{ 2 | /** Number of days representing the maximum lifetime for which the given threshold is applicable */ 3 | maxApplicableTokenLifetimeInDays: number; 4 | /** Number of days below which the token is considered close to expiration (must be lower than maxApplicableTokenLifetimeInDays) */ 5 | warningThresholdInDays: number; 6 | }>; 7 | -------------------------------------------------------------------------------- /test/helpers/global-mock-date.js: -------------------------------------------------------------------------------- 1 | const fakeNow = new Date('2023-10-26T12:00:00.000Z').getTime(); 2 | window.Date = class extends Date { 3 | static now() { 4 | return fakeNow; 5 | } 6 | 7 | // @ts-ignore 8 | constructor(...options) { 9 | if (options.length > 0) { 10 | // @ts-ignore 11 | super(...options); 12 | } else { 13 | super(fakeNow); 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/stories/assets/italic.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/lib/assets-url.js: -------------------------------------------------------------------------------- 1 | let assetsUrl = 'https://assets.clever-cloud.com'; 2 | 3 | /** @param {string} value */ 4 | export function setAssetsBaseUrl(value) { 5 | assetsUrl = value.replace(/\/$/, ''); 6 | } 7 | 8 | /** 9 | * @param {string} path 10 | * @returns {string} 11 | */ 12 | export function getAssetUrl(path) { 13 | return path.startsWith('/') ? `${assetsUrl}${path}` : `${assetsUrl}/${path}`; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/cc-doc-card/cc-doc-card.types.d.ts: -------------------------------------------------------------------------------- 1 | export type DocCardState = DocCardStateLoaded | DocCardStateLoading; 2 | 3 | export interface DocCardStateLoaded extends DocCard { 4 | type: 'loaded'; 5 | } 6 | 7 | export interface DocCardStateLoading { 8 | type: 'loading'; 9 | } 10 | 11 | export interface DocCard { 12 | description: string; 13 | heading: string; 14 | icons: string[]; 15 | link: string; 16 | } 17 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # run `git config blame.ignoreRevsFile .git-blame-ignore-revs` locally to apply 2 | 3 | # chore: format all remaining files with the format command 4 | a166f4f8da4902a37bf7ef9654186c9b6ef442c4 5 | 6 | # chore: update source code with Prettier and Stylelint update 7 | f9fcd572efca5301e44ae348ec5eb2c41b37e931 8 | 9 | # refactor: apply the new project file structure 10 | 79f7a4893dfb5194a2fb06d781c67766a5aa9349 11 | -------------------------------------------------------------------------------- /docs/copywriting/coming-soon.md: -------------------------------------------------------------------------------- 1 | --- 2 | kind: '🖋 Copywriting' 3 | title: 'Coming soon...' 4 | --- 5 | 6 | # 🖋 Copywriting 7 | 8 | 9 | 10 | This section will cover how our components talk to end users through written messages. 11 | 12 | Expected soon: 13 | 14 | - our copywriting principles, 15 | - guidelines about tone, internationalisation and a dictionary. -------------------------------------------------------------------------------- /eslint/lit-a11y/eslint-config-lit-a11y-clever-cloud.js: -------------------------------------------------------------------------------- 1 | import eslintLitA11yPlugin from 'eslint-plugin-lit-a11y'; 2 | 3 | export default { 4 | name: 'lit-a11y-cc', 5 | files: ['**/*.js'], 6 | plugins: { 7 | 'lit-a11y': eslintLitA11yPlugin, 8 | }, 9 | rules: { 10 | ...eslintLitA11yPlugin.configs.recommended.rules, 11 | // redundant role may be necessary sometimes 12 | 'lit-a11y/no-redundant-role': 'warn', 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/cc-input-text/cc-input-text.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when tags have changed. 5 | * @extends {CcEvent>} 6 | */ 7 | export class CcTagsChangeEvent extends CcEvent { 8 | static TYPE = 'cc-tags-change'; 9 | 10 | /** 11 | * @param {Array} detail 12 | */ 13 | constructor(detail) { 14 | super(CcTagsChangeEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/stories/lib/dom.js: -------------------------------------------------------------------------------- 1 | export function createContainer(elements) { 2 | const frag = document.createDocumentFragment(); 3 | elements.forEach((el) => { 4 | if (typeof el === 'string') { 5 | const title = document.createElement('div'); 6 | title.classList.add('title'); 7 | title.innerHTML = el; 8 | frag.appendChild(title); 9 | } else { 10 | frag.appendChild(el); 11 | } 12 | }); 13 | return frag; 14 | } 15 | -------------------------------------------------------------------------------- /src/styles/waiting.js: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | // language=CSS 4 | export const waitingStyles = css` 5 | @keyframes waiting { 6 | from { 7 | opacity: 0.85; 8 | } 9 | 10 | to { 11 | opacity: 1; 12 | } 13 | } 14 | 15 | .cc-waiting { 16 | animation-direction: alternate; 17 | animation-duration: 500ms; 18 | animation-iteration-count: infinite; 19 | animation-name: waiting; 20 | } 21 | `; 22 | -------------------------------------------------------------------------------- /.github/scripts/get-stories-groups.js: -------------------------------------------------------------------------------- 1 | import { appendFileSync } from 'node:fs'; 2 | import { getStoriesGroups } from '../../web-test-runner/get-story-files-groups.js'; 3 | 4 | const storiesGroups = await getStoriesGroups(); 5 | const storiesGroupsNames = storiesGroups.map(({ name }) => name); 6 | 7 | if (process.env.GITHUB_OUTPUT != null) { 8 | appendFileSync(process.env.GITHUB_OUTPUT, `stories-groups=${JSON.stringify(storiesGroupsNames)}\n`); 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/starting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-doc-list/cc-doc-list.types.d.ts: -------------------------------------------------------------------------------- 1 | import { DocCard } from '../cc-doc-card/cc-doc-card.types.js'; 2 | 3 | export type DocListState = DocListStateLoaded | DocListStateLoading | DocListStateError; 4 | 5 | export interface DocListStateLoaded { 6 | type: 'loaded'; 7 | docs: DocCard[]; 8 | } 9 | 10 | export interface DocListStateLoading { 11 | type: 'loading'; 12 | } 13 | 14 | export interface DocListStateError { 15 | type: 'error'; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-input-date/cc-input-date.types.d.ts: -------------------------------------------------------------------------------- 1 | export type InputDateValueState = InputDateValueStateEmpty | InputDateValueStateNaD | InputDateValueStateValid; 2 | 3 | export interface InputDateValueStateEmpty { 4 | type: 'empty'; 5 | } 6 | 7 | export interface InputDateValueStateNaD { 8 | type: 'NaD'; 9 | value: string; 10 | } 11 | 12 | export interface InputDateValueStateValid { 13 | type: 'valid'; 14 | value: string; 15 | date: Date; 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/events.types.d.ts: -------------------------------------------------------------------------------- 1 | export type EventWithTarget< 2 | T extends EventTarget = HTMLElement | SVGElement, 3 | U extends EventTarget = null | HTMLElement | SVGElement, 4 | > = GenericEventWithTarget; 5 | 6 | export type GenericEventWithTarget< 7 | E extends Event, 8 | T extends EventTarget = HTMLElement | SVGElement, 9 | U extends EventTarget = null | HTMLElement | SVGElement, 10 | > = E & { 11 | target: T; 12 | currentTarget: U; 13 | }; 14 | -------------------------------------------------------------------------------- /src/components/cc-addon-option/cc-addon-option.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when an add-on option is toggled. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcAddonOptionChangeEvent extends CcEvent { 8 | static TYPE = 'cc-addon-option-change'; 9 | 10 | /** 11 | * @param {boolean} detail 12 | */ 13 | constructor(detail) { 14 | super(CcAddonOptionChangeEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-product-list/cc-product-list.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | description: string; 3 | iconUrl: string; 4 | productStatus?: string; 5 | searchTerms?: string[]; 6 | name: string; 7 | url: string; 8 | } 9 | 10 | export interface ProductsCategory { 11 | categoryName: string; 12 | icon?: string; 13 | products: Product[]; 14 | } 15 | 16 | export interface CategoryFilter { 17 | categoryName: string; 18 | toggled: boolean; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/cc-article-card/cc-article-card.types.d.ts: -------------------------------------------------------------------------------- 1 | export type ArticleCardState = ArticleCardStateLoaded | ArticleCardStateLoading; 2 | 3 | export interface ArticleCardStateLoaded extends ArticleCard { 4 | type: 'loaded'; 5 | } 6 | 7 | export interface ArticleCardStateLoading { 8 | type: 'loading'; 9 | } 10 | 11 | export interface ArticleCard { 12 | banner: string; 13 | date: string; 14 | description: string; 15 | link: string; 16 | title: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/translations/translation.js: -------------------------------------------------------------------------------- 1 | import { i18n as i18nRaw } from '../lib/i18n/i18n.js'; 2 | 3 | // FIXME: We're using `@typedef` instead of `@import` here due to a false positive from TS 4 | // See: https://github.com/microsoft/TypeScript/issues/60908/ 5 | /** 6 | * @typedef {import('./translation.types.js').I18nFunction} I18nFunction 7 | */ 8 | 9 | /** @type {I18nFunction} */ 10 | export function i18n(key, data) { 11 | // @ts-ignore 12 | return i18nRaw(key, data); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/cc-addon-info/cc-addon-info.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when an add-on version update was requested. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcAddonVersionChangeEvent extends CcEvent { 8 | static TYPE = 'cc-addon-version-change'; 9 | 10 | /** @param {string} targetVersion */ 11 | constructor(targetVersion) { 12 | super(CcAddonVersionChangeEvent.TYPE, targetVersion); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/css-custom-properties.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get an object literally with CSS custom properties and their values 3 | * @param {HTMLElement} element 4 | * @returns {any} 5 | */ 6 | export function getCssCustomProperties(element) { 7 | const styles = getComputedStyle(element); 8 | const entries = Object.values(styles) 9 | .filter((name) => name.startsWith('--')) 10 | .map((name) => [name, styles.getPropertyValue(name)]); 11 | return Object.fromEntries(entries); 12 | } 13 | -------------------------------------------------------------------------------- /src/assets/arrows-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/arrows-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-invoice-list/cc-invoice-list.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Invoice } from '../common.types.js'; 2 | 3 | export type InvoiceListState = InvoiceListStateLoading | InvoiceListStateError | InvoiceListStateLoaded; 4 | 5 | export interface InvoiceListStateLoading { 6 | type: 'loading'; 7 | } 8 | 9 | export interface InvoiceListStateError { 10 | type: 'error'; 11 | } 12 | 13 | export interface InvoiceListStateLoaded { 14 | type: 'loaded'; 15 | invoices: Array; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-matomo-info/cc-matomo-info.types.d.ts: -------------------------------------------------------------------------------- 1 | export type MatomoInfoState = MatomoInfoStateLoaded | MatomoInfoStateLoading | MatomoInfoStateError; 2 | 3 | export interface MatomoInfoStateLoaded { 4 | type: 'loaded'; 5 | matomoUrl: string; 6 | mysqlUrl: string; 7 | phpUrl: string; 8 | redisUrl: string; 9 | } 10 | 11 | export interface MatomoInfoStateLoading { 12 | type: 'loading'; 13 | } 14 | 15 | export interface MatomoInfoStateError { 16 | type: 'error'; 17 | } 18 | -------------------------------------------------------------------------------- /.githooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | protected_branch='master' 4 | current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') 5 | 6 | if [ "$protected_branch" = "$current_branch" ] 7 | then 8 | read -p "You're about to push to ${protected_branch} branch, is that what you intended? [y|n] " -n 1 -r < /dev/tty 9 | echo 10 | if echo "$REPLY" | grep -E '^[Yy]$' > /dev/null 11 | then 12 | exit 0 13 | fi 14 | exit 1 15 | else 16 | exit 0 17 | fi 18 | -------------------------------------------------------------------------------- /rollup/rollup-cdn.config.js: -------------------------------------------------------------------------------- 1 | import { toCdnEntryName } from '../tasks/cdn-entry-name.js'; 2 | import { CDN_ENVIRONMENTS } from '../tasks/cdn-environments.js'; 3 | import { getCdnRollupConfig } from './rollup-cdn-common.js'; 4 | 5 | const version = process.env.VERSION; 6 | if (version == null) { 7 | throw new Error('VERSION env var is required.'); 8 | } 9 | const cdnEntryName = toCdnEntryName(CDN_ENVIRONMENTS.release, version); 10 | 11 | export default getCdnRollupConfig(cdnEntryName, true); 12 | -------------------------------------------------------------------------------- /src/components/cc-pricing-header/cc-pricing-header.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Zone } from '../common.types.js'; 2 | 3 | export interface PricingHeaderStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | export interface PricingHeaderStateError { 8 | type: 'error'; 9 | } 10 | 11 | export interface PricingHeaderStateLoaded { 12 | type: 'loaded'; 13 | zones: Zone[]; 14 | } 15 | 16 | export type PricingHeaderState = PricingHeaderStateLoading | PricingHeaderStateError | PricingHeaderStateLoaded; 17 | -------------------------------------------------------------------------------- /src/components/cc-header-orga/cc-header-orga.types.d.ts: -------------------------------------------------------------------------------- 1 | export type HeaderOrgaState = HeaderOrgaStateLoaded | HeaderOrgaStateLoading | HeaderOrgaStateError; 2 | 3 | export interface HeaderOrgaStateLoaded { 4 | type: 'loaded'; 5 | name: string; 6 | avatar?: string; 7 | cleverEnterprise?: boolean; 8 | emergencyNumber?: string; 9 | } 10 | 11 | export interface HeaderOrgaStateLoading { 12 | type: 'loading'; 13 | } 14 | 15 | export interface HeaderOrgaStateError { 16 | type: 'error'; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/cc-kv-string-editor/cc-kv-string-editor.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when a KV string key modification is requested. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcKvStringValueUpdateEvent extends CcEvent { 8 | static TYPE = 'cc-kv-string-value-update'; 9 | 10 | /** 11 | * @param {string} detail 12 | */ 13 | constructor(detail) { 14 | super(CcKvStringValueUpdateEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/ansi/ansi-palette-style.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {import('./ansi.types.js').AnsiPalette} palette - The palette 3 | * @return {string} - The CSS style corresponding to the given palette. 4 | */ 5 | export function ansiPaletteStyle(palette) { 6 | return [ 7 | ...Object.entries(palette).map(([colorName, color]) => `--cc-color-ansi-${colorName}: ${color}`), 8 | 'color: var(--cc-color-ansi-foreground)', 9 | 'background-color: var(--cc-color-ansi-background);', 10 | ].join(';'); 11 | } 12 | -------------------------------------------------------------------------------- /src/styles/cli-commands.js: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | // language=CSS 4 | export const cliCommandsStyles = css` 5 | cc-block-details [slot='content'] p { 6 | margin: 0; 7 | } 8 | 9 | cc-block-details [slot='content'] dl, 10 | cc-block-details [slot='content'] dt, 11 | cc-block-details [slot='content'] dd { 12 | margin: 0; 13 | padding: 0; 14 | } 15 | 16 | cc-block-details [slot='content'] dt { 17 | font-weight: bold; 18 | margin: 1em 0 0.5em; 19 | } 20 | `; 21 | -------------------------------------------------------------------------------- /src/lib/form/validation.types.d.ts: -------------------------------------------------------------------------------- 1 | export type Validity = ValidValidity | InvalidValidity; 2 | 3 | export interface ValidValidity { 4 | valid: true; 5 | } 6 | 7 | export interface InvalidValidity { 8 | valid: false; 9 | code: string; 10 | } 11 | 12 | export interface Validator { 13 | validate(value: any, formData?: Object): Validity; 14 | } 15 | 16 | export type ErrorMessage = null | string | Node; 17 | 18 | export type ErrorMessageMap = { [code: string]: ErrorMessage | (() => ErrorMessage) }; 19 | -------------------------------------------------------------------------------- /src/assets/baseline-limited.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/cc-env-var-create/cc-env-var-create.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when an env var creation is requested. 5 | * @extends {CcEvent<{name: string, value: string}>} 6 | */ 7 | export class CcEnvVarCreateEvent extends CcEvent { 8 | static TYPE = 'cc-env-var-create'; 9 | 10 | /** 11 | * @param {{name: string, value: string}} detail 12 | */ 13 | constructor(detail) { 14 | super(CcEnvVarCreateEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/notifications.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from './events.js'; 2 | 3 | /** 4 | * @import { Notification } from '../components/common.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when a notification message is raised. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcNotifyEvent extends CcEvent { 12 | static TYPE = 'cc-notify'; 13 | 14 | /** 15 | * @param {Notification} detail 16 | */ 17 | constructor(detail) { 18 | super(CcNotifyEvent.TYPE, detail); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/cc-article-list/cc-article-list.types.d.ts: -------------------------------------------------------------------------------- 1 | import { ArticleCard } from '../cc-article-card/cc-article-card.types.js'; 2 | 3 | export type ArticleListState = ArticleListStateLoaded | ArticleListStateLoading | ArticleListStateError; 4 | 5 | export interface ArticleListStateLoaded { 6 | type: 'loaded'; 7 | articles: ArticleCard[]; 8 | } 9 | 10 | export interface ArticleListStateLoading { 11 | type: 'loading'; 12 | } 13 | 14 | export interface ArticleListStateError { 15 | type: 'error'; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-tile-scalability/cc-tile-scalability.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Scalability } from '../common.types.js'; 2 | 3 | export type TileScalabilityState = TileScalabilityStateLoaded | TileScalabilityStateLoading | TileScalabilityStateError; 4 | 5 | export interface TileScalabilityStateLoaded extends Scalability { 6 | type: 'loaded'; 7 | } 8 | 9 | export interface TileScalabilityStateLoading { 10 | type: 'loading'; 11 | } 12 | 13 | export interface TileScalabilityStateError { 14 | type: 'error'; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/cc-kv-string-editor/cc-kv-string-editor.types.d.ts: -------------------------------------------------------------------------------- 1 | export type CcKvKeyStringEditorState = 2 | | CcKvKeyStringEditorStateLoading 3 | | CcKvKeyStringEditorStateIdle 4 | | CcKvKeyStringEditorStateSaving; 5 | 6 | export interface CcKvKeyStringEditorStateLoading { 7 | type: 'loading'; 8 | } 9 | 10 | export interface CcKvKeyStringEditorStateIdle { 11 | type: 'idle'; 12 | value: string; 13 | } 14 | 15 | export interface CcKvKeyStringEditorStateSaving { 16 | type: 'saving'; 17 | value: string; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/cc-logs-instances/cc-logs-instances.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when logs instances selection changes. 5 | * @extends {CcEvent>} 6 | */ 7 | export class CcLogsInstancesSelectionChangeEvent extends CcEvent { 8 | static TYPE = 'cc-logs-instances-selection-change'; 9 | 10 | /** 11 | * @param {Array} detail 12 | */ 13 | constructor(detail) { 14 | super(CcLogsInstancesSelectionChangeEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-map/cc-map.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Marker, PointExpression } from 'src/lib/leaflet/leaflet-esm.js'; 2 | import { Point } from '../common.types.js'; 3 | 4 | export interface CachedPoint { 5 | point: Point; 6 | marker: Marker & { 7 | tag?: string; 8 | tooltip?: string | { tag: string }; 9 | }; 10 | iconElement: MapIconElement; 11 | } 12 | 13 | export interface MapIconElement extends HTMLElement { 14 | size: PointExpression; 15 | anchor: PointExpression; 16 | tooltip: PointExpression; 17 | } 18 | -------------------------------------------------------------------------------- /src/stories/lib/timers.js: -------------------------------------------------------------------------------- 1 | export function setTimeoutDom(fn, delay, domNode) { 2 | const id = setTimeout(() => { 3 | if (domNode.parentNode == null) { 4 | clearTimeout(id); 5 | } else { 6 | fn(); 7 | } 8 | }, delay); 9 | return id; 10 | } 11 | 12 | export function setIntervalDom(fn, delay, domNode) { 13 | const id = setInterval(() => { 14 | if (domNode.parentNode == null) { 15 | clearInterval(id); 16 | } else { 17 | fn(); 18 | } 19 | }, delay); 20 | return id; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/git.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-order-summary/cc-order-summary.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface OrderSummary { 2 | name: string; 3 | tags?: Array; 4 | logo?: LogoInfos; 5 | configuration?: Array; 6 | submitStatus?: 'disabled' | 'waiting'; 7 | } 8 | 9 | export interface LogoInfos { 10 | url: string; 11 | alt: string; 12 | } 13 | 14 | export interface ConfigurationItem { 15 | label: string; 16 | value: string; 17 | a11yLive?: boolean; 18 | skeleton?: boolean; 19 | skeletonValueOnly?: boolean; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/cc-feature-list/cc-feature-list.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when a feature setting changes. 5 | * @extends {CcEvent<{featureId: string, newValue: string}>} 6 | */ 7 | export class CcFeatureSettingChangeEvent extends CcEvent { 8 | static TYPE = 'cc-feature-setting-change'; 9 | 10 | /** 11 | * @param {{featureId: string, newValue: string}} detail 12 | */ 13 | constructor(detail) { 14 | super(CcFeatureSettingChangeEvent.TYPE, detail); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-logsmap/cc-logsmap.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { MapModeType } from '../common.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the logsmap display mode changes. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcLogsmapModeChangeEvent extends CcEvent { 12 | static TYPE = 'cc-logsmap-mode-change'; 13 | 14 | /** 15 | * @param {MapModeType} detail 16 | */ 17 | constructor(detail) { 18 | super(CcLogsmapModeChangeEvent.TYPE, detail); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/remote-assets.js: -------------------------------------------------------------------------------- 1 | import { getAssetUrl } from './assets-url.js'; 2 | 3 | /** 4 | * @param {string|null} countryCode 5 | * @return {string|null} 6 | */ 7 | export function getFlagUrl(countryCode) { 8 | return countryCode != null ? getAssetUrl(`/flags/${countryCode.toLowerCase()}.svg`) : null; 9 | } 10 | 11 | /** 12 | * @param {string|null} providerSlug 13 | * @return {string|null} 14 | */ 15 | export function getInfraProviderLogoUrl(providerSlug) { 16 | return providerSlug != null ? getAssetUrl(`/infra/${providerSlug}.svg`) : null; 17 | } 18 | -------------------------------------------------------------------------------- /docs/guidelines/coming-soon.md: -------------------------------------------------------------------------------- 1 | --- 2 | kind: '📖 Guidelines' 3 | title: 'Coming soon...' 4 | --- 5 | 6 | # 📖 Guidelines 7 | 8 | 9 | 10 | This section will cover how we design our components, from a global perspective but also from a component level. 11 | The guides will mostly be recommendations and best practices and not intangible rules. 12 | 13 | Expected soon: 14 | 15 | - our design principles, 16 | - guidelines about layout, list, form, button, interaction and more! 17 | -------------------------------------------------------------------------------- /rollup/rollup-plugin-styles-assets.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | export function stylesAssetsPlugin(options) { 4 | const transform = options?.transform ?? ((css) => css); 5 | return { 6 | generateBundle: async function () { 7 | const stylesheet = fs.readFileSync('src/styles/default-theme.css', 'utf8'); 8 | const minifiedStylesheet = transform(stylesheet); 9 | 10 | this.emitFile({ 11 | type: 'asset', 12 | name: 'default-theme.css', 13 | source: minifiedStylesheet, 14 | }); 15 | }, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/cc-pricing-product/cc-pricing-product.types.d.ts: -------------------------------------------------------------------------------- 1 | import { FormattedFeature, Plan } from '../common.types.js'; 2 | 3 | interface PricingProductStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | interface PricingProductStateError { 8 | type: 'error'; 9 | } 10 | 11 | interface PricingProductStateLoaded { 12 | type: 'loaded'; 13 | productFeatures: FormattedFeature[]; 14 | name: string; 15 | plans: Plan[]; 16 | } 17 | 18 | export type PricingProductState = PricingProductStateLoading | PricingProductStateError | PricingProductStateLoaded; 19 | -------------------------------------------------------------------------------- /src/components/cc-token-api-creation-form/cc-token-api-creation-form.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { NewToken } from './cc-token-api-creation-form.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when a token creation is requested. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcTokenCreateEvent extends CcEvent { 12 | static TYPE = 'cc-token-create'; 13 | 14 | /** @param {NewToken} detail */ 15 | constructor(detail) { 16 | super(CcTokenCreateEvent.TYPE, detail); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/cc-invoice/cc-invoice.types.d.ts: -------------------------------------------------------------------------------- 1 | export type InvoiceState = InvoiceStateLoading | InvoiceStateError | InvoiceStateLoaded; 2 | 3 | interface InvoiceStateLoading { 4 | type: 'loading'; 5 | number?: string; 6 | } 7 | 8 | interface InvoiceStateError { 9 | type: 'error'; 10 | number: string; 11 | } 12 | 13 | interface InvoiceStateLoaded { 14 | type: 'loaded'; 15 | number: string; 16 | downloadUrl: string; 17 | emissionDate: string; 18 | amount: number; 19 | currency: string; // ISO 4217 currency code 20 | invoiceHtml: string; 21 | } 22 | -------------------------------------------------------------------------------- /rollup/rollup-cdn-preview.config.js: -------------------------------------------------------------------------------- 1 | import { toCdnEntryName } from '../tasks/cdn-entry-name.js'; 2 | import { CDN_ENVIRONMENTS } from '../tasks/cdn-environments.js'; 3 | import { getCurrentBranch } from '../tasks/git-utils.js'; 4 | import { getCdnRollupConfig } from './rollup-cdn-common.js'; 5 | 6 | const nameFromEnv = process.env.PREVIEW; 7 | const name = nameFromEnv == null || nameFromEnv.length === 0 ? getCurrentBranch() : nameFromEnv; 8 | const cdnEntryName = toCdnEntryName(CDN_ENVIRONMENTS.preview, name); 9 | 10 | export default getCdnRollupConfig(cdnEntryName, false); 11 | -------------------------------------------------------------------------------- /rollup/rollup-plugin-index-generator.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export function indexGeneratorPlugin(files) { 4 | return { 5 | name: 'index-generator', 6 | generateBundle() { 7 | const source = files 8 | .map((f) => { 9 | const filename = path.parse(f).base; 10 | return `import './${filename}';`; 11 | }) 12 | .join('\n'); 13 | 14 | this.emitFile({ 15 | type: 'asset', 16 | id: 'index', 17 | fileName: 'index.js', 18 | source, 19 | }); 20 | }, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/cc-jenkins-info/cc-jenkins-info.types.d.ts: -------------------------------------------------------------------------------- 1 | export type JenkinsInfoState = JenkinsInfoStateLoading | JenkinsInfoStateError | JenkinsInfoStateLoaded; 2 | 3 | interface JenkinsInfoStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | interface JenkinsInfoStateError { 8 | type: 'error'; 9 | } 10 | 11 | interface JenkinsInfoStateLoaded { 12 | type: 'loaded'; 13 | jenkinsLink: string; 14 | jenkinsManageLink: string; 15 | versions: JenkinsInfoVersions; 16 | } 17 | 18 | interface JenkinsInfoVersions { 19 | current: string; 20 | available: string; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/cc-tile-instances/cc-tile-instances.types.d.ts: -------------------------------------------------------------------------------- 1 | export type TileInstancesState = TileInstancesStateLoading | TileInstancesStateLoaded | TileInstancesStateError; 2 | 3 | export interface TileInstancesStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | export interface TileInstancesStateLoaded { 8 | type: 'loaded'; 9 | running: Array; 10 | deploying: Array; 11 | } 12 | 13 | export interface TileInstancesStateError { 14 | type: 'error'; 15 | } 16 | 17 | export interface InstanceState { 18 | flavorName: string; 19 | count: number; 20 | } 21 | -------------------------------------------------------------------------------- /src/stories/assets/underline.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/cc-addon-option-form/cc-addon-option-form.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { AddonOptionStates } from '../common.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the add-on options form is submitted. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcAddonOptionFormSubmitEvent extends CcEvent { 12 | static TYPE = 'cc-addon-option-form-submit'; 13 | 14 | /** 15 | * @param {AddonOptionStates} detail 16 | */ 17 | constructor(detail) { 18 | super(CcAddonOptionFormSubmitEvent.TYPE, detail); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/cc-plan-picker/cc-plan-picker.types.d.ts: -------------------------------------------------------------------------------- 1 | import { BadgeIntent } from '../cc-badge/cc-badge.types.js'; 2 | import { IconModel } from '../common.types.js'; 3 | 4 | export interface PlanItem { 5 | id: string; 6 | badge?: PlanBadge; 7 | name: string; 8 | details?: PlanDetails[]; 9 | disabled?: boolean; 10 | selected?: boolean; 11 | relatedPlans?: Array>; 12 | } 13 | 14 | export interface PlanBadge { 15 | content: string; 16 | intent?: BadgeIntent; 17 | } 18 | 19 | export interface PlanDetails { 20 | icon: IconModel; 21 | value: string; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/cc-tile-deployments/cc-tile-deployments.types.d.ts: -------------------------------------------------------------------------------- 1 | export type TileDeploymentsState = TileDeploymentsStateLoading | TileDeploymentsStateLoaded | TileDeploymentsStateError; 2 | 3 | interface TileDeploymentsStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | interface TileDeploymentsStateLoaded { 8 | type: 'loaded'; 9 | deploymentsInfo: Array; 10 | } 11 | 12 | interface TileDeploymentsStateError { 13 | type: 'error'; 14 | } 15 | 16 | export interface DeploymentTileInfo { 17 | state: string; 18 | action: string; 19 | date: string; 20 | logsUrl: string; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/cc-logs-control/cc-logs-control.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { LogsOptionsChangeEventData } from './cc-logs-control.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the logs options have changed. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcLogsOptionsChangeEvent extends CcEvent { 12 | static TYPE = 'cc-logs-options-change'; 13 | 14 | /** 15 | * @param {LogsOptionsChangeEventData} detail 16 | */ 17 | constructor(detail) { 18 | super(CcLogsOptionsChangeEvent.TYPE, detail); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/stories/assets/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.storybook/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | 3 | # If an existing asset or directory is requested, serve it 4 | RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] 5 | RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d 6 | RewriteRule ^ - [L] 7 | 8 | 9 | 10 | Header set Cache-Control "no-cache" 11 | 12 | 13 | 14 | Header set Cache-Control "max-age=2592000, immutable" 15 | 16 | 17 | 18 | Header set Cache-Control "max-age=31536000, immutable" 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/lib/fake-strings.js: -------------------------------------------------------------------------------- 1 | // It's more representative of a real sentence to use this than to try to generate something with spaces. 2 | const FAKE_STRING_BASE = 3 | '??? ??????????? ???? ?????? ??? ????????????? ????????? ?? ??????? ?? ????? ????????????? ?? ?????? ??? ?? ??????? ?? ????????? ?? ?????????? ?? ??????????? ????? ?????????? ?? ???? ???????????? ???? ????? ????????????????'; 4 | 5 | /** 6 | * Creates a fake string of `charCount` characters 7 | * 8 | * @param {number} charCount 9 | * @return {string} 10 | */ 11 | export function fakeString(charCount) { 12 | return FAKE_STRING_BASE.substring(0, charCount); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/cc-clipboard/cc-clipboard.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-clipboard.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🧬 Atoms/', 7 | component: 'cc-clipboard', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-clipboard', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ value: 'Text to copy' }], 16 | }); 17 | 18 | export const emptyText = makeStory(conf, { 19 | items: [{ value: '' }], 20 | }); 21 | 22 | export const shortText = makeStory(conf, { 23 | items: [{ value: 'Foo' }], 24 | }); 25 | -------------------------------------------------------------------------------- /src/components/cc-zone-picker/cc-zone-picker.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface ZoneItem { 2 | code: string; 3 | country: string; 4 | countryCode: string; 5 | name: string; 6 | flagUrl: string; 7 | images: Array; 8 | disabled?: boolean; 9 | selected?: boolean; 10 | } 11 | 12 | export interface ZoneImage { 13 | url: string | URL; 14 | alt: string; 15 | } 16 | 17 | export type ZonesSections = Array | [SingleZoneSection]; 18 | 19 | export interface ZoneSection { 20 | title: string; 21 | zones: Array; 22 | } 23 | 24 | export interface SingleZoneSection { 25 | zones: Array; 26 | } 27 | -------------------------------------------------------------------------------- /src/stories/lib/autodocs-template.jsx: -------------------------------------------------------------------------------- 1 | // we disable this rule because this file is only meant to be processed by Storybook. It is not part of our npm / CDN bundle. 2 | // eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars 3 | import { Controls, Description, Subtitle, Title } from '@storybook/addon-docs/blocks'; 4 | // eslint-disable-next-line import/no-extraneous-dependencies, no-unused-vars 5 | import React from 'react'; 6 | 7 | export function AutodocsTemplate() { 8 | return ( 9 | <> 10 | 11 | <Subtitle /> 12 | <Description /> 13 | <Controls /> 14 | </> 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/cc-logs-message-filter/cc-logs-message-filter.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { LogsMessageFilterValue } from './cc-logs-message-filter.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the logs message filter changes. 9 | * @extends {CcEvent<LogsMessageFilterValue>} 10 | */ 11 | export class CcLogsMessageFilterChangeEvent extends CcEvent { 12 | static TYPE = 'cc-logs-message-filter-change'; 13 | 14 | /** 15 | * @param {LogsMessageFilterValue} detail 16 | */ 17 | constructor(detail) { 18 | super(CcLogsMessageFilterChangeEvent.TYPE, detail); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/focus-helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {Element|ShadowRoot|Document} element The root element on which the querySelector is made (can be `null`) 3 | * @param {string} selector The query selector 4 | * @param {() => void} [orElse] The optional function to call when the result of the query selector is `null` 5 | */ 6 | export function focusBySelector(element, selector, orElse = null) { 7 | /** @type {Element & { focus?: () => void}} */ 8 | const elementToFocus = element?.querySelector(selector); 9 | if (typeof elementToFocus?.focus === 'function') { 10 | elementToFocus.focus(); 11 | } else { 12 | orElse?.(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/animate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {ShadowRoot} shadowRoot 4 | * @param {string} selector 5 | * @param {Array<Keyframe> | PropertyIndexedKeyframes} keyframes 6 | * @param {number | KeyframeAnimationOptions} options 7 | */ 8 | export function animate(shadowRoot, selector, keyframes, options) { 9 | Array.from(shadowRoot.querySelectorAll(selector)).forEach((element) => element.animate(keyframes, options)); 10 | } 11 | 12 | export const QUICK_SHRINK = { 13 | keyframes: [{ transform: 'scale(1)' }, { transform: 'scale(0.9)' }, { transform: 'scale(1)' }], 14 | options: { 15 | duration: 200, 16 | easing: 'ease-in-out', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/cc-addon-header/cc-addon-header.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatch when an addon restart is requested. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcAddonRestartEvent extends CcEvent { 8 | static TYPE = 'cc-addon-restart'; 9 | 10 | constructor() { 11 | super(CcAddonRestartEvent.TYPE); 12 | } 13 | } 14 | 15 | /** 16 | * Dispatch when an addon rebuild is requested. 17 | * @extends {CcEvent} 18 | */ 19 | export class CcAddonRebuildEvent extends CcEvent { 20 | static TYPE = 'cc-addon-rebuild'; 21 | 22 | constructor() { 23 | super(CcAddonRebuildEvent.TYPE); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/components/cc-header-app/cc-header-app.types.d.ts: -------------------------------------------------------------------------------- 1 | import { App, AppStatus, Zone } from '../common.types.js'; 2 | 3 | export type HeaderAppState = HeaderAppStateLoaded | HeaderAppStateLoading | HeaderAppStateError; 4 | 5 | export interface HeaderAppStateLoaded extends App { 6 | type: 'loaded'; 7 | status: AppStatus; 8 | runningCommit?: string | null; 9 | startingCommit?: string | null; 10 | zone: Zone; 11 | } 12 | 13 | export interface HeaderAppStateLoading { 14 | type: 'loading'; 15 | } 16 | 17 | export interface HeaderAppStateError { 18 | type: 'error'; 19 | } 20 | 21 | export type LastUserAction = 'start' | 'restart' | 'cancel' | 'stop'; 22 | -------------------------------------------------------------------------------- /src/components/cc-addon-credentials-content/cc-addon-credentials-content.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatched when a network group creation is requested. 5 | * @extends {CcEvent} 6 | */ 7 | export class CcNgEnable extends CcEvent { 8 | static TYPE = 'cc-ng-enable'; 9 | 10 | constructor() { 11 | super(CcNgEnable.TYPE); 12 | } 13 | } 14 | 15 | /** 16 | * Dispatched when a network group deletion is requested. 17 | * @extends {CcEvent} 18 | */ 19 | export class CcNgDisable extends CcEvent { 20 | static TYPE = 'cc-ng-disable'; 21 | 22 | constructor() { 23 | super(CcNgDisable.TYPE); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/send-to-api.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface ApiConfig { 2 | API_HOST: string; 3 | API_OAUTH_TOKEN: string; 4 | API_OAUTH_TOKEN_SECRET: string; 5 | OAUTH_CONSUMER_KEY: string; 6 | OAUTH_CONSUMER_SECRET: string; 7 | } 8 | 9 | export interface Warp10ApiConfig { 10 | WARP_10_HOST: string; 11 | API_OAUTH_TOKEN: string; 12 | API_OAUTH_TOKEN_SECRET: string; 13 | OAUTH_CONSUMER_KEY: string; 14 | OAUTH_CONSUMER_SECRET: string; 15 | } 16 | 17 | export interface AuthBridgeConfig { 18 | AUTH_BRIDGE_HOST: string; 19 | API_OAUTH_TOKEN: string; 20 | API_OAUTH_TOKEN_SECRET: string; 21 | OAUTH_CONSUMER_KEY: string; 22 | OAUTH_CONSUMER_SECRET: string; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/cc-toaster/cc-toaster.types.d.ts: -------------------------------------------------------------------------------- 1 | import { NotificationIntent } from '../common.types.js'; 2 | 3 | export type ToastPosition = 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right'; 4 | 5 | export type ToastAnimation = 'fade' | 'slide' | 'fade-and-slide'; 6 | 7 | export interface Notification { 8 | message: string; 9 | title?: string; 10 | intent: NotificationIntent; 11 | options?: ToastOptions; 12 | } 13 | 14 | export interface ToastOptions { 15 | timeout?: number; 16 | closeable?: boolean; 17 | showProgress?: boolean; 18 | } 19 | 20 | export interface Toast extends Notification { 21 | key: string; 22 | dismissing?: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/cc-addon-features/cc-addon-features.types.d.ts: -------------------------------------------------------------------------------- 1 | import { IconModel } from '../common.types.js'; 2 | 3 | export type AddonFeaturesState = AddonFeaturesStateLoaded | AddonFeaturesStateLoading | AddonFeaturesStateError; 4 | 5 | export interface AddonFeature { 6 | name: string; 7 | value: string; 8 | } 9 | 10 | export interface AddonFeaturesStateLoaded { 11 | type: 'loaded'; 12 | features: AddonFeature[]; 13 | } 14 | 15 | export interface AddonFeaturesStateLoading { 16 | type: 'loading'; 17 | } 18 | 19 | export interface AddonFeaturesStateError { 20 | type: 'error'; 21 | } 22 | 23 | export interface AddonFeatureWithIcon extends AddonFeature { 24 | icon?: IconModel; 25 | } 26 | -------------------------------------------------------------------------------- /src/components/cc-addon-linked-apps/cc-addon-linked-apps.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Zone } from '../common.types.js'; 2 | 3 | export type AddonLinkedAppsState = AddonLinkedAppsStateLoading | AddonLinkedAppsStateLoaded | AddonLinkedAppsStateError; 4 | 5 | export interface AddonLinkedAppsStateLoading { 6 | type: 'loading'; 7 | } 8 | 9 | export interface AddonLinkedAppsStateLoaded { 10 | type: 'loaded'; 11 | linkedApplications: Array<LinkedApplication>; 12 | } 13 | 14 | export interface AddonLinkedAppsStateError { 15 | type: 'error'; 16 | } 17 | 18 | export interface LinkedApplication { 19 | name: string; 20 | link: string; 21 | variantName: string; 22 | variantLogoUrl: string; 23 | zone: Zone; 24 | } 25 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" width="115" height="115"><g fill="none" fill-rule="evenodd"><path fill="#AB2B4A" d="M107.998 28.748v57.5L97.297 72.499 91.335 57.5h-.004l5.662-15.209z"/><path fill="#E87A68" d="M8.004 28.748v57.5l9.46-13.333L24.667 57.5h.004l-7.323-14.625z"/><path fill="#D74D4E" d="m91.331 57.5-31.515 1.992L24.667 57.5l14.668-28.752L58.001 0l20.296 31.564z"/><path fill="#BD3246" d="M107.998 28.748 91.331 57.5 58.001 0z"/><path fill="#F19175" d="M58.001 0 24.667 57.5 8 28.748z"/><path fill="#CF3942" d="M91.331 57.5 79.94 82.328 58.001 115 35.424 81.23 24.667 57.5z"/><path fill="#E0625B" d="M58.001 115 8 86.248 24.667 57.5z"/><path fill="#9A244F" d="m57.998 115 50-28.752L91.331 57.5z"/></g></svg> 2 | -------------------------------------------------------------------------------- /src/components/cc-logs-date-range-selector/cc-logs-date-range-selector.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { LogsDateRangeSelectionChangeEventData } from './cc-logs-date-range-selector.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the logs date range selection changes. 9 | * @extends {CcEvent<LogsDateRangeSelectionChangeEventData>} 10 | */ 11 | export class CcLogsDateRangeSelectionChangeEvent extends CcEvent { 12 | static TYPE = 'cc-logs-date-range-selection-change'; 13 | 14 | /** 15 | * @param {LogsDateRangeSelectionChangeEventData} detail 16 | */ 17 | constructor(detail) { 18 | super(CcLogsDateRangeSelectionChangeEvent.TYPE, detail); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/i18n/i18n.types.d.ts: -------------------------------------------------------------------------------- 1 | export type TranslationsMap = { [lang: string]: Translations }; 2 | 3 | export type Translations = { [key: string]: Translation }; 4 | 5 | export type Translation = string | TranslateFunction; 6 | 7 | export type TranslateFunction = (data: any) => Translated; 8 | 9 | export type Translated = string | Node; 10 | 11 | export type DateInput = number | string | Date; 12 | 13 | export type DateFormatter = (dateInput: DateInput) => string; 14 | 15 | export type DateUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second'; 16 | 17 | export type RelativeTimeFormatFunction = (value: number, unit: DateUnit) => string; 18 | 19 | export type NumberFormatter = (number: number) => string; 20 | -------------------------------------------------------------------------------- /src/lib/date/date.types.d.ts: -------------------------------------------------------------------------------- 1 | export type Timezone = 'local' | 'UTC'; 2 | 3 | export type DateFormat = 'datetime-iso' | 'datetime-short'; 4 | 5 | export interface DateFormattedParts { 6 | date: string; 7 | separator: 'T' | ' '; 8 | time: string; 9 | millisecond?: string; 10 | timezone?: string; 11 | } 12 | 13 | export type DateFormattedPart = keyof DateFormattedParts; 14 | 15 | export interface DateParts { 16 | year: string; 17 | month: string; 18 | day: string; 19 | hour: string; 20 | minute: string; 21 | second: string; 22 | millisecond?: string; 23 | timezone?: string; 24 | } 25 | 26 | export type DatePart = keyof DateParts; 27 | 28 | export type DateField = 'Y' | 'M' | 'D' | 'H' | 'm' | 's' | 'S'; 29 | -------------------------------------------------------------------------------- /src/lib/i18n/i18n-display.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get the translated name of a country using its code with a fallback 3 | * 4 | * @param {string} lang - BCP 47 language tag 5 | * @param {string} code - ISO 3166 Country code 6 | * @param {string} name - Country name (fallback) 7 | * @returns {string} 8 | */ 9 | export function getCountryName(lang, code, name) { 10 | // try/catch with fallback on english name because the support is not great for now 11 | // https://caniuse.com/mdn-javascript_builtins_intl_displaynames_of 12 | try { 13 | // This API was not really designed for this but... 14 | return new Intl.DisplayNames([lang], { type: 'region' }).of(code.toUpperCase()); 15 | } catch { 16 | return name; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/cc-heptapod-info/cc-heptapod-info.types.d.ts: -------------------------------------------------------------------------------- 1 | export type HeptapodInfoState = 2 | | HeptapodInfoStateLoaded 3 | | HeptapodInfoStateLoading 4 | | HeptapodInfoStateError 5 | | HeptapodInfoStateNotUsed; 6 | 7 | export interface HeptapodInfoStateLoaded { 8 | type: 'loaded'; 9 | statistics: Statistics; 10 | } 11 | 12 | export interface HeptapodInfoStateLoading { 13 | type: 'loading'; 14 | } 15 | 16 | export interface HeptapodInfoStateError { 17 | type: 'error'; 18 | } 19 | 20 | export interface HeptapodInfoStateNotUsed { 21 | type: 'not-used'; 22 | } 23 | 24 | export interface Statistics { 25 | privateActiveUsers: number; 26 | publicActiveUsers: number; 27 | storage: number; 28 | price: number; 29 | } 30 | -------------------------------------------------------------------------------- /src/lib/ansi/ansi.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface AnsiPalette { 2 | foreground: string; 3 | background: string; 4 | 'background-hover': string; 5 | 'background-selected': string; 6 | black: string; 7 | red: string; 8 | green: string; 9 | yellow: string; 10 | blue: string; 11 | magenta: string; 12 | cyan: string; 13 | white: string; 14 | 'bright-black': string; 15 | 'bright-red': string; 16 | 'bright-green': string; 17 | 'bright-yellow': string; 18 | 'bright-blue': string; 19 | 'bright-magenta': string; 20 | 'bright-cyan': string; 21 | 'bright-white': string; 22 | } 23 | 24 | export interface AnsiPart { 25 | styles: Array<string>; 26 | text: string; 27 | } 28 | 29 | export type ColorName = keyof AnsiPalette; 30 | -------------------------------------------------------------------------------- /src/stories/assets/scaleway.svg: -------------------------------------------------------------------------------- 1 | <svg fill="#4F0599" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Scaleway -------------------------------------------------------------------------------- /test/helpers/mock-now.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} nowIsoString The fake now ISO string 3 | * @param {function} fn the function to execute 4 | */ 5 | export function withMockedNow(nowIsoString, fn) { 6 | const realDate = window.Date; 7 | const fakeNow = new Date(nowIsoString).getTime(); 8 | // @ts-ignore 9 | window.Date = class extends Date { 10 | static now() { 11 | return fakeNow; 12 | } 13 | 14 | // @ts-ignore 15 | constructor(...options) { 16 | if (options.length > 0) { 17 | // @ts-ignore 18 | super(...options); 19 | } else { 20 | super(fakeNow); 21 | } 22 | } 23 | }; 24 | try { 25 | return fn(); 26 | } finally { 27 | window.Date = realDate; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/cc-tile-requests/cc-tile-requests.types.d.ts: -------------------------------------------------------------------------------- 1 | export type RequestsData = [ 2 | number, // Start timestamp in milliseconds. Expected to be rounded to the hour of its respective TZ. 3 | number, // End timestamp in milliseconds. Expected to be rounded to the hour of its respective TZ. 4 | number, // Number of request during this time window. 5 | ]; 6 | 7 | export type TileRequestsState = TileRequestsStateLoaded | TileRequestsStateLoading | TileRequestsStateError; 8 | 9 | export interface TileRequestsStateLoaded { 10 | type: 'loaded'; 11 | data: Array; 12 | } 13 | 14 | export interface TileRequestsStateLoading { 15 | type: 'loading'; 16 | } 17 | 18 | export interface TileRequestsStateError { 19 | type: 'error'; 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/ansi/palettes/hyoob.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @import { AnsiPalette } from '../ansi.types.js' 3 | */ 4 | 5 | /** @type {AnsiPalette} */ 6 | export default { 7 | foreground: '#FFFFFF', 8 | background: '#000000', 9 | 'background-hover': '#1E1E1E', 10 | 'background-selected': '#2B2B2B', 11 | black: '#000000', 12 | red: '#FF4040', 13 | green: '#90AF7D', 14 | yellow: '#FFFF66', 15 | blue: '#9999FF', 16 | magenta: '#FF4BB9', 17 | cyan: '#3AEEE0', 18 | white: '#FFFFFF', 19 | 'bright-black': '#BBBBBB', 20 | 'bright-red': '#FF4040', 21 | 'bright-green': '#90AF7D', 22 | 'bright-yellow': '#FFFF66', 23 | 'bright-blue': '#9999FF', 24 | 'bright-magenta': '#FF4BB9', 25 | 'bright-cyan': '#3AEEE0', 26 | 'bright-white': '#FFFFFF', 27 | }; 28 | -------------------------------------------------------------------------------- /src/lib/regex-parse.js: -------------------------------------------------------------------------------- 1 | const VALID_FLAGS = 'dgimsuy'; 2 | const REGEX_WITH_TRAILING_SLASH = /\/(?.+)\/(?[a-z]*)/i; 3 | 4 | /** 5 | * @param {string} input 6 | * @return {RegExp} 7 | */ 8 | export function parseRegex(input) { 9 | if (input.startsWith('/')) { 10 | const m = input.match(REGEX_WITH_TRAILING_SLASH); 11 | 12 | if (m == null) { 13 | throw new Error('invalid regular expression format'); 14 | } 15 | 16 | const { expression, flags } = m.groups; 17 | 18 | const validFlags = Array.from(new Set(flags)) 19 | .filter((flag) => VALID_FLAGS.includes(flag)) 20 | .join(''); 21 | 22 | return new RegExp(expression, validFlags); 23 | } else { 24 | return new RegExp(input); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/cc-addon-mysql-options/cc-addon-mysql-options.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-addon-mysql-options.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Addon/', 7 | component: 'cc-addon-mysql-options', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-addon-mysql-options', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ options: [{ name: 'encryption', enabled: false }] }], 16 | }); 17 | 18 | export const encryptionEnabled = makeStory(conf, { 19 | items: [{ options: [{ name: 'encryption', enabled: true }] }], 20 | }); 21 | 22 | // This component isn't used when there are no options => no story for this case. 23 | -------------------------------------------------------------------------------- /src/components/cc-addon-redis-options/cc-addon-redis-options.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-addon-redis-options.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Addon/', 7 | component: 'cc-addon-redis-options', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-addon-redis-options', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ options: [{ name: 'encryption', enabled: false }] }], 16 | }); 17 | 18 | export const encryptionEnabled = makeStory(conf, { 19 | items: [{ options: [{ name: 'encryption', enabled: true }] }], 20 | }); 21 | 22 | // This component isn't used when there are no options => no story for this case. 23 | -------------------------------------------------------------------------------- /src/components/cc-visual-tests-report-menu/cc-visual-tests-report-menu.types.d.ts: -------------------------------------------------------------------------------- 1 | import { VisualTestResult } from '../cc-visual-tests-report/visual-tests-report.types.js'; 2 | 3 | export type VisualTestsReportMenuViewportEntry = { 4 | viewportType: VisualTestResult['viewportType']; 5 | browserName: VisualTestResult['browserName']; 6 | id: string; 7 | }; 8 | 9 | export type VisualTestsReportMenuStoryEntry = { 10 | storyName: string; 11 | viewports: Array; 12 | }; 13 | 14 | export type VisualTestsReportMenuComponentEntry = { 15 | componentTagName: string; 16 | stories: Array; 17 | }; 18 | 19 | export type VisualTestsReportMenuEntries = Array; 20 | -------------------------------------------------------------------------------- /src/lib/ansi/palettes/default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @import { AnsiPalette } from '../ansi.types.js' 3 | */ 4 | 5 | /** @type {AnsiPalette} */ 6 | export default { 7 | foreground: '#000000', 8 | background: '#FFFFFF', 9 | 'background-hover': '#F5F5F5', 10 | 'background-selected': '#EBEBEB', 11 | black: '#000000', 12 | red: '#990000', 13 | green: '#0C7814', 14 | yellow: '#6D6B12', 15 | blue: '#0000B2', 16 | magenta: '#B200B2', 17 | cyan: '#28757B', 18 | white: '#BFBFBF', 19 | 'bright-black': '#666666', 20 | 'bright-red': '#D60000', 21 | 'bright-green': '#00D900', 22 | 'bright-yellow': '#E5E500', 23 | 'bright-blue': '#0000FF', 24 | 'bright-magenta': '#E500E5', 25 | 'bright-cyan': '#00E5E5', 26 | 'bright-white': '#E5E5E5', 27 | }; 28 | -------------------------------------------------------------------------------- /src/lib/ansi/palettes/everblush.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @import { AnsiPalette } from '../ansi.types.js' 3 | */ 4 | 5 | /** @type {AnsiPalette} */ 6 | export default { 7 | foreground: '#DADADA', 8 | background: '#141B1E', 9 | 'background-hover': '#1E2528', 10 | 'background-selected': '#282F32', 11 | black: '#232A2D', 12 | red: '#E57474', 13 | green: '#8CCF7E', 14 | yellow: '#E5C76B', 15 | blue: '#67B0E8', 16 | magenta: '#C47FD5', 17 | cyan: '#6CBFBF', 18 | white: '#B3B9B8', 19 | 'bright-black': '#2D3437', 20 | 'bright-red': '#EF7E7E', 21 | 'bright-green': '#96D988', 22 | 'bright-yellow': '#F4D67A', 23 | 'bright-blue': '#71BAF2', 24 | 'bright-magenta': '#CE89DF', 25 | 'bright-cyan': '#67CBE7', 26 | 'bright-white': '#BDC3C2', 27 | }; 28 | -------------------------------------------------------------------------------- /src/lib/ansi/palettes/night-owl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @import { AnsiPalette } from '../ansi.types.js' 3 | */ 4 | 5 | /** @type {AnsiPalette} */ 6 | export default { 7 | foreground: '#D6DEEB', 8 | background: '#011627', 9 | 'background-hover': '#0B2031', 10 | 'background-selected': '#152A3B', 11 | black: '#011627', 12 | red: '#EF5350', 13 | green: '#22DA6E', 14 | yellow: '#ADDB67', 15 | blue: '#82AAFF', 16 | magenta: '#C792EA', 17 | cyan: '#21C7A8', 18 | white: '#FFFFFF', 19 | 'bright-black': '#575656', 20 | 'bright-red': '#EF5350', 21 | 'bright-green': '#22DA6E', 22 | 'bright-yellow': '#FFEB95', 23 | 'bright-blue': '#82AAFF', 24 | 'bright-magenta': '#C792EA', 25 | 'bright-cyan': '#7FDBCA', 26 | 'bright-white': '#FFFFFF', 27 | }; 28 | -------------------------------------------------------------------------------- /src/lib/ansi/palettes/one-light.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @import { AnsiPalette } from '../ansi.types.js' 3 | */ 4 | 5 | /** @type {AnsiPalette} */ 6 | export default { 7 | foreground: '#2A2B32', 8 | background: '#F8F8F8', 9 | 'background-hover': '#EEEEEE', 10 | 'background-selected': '#E4E4E4', 11 | black: '#000000', 12 | red: '#D13B38', 13 | green: '#3B813D', 14 | yellow: '#855504', 15 | blue: '#315EEE', 16 | magenta: '#930092', 17 | cyan: '#0E6FAD', 18 | white: '#8E8F96', 19 | 'bright-black': '#2A2B32', 20 | 'bright-red': '#D13B38', 21 | 'bright-green': '#3B813D', 22 | 'bright-yellow': '#855504', 23 | 'bright-blue': '#315EEE', 24 | 'bright-magenta': '#930092', 25 | 'bright-cyan': '#0E6FAD', 26 | 'bright-white': '#FFFEFE', 27 | }; 28 | -------------------------------------------------------------------------------- /src/components/cc-env-var-linked-services/cc-env-var-linked-services.types.d.ts: -------------------------------------------------------------------------------- 1 | import { EnvVar } from '../common.types.js'; 2 | 3 | export type EnvVarLinkedServicesState = 4 | | EnvVarLinkedServicesStateLoading 5 | | EnvVarLinkedServicesStateLoaded 6 | | EnvVarLinkedServicesStateError; 7 | 8 | interface EnvVarLinkedServicesStateLoading { 9 | type: 'loading'; 10 | } 11 | 12 | interface EnvVarLinkedServicesStateLoaded { 13 | type: 'loaded'; 14 | services: Array; 15 | } 16 | 17 | interface EnvVarLinkedServicesStateError { 18 | type: 'error'; 19 | } 20 | 21 | export type EnvVarLinkedServicesType = 'addon' | 'app'; 22 | 23 | export interface LinkedService { 24 | id: string; 25 | name: string; 26 | variables: Array; 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/ansi/palettes/tokyo-night-light.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @import { AnsiPalette } from '../ansi.types.js' 3 | */ 4 | 5 | /** @type {AnsiPalette} */ 6 | export default { 7 | foreground: '#565A6E', 8 | background: '#D5D6DB', 9 | 'background-hover': '#CBCCD1', 10 | 'background-selected': '#C1C2C7', 11 | black: '#0F0F14', 12 | red: '#8C4351', 13 | green: '#485E30', 14 | yellow: '#855215', 15 | blue: '#34548A', 16 | magenta: '#5A4A78', 17 | cyan: '#0F4B6E', 18 | white: '#343B58', 19 | 'bright-black': '#9699A3', 20 | 'bright-red': '#8C4351', 21 | 'bright-green': '#485E30', 22 | 'bright-yellow': '#855215', 23 | 'bright-blue': '#34548A', 24 | 'bright-magenta': '#5A4A78', 25 | 'bright-cyan': '#0F4B6E', 26 | 'bright-white': '#343B58', 27 | }; 28 | -------------------------------------------------------------------------------- /web-test-runner/cem-analyzer-plugin.js: -------------------------------------------------------------------------------- 1 | import { cli } from '@custom-elements-manifest/analyzer/cli.js'; 2 | 3 | const path = '/dist/custom-elements.json'; 4 | 5 | // This plugin generates and serves the CEM on demand. 6 | export const cemAnalyzerPlugin = { 7 | name: 'cem-analyzer-plugin', 8 | // we disable transform cache to enforce generation for every call 9 | transform(context) { 10 | if (context.path === path) { 11 | return { 12 | transformCache: false, 13 | }; 14 | } 15 | }, 16 | async serve(context) { 17 | if (context.path === path) { 18 | const cemJson = await cli({ 19 | argv: ['analyze'], 20 | noWrite: true, 21 | }); 22 | 23 | return JSON.stringify(cemJson); 24 | } 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/components/cc-addon-jenkins-options/cc-addon-jenkins-options.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-addon-jenkins-options.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Addon/', 7 | component: 'cc-addon-jenkins-options', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-addon-jenkins-options', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ options: [{ name: 'encryption', enabled: false }] }], 16 | }); 17 | 18 | export const encryptionEnabled = makeStory(conf, { 19 | items: [{ options: [{ name: 'encryption', enabled: true }] }], 20 | }); 21 | 22 | // This component isn't used when there are no options => no story for this case. 23 | -------------------------------------------------------------------------------- /src/components/cc-addon-mongodb-options/cc-addon-mongodb-options.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-addon-mongodb-options.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Addon/', 7 | component: 'cc-addon-mongodb-options', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-addon-mongodb-options', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ options: [{ name: 'encryption', enabled: false }] }], 16 | }); 17 | 18 | export const encryptionEnabled = makeStory(conf, { 19 | items: [{ options: [{ name: 'encryption', enabled: true }] }], 20 | }); 21 | 22 | // This component isn't used when there are no options => no story for this case. 23 | -------------------------------------------------------------------------------- /src/components/cc-feature-list/cc-feature-list.types.d.ts: -------------------------------------------------------------------------------- 1 | export type FeatureListState = FeatureListStateLoaded | FeatureListStateLoading | FeatureListStateError; 2 | 3 | export type FeatureStatus = 'alpha' | 'beta' | 'preview'; 4 | 5 | export interface Feature { 6 | id: string; 7 | name: string; 8 | description: string; 9 | options: { label: string; value: string }[]; 10 | value: string; 11 | status?: FeatureStatus; 12 | documentationLink?: string; 13 | feedbackLink?: string; 14 | } 15 | 16 | export interface FeatureListStateLoaded { 17 | type: 'loaded'; 18 | featureList: Feature[]; 19 | } 20 | 21 | export interface FeatureListStateLoading { 22 | type: 'loading'; 23 | } 24 | 25 | export interface FeatureListStateError { 26 | type: 'error'; 27 | } 28 | -------------------------------------------------------------------------------- /src/components/cc-elasticsearch-info/cc-elasticsearch-info.types.d.ts: -------------------------------------------------------------------------------- 1 | export type ElasticSearchInfoState = 2 | | ElasticSearchInfoStateLoaded 3 | | ElasticSearchInfoStateLoading 4 | | ElasticSearchInfoStateError; 5 | 6 | export interface ElasticSearchInfoStateLoaded { 7 | type: 'loaded'; 8 | links: LinkLoaded[]; 9 | } 10 | 11 | export interface ElasticSearchInfoStateLoading { 12 | type: 'loading'; 13 | links: LinkLoading[]; 14 | } 15 | 16 | export interface ElasticSearchInfoStateError { 17 | type: 'error'; 18 | } 19 | 20 | export interface LinkLoaded { 21 | type: LinkType; 22 | href: string; 23 | } 24 | 25 | export interface LinkLoading { 26 | type: LinkType; 27 | href?: null; 28 | } 29 | 30 | export type LinkType = 'elasticsearch' | 'kibana' | 'apm'; 31 | -------------------------------------------------------------------------------- /src/components/cc-grafana-info/cc-grafana-info.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * Dispatch when grafana activation or deactivation is requested. 5 | * @extends {CcEvent<{isEnabled: boolean}>} 6 | */ 7 | export class CcGrafanaToggleEvent extends CcEvent { 8 | static TYPE = 'cc-grafana-toggle'; 9 | 10 | /** 11 | * @param {{isEnabled: boolean}} detail 12 | */ 13 | constructor(detail) { 14 | super(CcGrafanaToggleEvent.TYPE, detail); 15 | } 16 | } 17 | 18 | /** 19 | * Dispatch when grafana reset is requested. 20 | * @extends {CcEvent} 21 | */ 22 | export class CcGrafanaResetEvent extends CcEvent { 23 | static TYPE = 'cc-grafana-reset'; 24 | 25 | constructor() { 26 | super(CcGrafanaResetEvent.TYPE); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/cc-grafana-info/cc-grafana-info.types.d.ts: -------------------------------------------------------------------------------- 1 | export type GrafanaInfoState = GrafanaInfoStateLoading | GrafanaInfoStateLoadingError | GrafanaInfoStateLoaded; 2 | 3 | export interface GrafanaInfoStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | export interface GrafanaInfoStateLoadingError { 8 | type: 'error'; 9 | } 10 | 11 | export interface GrafanaInfoStateLoaded { 12 | type: 'loaded'; 13 | info: GrafanaInfo; 14 | } 15 | 16 | export type GrafanaInfo = GrafanaInfoEnabled | GrafanaInfoDisabled; 17 | 18 | export interface GrafanaInfoEnabled { 19 | status: 'enabled'; 20 | link?: string; 21 | action?: 'disabling' | 'resetting' | null; 22 | } 23 | 24 | export interface GrafanaInfoDisabled { 25 | status: 'disabled'; 26 | action?: 'enabling' | null; 27 | } 28 | -------------------------------------------------------------------------------- /src/assets/baseline-newly.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/cc-addon-postgresql-options/cc-addon-postgresql-options.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-addon-postgresql-options.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Addon/', 7 | component: 'cc-addon-postgresql-options', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-addon-postgresql-options', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ options: [{ name: 'encryption', enabled: false }] }], 16 | }); 17 | 18 | export const encryptionEnabled = makeStory(conf, { 19 | items: [{ options: [{ name: 'encryption', enabled: true }] }], 20 | }); 21 | 22 | // This component isn't used when there are no options => no story for this case. 23 | -------------------------------------------------------------------------------- /src/components/cc-tcp-redirection-form/cc-tcp-redirection-form.types.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TcpRedirectionStateLoaded, 3 | TcpRedirectionStateWaiting, 4 | } from '../cc-tcp-redirection/cc-tcp-redirection.types.js'; 5 | 6 | export type TcpRedirectionFormContextType = 'user' | 'admin'; 7 | 8 | export type TcpRedirectionFormState = 9 | | TcpRedirectionFormStateLoading 10 | | TcpRedirectionFormStateLoaded 11 | | TcpRedirectionFormStateError; 12 | 13 | export interface TcpRedirectionFormStateLoading { 14 | type: 'loading'; 15 | } 16 | 17 | export interface TcpRedirectionFormStateLoaded { 18 | type: 'loaded'; 19 | redirections: Array; 20 | } 21 | 22 | export interface TcpRedirectionFormStateError { 23 | type: 'error'; 24 | } 25 | -------------------------------------------------------------------------------- /src/components/cc-logs-app-runtime/cc-logs-app-runtime.types.d.ts: -------------------------------------------------------------------------------- 1 | import { LogsStreamState } from '../../lib/logs/logs-stream.types.js'; 2 | import { GhostInstance, Instance } from '../cc-logs-instances/cc-logs-instances.types.js'; 3 | 4 | export interface LogsAppRuntimeStateLoadingInstances { 5 | type: 'loadingInstances'; 6 | } 7 | 8 | export interface LogsAppRuntimeStateErrorInstances { 9 | type: 'errorInstances'; 10 | } 11 | 12 | export interface LogsAppRuntimeStateLoaded { 13 | type: 'loaded'; 14 | streamState: LogsStreamState; 15 | instances: Array; 16 | selection: Array; 17 | } 18 | 19 | export type LogsAppRuntimeState = 20 | | LogsAppRuntimeStateLoadingInstances 21 | | LogsAppRuntimeStateErrorInstances 22 | | LogsAppRuntimeStateLoaded; 23 | -------------------------------------------------------------------------------- /src/components/cc-tcp-redirection/cc-tcp-redirection.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface TcpRedirection { 2 | namespace: string; 3 | isPrivate: boolean; 4 | sourcePort?: number | null; 5 | } 6 | 7 | export type TcpRedirectionState = TcpRedirectionStateLoading | TcpRedirectionStateLoaded | TcpRedirectionStateWaiting; 8 | 9 | export interface TcpRedirectionStateLoading { 10 | type: 'loading'; 11 | } 12 | 13 | export interface TcpRedirectionStateLoaded extends TcpRedirection { 14 | type: 'loaded'; 15 | } 16 | 17 | export interface TcpRedirectionStateWaiting extends TcpRedirection { 18 | type: 'waiting'; 19 | } 20 | 21 | export interface CreateTcpRedirection { 22 | namespace: string; 23 | } 24 | 25 | export interface DeleteTcpRedirection { 26 | namespace: string; 27 | sourcePort: number; 28 | } 29 | -------------------------------------------------------------------------------- /src/stories/assets/left.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/stories/assets/right.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/stories/fixtures/fake-map-data.js: -------------------------------------------------------------------------------- 1 | import fakePointsDataBig from './country-city-points-big-orga.js'; 2 | import fakePointsDataMedium from './country-city-points-medium-orga.js'; 3 | import fakePointsDataNormal from './country-city-points-normal-orga.js'; 4 | 5 | const FAKE_POINTS_DATA = [ 6 | fakePointsDataNormal, 7 | fakePointsDataMedium, 8 | fakePointsDataBig, 9 | ]; 10 | 11 | let lastSampleIndex; 12 | let fakeDataIndex = 0; 13 | 14 | export function getFakePointsData (sampleIndex) { 15 | if (sampleIndex !== lastSampleIndex) { 16 | fakeDataIndex = 0; 17 | lastSampleIndex = sampleIndex; 18 | } 19 | const data = Promise.resolve(FAKE_POINTS_DATA[sampleIndex][fakeDataIndex]); 20 | fakeDataIndex = (fakeDataIndex + 1) % FAKE_POINTS_DATA[sampleIndex].length; 21 | return data; 22 | } 23 | -------------------------------------------------------------------------------- /tasks/cdn-entry-name.js: -------------------------------------------------------------------------------- 1 | import semver from 'semver'; 2 | 3 | /** 4 | * 5 | * @param {CdnEnvironment} cdnEnvironment 6 | * @param {string} name 7 | * @return {string} 8 | */ 9 | export function toCdnEntryName(cdnEnvironment, name) { 10 | if (name == null) { 11 | throw new Error('Invalid CDN entry name: It cannot be null.'); 12 | } 13 | 14 | const result = name.trim(); 15 | 16 | if (result.length === 0) { 17 | throw new Error('Invalid CDN entry name: It cannot be empty.'); 18 | } 19 | 20 | if (cdnEnvironment.semver) { 21 | if (semver.valid(result) == null) { 22 | throw new Error(`Invalid CDN entry name '${result}': It must be a valid version.`); 23 | } 24 | 25 | return result; 26 | } 27 | 28 | return result.replaceAll('/', '-').replaceAll(' ', '-'); 29 | } 30 | -------------------------------------------------------------------------------- /src/components/cc-header-addon/cc-header-addon.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Addon, Zone } from '../common.types.js'; 2 | 3 | export type HeaderAddonState = 4 | | HeaderAddonStateLoaded 5 | | HeaderAddonStateLoadedWithVersion 6 | | HeaderAddonStateLoading 7 | | HeaderAddonStateError; 8 | 9 | export interface HeaderAddonStateLoaded extends Addon { 10 | type: 'loaded'; 11 | hasVersion: false; 12 | zone: Zone; 13 | } 14 | 15 | export interface HeaderAddonStateLoadedWithVersion extends Addon { 16 | type: 'loaded'; 17 | hasVersion: true; 18 | version: string; 19 | zone: Zone; 20 | } 21 | 22 | export interface HeaderAddonStateLoading { 23 | type: 'loading'; 24 | hasVersion: boolean; 25 | } 26 | 27 | export interface HeaderAddonStateError { 28 | type: 'error'; 29 | hasVersion: boolean; 30 | } 31 | -------------------------------------------------------------------------------- /src/stories/assets/justify.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/stories/assets/center.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/cc-token-api-update-form/cc-token-api-update-form.types.d.ts: -------------------------------------------------------------------------------- 1 | export type TokenApiUpdateFormState = 2 | | TokenApiUpdateFormStateLoading 3 | | TokenApiUpdateFormStateError 4 | | TokenApiUpdateFormStateLoaded 5 | | TokenApiUpdateFormStateUpdating; 6 | 7 | export interface TokenApiUpdateFormStateLoading { 8 | type: 'loading'; 9 | } 10 | 11 | export interface TokenApiUpdateFormStateError { 12 | type: 'error'; 13 | } 14 | 15 | type FormValues = { 16 | name: string; 17 | description?: string; 18 | }; 19 | 20 | export interface TokenApiUpdateFormStateLoaded { 21 | type: 'loaded'; 22 | values: FormValues; 23 | } 24 | 25 | export interface TokenApiUpdateFormStateUpdating { 26 | type: 'updating'; 27 | values: FormValues; 28 | } 29 | 30 | export type CcTokenChangePayload = Required; 31 | -------------------------------------------------------------------------------- /test-mocha/cem/fixtures/cc-test-component-with-import.js: -------------------------------------------------------------------------------- 1 | import { LitElement } from 'lit'; 2 | 3 | /** 4 | * @import {Foo, Bar} from './cc-test-component.types.js' 5 | * @import {TheInterface} from './cc-test-component.types.js' 6 | * @import {TheType} from './cc-test-component.types.js' 7 | */ 8 | 9 | /** 10 | * Test component using @import syntax instead of @typedef 11 | */ 12 | // eslint-disable-next-line wc/define-tag-after-class-definition 13 | export class CcTestComponentWithImport extends LitElement { 14 | constructor() { 15 | super(); 16 | 17 | /** @type {Foo|Bar} - lorem ipsum. */ 18 | this.union = null; 19 | 20 | /** @type {TheInterface} - lorem ipsum. */ 21 | this.interface = null; 22 | 23 | /** @type {TheType} - lorem ipsum. */ 24 | this.typeDeclaration = null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/contributing/tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | kind: '👋 Contributing' 3 | title: 'Tools' 4 | --- 5 | 6 | # Tools reference 7 | 8 | Here's list of tools we recommand to work on this project: 9 | 10 | * [OctoLinker](https://github.com/OctoLinker/OctoLinker) 11 | * [Refined GitHub](https://github.com/refined-github/refined-github) 12 | * [VSCode](https://code.visualstudio.com/) 13 | * [lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin) 14 | * [Inline HTML](https://marketplace.visualstudio.com/items?itemName=pushqrdx.inline-html) 15 | * [WebStorm](https://www.jetbrains.com/fr-fr/webstorm/) 16 | * [clever-tools](https://github.com/CleverCloud/clever-tools) 17 | * [s3cmd](https://s3tools.org/s3cmd) 18 | * [Volta](https://volta.sh/) 19 | * [Web Component Dev Tools](https://open-wc.org/guides/tools/web-component-devtools/#download) 20 | -------------------------------------------------------------------------------- /sandbox/sandbox-styles.js: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | // language=CSS 4 | export const sandboxStyles = css` 5 | :host { 6 | display: grid; 7 | gap: 1em; 8 | grid-template-areas: 9 | 'ctrl-top .' 10 | 'main ctrl-right'; 11 | grid-template-columns: 1fr max-content; 12 | grid-template-rows: max-content 1fr; 13 | } 14 | 15 | .ctrl-top { 16 | align-items: center; 17 | display: flex; 18 | flex-wrap: wrap; 19 | gap: 0.5em; 20 | grid-area: ctrl-top; 21 | } 22 | 23 | .ctrl-right { 24 | display: flex; 25 | flex-direction: column; 26 | gap: 0.5em; 27 | grid-area: ctrl-right; 28 | } 29 | 30 | .main { 31 | background-color: #f1f4f9; /* this is the color used in console3 */ 32 | border: 1px solid #8aa3cd; 33 | grid-area: main; 34 | padding: 0.5em; 35 | } 36 | `; 37 | -------------------------------------------------------------------------------- /src/components/cc-logs-control/cc-logs-control.types.d.ts: -------------------------------------------------------------------------------- 1 | import { Timezone } from '../../lib/date/date.types.js'; 2 | import { DateDisplay } from '../cc-logs/date-display.types.js'; 3 | 4 | export type LogsControlPalette = 'default' | 'One Light' | 'Tokyo Night Light' | 'Night Owl' | 'Everblush' | 'Hyoob'; 5 | 6 | export interface LogsMetadataDisplay { 7 | label: string; 8 | hidden: boolean; 9 | } 10 | 11 | export interface LogsOptions { 12 | 'date-display': DateDisplay; 13 | 'metadata-display': Record; 14 | palette: LogsControlPalette; 15 | timezone: Timezone; 16 | 'wrap-lines': boolean; 17 | 'strip-ansi': boolean; 18 | } 19 | 20 | export interface LogsOptionsChangeEventData { 21 | /** The name of the option that has changed */ 22 | name: keyof LogsOptions; 23 | /** The new options */ 24 | options: LogsOptions; 25 | } 26 | -------------------------------------------------------------------------------- /src/components/cc-pricing-product-consumption/cc-pricing-product-consumption.types.d.ts: -------------------------------------------------------------------------------- 1 | import { PricingSection, SectionType } from '../common.types.js'; 2 | 3 | interface PricingProductConsumptionStateLoading { 4 | type: 'loading'; 5 | } 6 | 7 | interface PricingProductConsumptionStateError { 8 | type: 'error'; 9 | } 10 | 11 | interface PricingProductConsumptionStateLoaded { 12 | type: 'loaded'; 13 | name: string; 14 | sections: PricingSection[]; 15 | } 16 | 17 | export type PricingProductConsumptionState = 18 | | PricingProductConsumptionStateLoading 19 | | PricingProductConsumptionStateError 20 | | PricingProductConsumptionStateLoaded; 21 | 22 | export type SectionStates = Partial< 23 | Record< 24 | SectionType, 25 | { 26 | isClosed: boolean; 27 | quantity: number; 28 | unitValue: string; 29 | } 30 | > 31 | >; 32 | -------------------------------------------------------------------------------- /src/lib/notifications.js: -------------------------------------------------------------------------------- 1 | import { CcNotifyEvent } from './notifications.events.js'; 2 | 3 | /** 4 | * @import { Notification } from '../components/common.types.js' 5 | */ 6 | 7 | /** 8 | * @param {Notification} notification 9 | * @param {Window|Node} target 10 | */ 11 | export function notify(notification, target = window) { 12 | target.dispatchEvent(new CcNotifyEvent(notification)); 13 | } 14 | 15 | /** 16 | * @param {string|Node} message 17 | * @param {string} [title] 18 | */ 19 | export function notifyError(message, title) { 20 | notify({ 21 | message, 22 | title, 23 | intent: 'danger', 24 | }); 25 | } 26 | 27 | /** 28 | * @param {string|Node} message 29 | * @param {string} [title] 30 | */ 31 | export function notifySuccess(message, title) { 32 | notify({ 33 | message, 34 | title, 35 | intent: 'success', 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /docs/getting-started/manual-installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | kind: '🏡 Getting Started' 3 | title: 'Manual installation' 4 | --- 5 | 6 | # How to install components manually? 7 | 8 | ## Theme 9 | 10 | 11 |
With this solution, you won't get automatic updates. You will need to check the changelog for potential breaking changes and update your local copy every time.
12 |
13 | 14 |
15 | 16 | If your project toolchain is not based on Node.js and npm, you can copy-paste the CSS file in your own source code. 17 | 18 | The CSS file to copy is available at (replace `` with the one you're using): 19 | 20 | ``` 21 | https://github.com/CleverCloud/clever-components/blob//src/styles/default-theme.css 22 | ``` 23 | -------------------------------------------------------------------------------- /src/components/cc-map-marker-server/cc-map-marker-server.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-map-marker-server.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Maps/', 7 | component: 'cc-map-marker-server', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-map-marker-server', 12 | displayMode: 'flex-wrap', 13 | }; 14 | 15 | export const defaultStory = makeStory(conf, { 16 | items: [{ state: 'default' }, { state: 'hovered' }, { state: 'selected' }], 17 | }); 18 | 19 | export const stateWithDefault = makeStory(conf, { 20 | items: [{ state: 'default' }], 21 | }); 22 | 23 | export const stateWithHovered = makeStory(conf, { 24 | items: [{ state: 'hovered' }], 25 | }); 26 | 27 | export const stateWithSelected = makeStory(conf, { 28 | items: [{ state: 'selected' }], 29 | }); 30 | -------------------------------------------------------------------------------- /src/components/cc-logs/cc-logs.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { Log } from './cc-logs.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the logs follow state changed after a user interaction. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcLogsFollowChangeEvent extends CcEvent { 12 | static TYPE = 'cc-logs-follow-change'; 13 | 14 | /** 15 | * @param {boolean} detail 16 | */ 17 | constructor(detail) { 18 | super(CcLogsFollowChangeEvent.TYPE, detail); 19 | } 20 | } 21 | 22 | /** 23 | * Dispatched when log inspect is requested 24 | * @extends {CcEvent} 25 | */ 26 | export class CcLogInspectEvent extends CcEvent { 27 | static TYPE = 'cc-log-inspect'; 28 | 29 | /** 30 | * @param {Log} detail 31 | */ 32 | constructor(detail) { 33 | super(CcLogInspectEvent.TYPE, detail); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/lib/i18n/i18n-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Prepares a plural() function for a given lang 3 | * 4 | * @param {string} lang - BCP 47 language tag 5 | * @returns {(number: number, one: string, other?: string) => string} 6 | */ 7 | export function preparePlural(lang) { 8 | const pr = new Intl.PluralRules(lang); 9 | 10 | /** 11 | * Based on https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules 12 | * 13 | * @param {number} number - The number to get a plural rule for. 14 | * @param {string} one - The singular form of the string. 15 | * @param {string} [other] - The plural form of the string (optional with automatic "s" suffix). 16 | * @returns {string} 17 | */ 18 | return function plural(number, one, other = one + 's') { 19 | const rules = { zero: one, one, two: other, few: other, many: other, other }; 20 | return rules[pr.select(number)]; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/styles/skeleton.js: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | // language=CSS 4 | export const skeletonStyles = css` 5 | @keyframes skeleton-pulse { 6 | from { 7 | opacity: 0.85; 8 | } 9 | 10 | to { 11 | opacity: 0.45; 12 | } 13 | } 14 | 15 | /* FIXME: temporary solution for Safari until we build a directive for skeletons. See https://github.com/CleverCloud/clever-components/issues/1111 for more info */ 16 | * { 17 | animation: none; 18 | } 19 | 20 | .skeleton { 21 | animation-direction: alternate; 22 | animation-duration: 500ms; 23 | animation-iteration-count: infinite; 24 | animation-name: skeleton-pulse; 25 | animation-play-state: var(--cc-skeleton-state, running); 26 | color: transparent; 27 | cursor: progress; 28 | -moz-user-select: none; 29 | -webkit-user-select: none; 30 | -ms-user-select: none; 31 | user-select: none; 32 | } 33 | `; 34 | -------------------------------------------------------------------------------- /src/components/cc-code/cc-code.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-code.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🧬 Atoms/', 7 | component: 'cc-code', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-code', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{ innerHTML: `clever help` }], 16 | }); 17 | 18 | export const multiLines = makeStory(conf, { 19 | items: [ 20 | { 21 | innerHTML: ` 22 | { 23 | "name" : "myApp", 24 | "version" : "0.1.0", 25 | "main" : "myApp.js", 26 | } 27 | `, 28 | }, 29 | ], 30 | }); 31 | 32 | export const longLine = makeStory(conf, { 33 | items: [ 34 | { 35 | innerHTML: `GET /api/orders/checkout?session_id=cs_test_a1B2c3D4E5f6G7h8I9J0kLmNoPqRsTuVwXyZ1234567890abcdef1234567890abcdef HTTP/1.1`, 36 | }, 37 | ], 38 | }); 39 | -------------------------------------------------------------------------------- /src/components/cc-env-var-create/cc-env-var-create.stories.js: -------------------------------------------------------------------------------- 1 | import { makeStory } from '../../stories/lib/make-story.js'; 2 | import './cc-env-var-create.js'; 3 | 4 | export default { 5 | tags: ['autodocs'], 6 | title: '🛠 Environment variables/', 7 | component: 'cc-env-var-create', 8 | }; 9 | 10 | const conf = { 11 | component: 'cc-env-var-create', 12 | }; 13 | 14 | export const defaultStory = makeStory(conf, { 15 | items: [{}], 16 | }); 17 | 18 | export const validationWithExistingNames = makeStory(conf, { 19 | docs: 'In this example `FOO` and `BAR` are already defined and cannot be used as a variable name again.', 20 | items: [{ variablesNames: ['FOO', 'BAR'], _variableName: 'FOO' }], 21 | }); 22 | 23 | export const validationWithStrictMode = makeStory(conf, { 24 | items: [{ validationMode: 'strict' }], 25 | }); 26 | 27 | export const disabled = makeStory(conf, { 28 | items: [{ disabled: true }], 29 | }); 30 | -------------------------------------------------------------------------------- /src/components/cc-token-api-update-form/cc-token-api-update-form.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { CcTokenChangePayload } from './cc-token-api-update-form.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when the update token form is submitted 9 | * @extends {CcEvent} 10 | */ 11 | export class CcTokenChangeEvent extends CcEvent { 12 | static TYPE = 'cc-token-change'; 13 | 14 | /** @param {CcTokenChangePayload} detail */ 15 | constructor(detail) { 16 | super(CcTokenChangeEvent.TYPE, detail); 17 | } 18 | } 19 | 20 | /** 21 | * Dispatched when the API token has been updated successfully 22 | * @extends {CcEvent} 23 | */ 24 | export class CcTokenWasUpdatedEvent extends CcEvent { 25 | static TYPE = 'cc-token-was-updated'; 26 | 27 | /** @param {string} detail */ 28 | constructor(detail) { 29 | super(CcTokenWasUpdatedEvent.TYPE, detail); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/cc-kv-terminal/cc-kv-terminal.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { CcKvTerminalState } from './cc-kv-terminal.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when KV terminal state changes. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcKvTerminalStateChangeEvent extends CcEvent { 12 | static TYPE = 'cc-kv-terminal-state-change'; 13 | 14 | /** 15 | * @param {CcKvTerminalState} detail 16 | */ 17 | constructor(detail) { 18 | super(CcKvTerminalStateChangeEvent.TYPE, detail); 19 | } 20 | } 21 | 22 | /** 23 | * Dispatched when a KV command execution is requested. 24 | * @extends {CcEvent} 25 | */ 26 | export class CcKvCommandExecuteEvent extends CcEvent { 27 | static TYPE = 'cc-kv-command-execute'; 28 | 29 | /** 30 | * @param {string} detail 31 | */ 32 | constructor(detail) { 33 | super(CcKvCommandExecuteEvent.TYPE, detail); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /web-test-runner/wds-common.js: -------------------------------------------------------------------------------- 1 | import rollupCommonjs from '@rollup/plugin-commonjs'; 2 | import { fromRollup } from '@web/dev-server-rollup'; 3 | import { esbuildBundlePlugin } from './esbuild-bundle-plugin.js'; 4 | 5 | const commonjs = fromRollup(rollupCommonjs); 6 | 7 | function commonJsIdentifiers(ids) { 8 | return ids.map((id) => `**/node_modules/${id}/**/*`); 9 | } 10 | 11 | // regroup ES module files into one bundle 12 | export const esbuildBundlePluginWithConfig = esbuildBundlePlugin({ 13 | pathsToBundle: ['/src/lib/leaflet-esm.js', '/node_modules/chart.js/dist/chart.esm.js'], 14 | }); 15 | 16 | // convert CommonJS modules to ES6 to be included in the rollup bundle 17 | export const commonjsPluginWithConfig = commonjs({ 18 | // the commonjs plugin is slow, list the required packages explicitly: 19 | include: commonJsIdentifiers([ 20 | 'statuses', 21 | // used by clever-client 22 | 'oauth-1.0a', 23 | 'component-emitter', 24 | ]), 25 | }); 26 | -------------------------------------------------------------------------------- /src/templates/cc-addon-encryption-at-rest-option/cc-addon-encryption-at-rest-option.js: -------------------------------------------------------------------------------- 1 | import { html } from 'lit'; 2 | import { iconRemixShieldKeyholeFill as iconEncryptionAtRest } from '../../assets/cc-remix.icons.js'; 3 | import '../../components/cc-icon/cc-icon.js'; 4 | import { i18n } from '../../translations/translation.js'; 5 | 6 | /** 7 | * @import { EncryptionAddonOption, AddonOptionWithMetadata } from '../../components/common.types.js' 8 | */ 9 | 10 | /** @type {(option: EncryptionAddonOption) => AddonOptionWithMetadata & EncryptionAddonOption} */ 11 | export const ccAddonEncryptionAtRestOption = ({ enabled }) => { 12 | const description = html` 13 |
${i18n('cc-addon-encryption-at-rest-option.description')}
14 | `; 15 | 16 | return { 17 | title: i18n('cc-addon-encryption-at-rest-option.title'), 18 | icon: iconEncryptionAtRest, 19 | description, 20 | enabled, 21 | name: 'encryption', 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/components/cc-logs-date-range-selector/cc-logs-date-range-selector.types.d.ts: -------------------------------------------------------------------------------- 1 | import { DateRange } from '../../lib/date/date-range.types.js'; 2 | 3 | export type LogsDateRangeSelection = 4 | | LogsDateRangeSelectionLive 5 | | LogsDateRangeSelectionPreset 6 | | LogsDateRangeSelectionCustom; 7 | 8 | export interface LogsDateRangeSelectionLive { 9 | type: 'live'; 10 | } 11 | 12 | export interface LogsDateRangeSelectionPreset { 13 | type: 'preset'; 14 | preset: LogsDateRangePresetType; 15 | } 16 | 17 | export interface LogsDateRangeSelectionCustom { 18 | type: 'custom'; 19 | since: string; 20 | until: string; 21 | } 22 | 23 | export type LogsDateRangePresetType = 'lastHour' | 'last4Hours' | 'last7Days' | 'today' | 'yesterday'; 24 | 25 | export type LogsDateRangeSelectOption = 'live' | 'custom' | LogsDateRangePresetType; 26 | 27 | export interface LogsDateRangeSelectionChangeEventData { 28 | selection: LogsDateRangeSelection; 29 | range: DateRange; 30 | } 31 | -------------------------------------------------------------------------------- /test/helpers/story-testing-utils.types.d.ts: -------------------------------------------------------------------------------- 1 | import type { AnnotatedStoryFn } from '@storybook/csf'; 2 | import type { StoryObj, WebComponentsRenderer } from '@storybook/web-components'; 3 | 4 | export type StoryParams = StoryObj['parameters']; 5 | 6 | export type AccessibilityTestOptions = { 7 | tests: { 8 | accessibility: { 9 | enable: boolean; 10 | ignoredRules: Array; 11 | }; 12 | }; 13 | }; 14 | 15 | export type AnnotatedStoryFnClever = AnnotatedStoryFn & { 16 | parameters: StoryParams & AccessibilityTestOptions; 17 | }; 18 | 19 | export type RawStoriesModule = { 20 | default: { 21 | component: keyof HTMLElementTagNameMap; 22 | }; 23 | } & { [storyName: string]: AnnotatedStoryFnClever } & {}; 24 | 25 | export type ArrayOfStoryFunctions = Array<{ storyName: string; storyFunction: AnnotatedStoryFnClever }>; 26 | 27 | export type ModuleEntryWithStoryFunction = [storyName: string, storyFunction: AnnotatedStoryFnClever]; 28 | -------------------------------------------------------------------------------- /src/components/cc-orga-member-list/cc-orga-member-list.types.d.ts: -------------------------------------------------------------------------------- 1 | import { OrgaMemberCardState, OrgaMemberRole } from '../cc-orga-member-card/cc-orga-member-card.types.js'; 2 | 3 | export type OrgaMemberListState = OrgaMemberListStateLoading | OrgaMemberListStateLoaded | OrgaMemberListStateError; 4 | 5 | interface OrgaMemberListStateLoading { 6 | type: 'loading'; 7 | } 8 | 9 | interface OrgaMemberListStateLoaded { 10 | type: 'loaded'; 11 | memberList: OrgaMemberCardState[]; 12 | identityFilter: string; 13 | mfaDisabledOnlyFilter: boolean; 14 | dangerZoneState: 'idle' | 'leaving' | 'error'; 15 | } 16 | 17 | interface OrgaMemberListStateError { 18 | type: 'error'; 19 | } 20 | 21 | export interface InviteMember { 22 | email: string; 23 | role: OrgaMemberRole; 24 | } 25 | 26 | interface ListAuthorisations { 27 | invite: boolean; 28 | edit: boolean; 29 | delete: boolean; 30 | } 31 | 32 | export interface InviteMemberFormState { 33 | type: 'idle' | 'inviting'; 34 | } 35 | -------------------------------------------------------------------------------- /src/components/cc-kv-terminal/cc-kv-terminal.types.d.ts: -------------------------------------------------------------------------------- 1 | export type CcKvTerminalState = CcKvTerminalStateIdle | CcKvTerminalStateRunning; 2 | 3 | export interface CcKvTerminalStateIdle { 4 | type: 'idle'; 5 | history: Array; 6 | } 7 | 8 | export interface CcKvTerminalStateRunning { 9 | type: 'running'; 10 | commandLine: string; 11 | history: Array; 12 | } 13 | 14 | export interface CcKvCommandHistoryEntry { 15 | commandLine: string; 16 | result: Array; 17 | success: boolean; 18 | } 19 | 20 | export type CcKvCommandContentItem = CcKvCommandContentItemCommandLine | CcKvCommandContentItemResultLine; 21 | 22 | interface CcKvCommandContentItemCommandLine { 23 | id: string; 24 | type: 'commandLine'; 25 | line: string; 26 | hasResult: boolean; 27 | } 28 | 29 | interface CcKvCommandContentItemResultLine { 30 | id: string; 31 | type: 'resultLine'; 32 | line: string; 33 | success: boolean; 34 | last: boolean; 35 | } 36 | -------------------------------------------------------------------------------- /src/components/cc-pricing-estimation/cc-pricing-estimation.types.d.ts: -------------------------------------------------------------------------------- 1 | import { ConsumptionPlan, Plan, PricingSection } from '../common.types.js'; 2 | 3 | export type PricingEstimationState = 4 | | PricingEstimationStateLoaded 5 | | PricingEstimationStateLoading 6 | | PricingEstimationStateError; 7 | 8 | export interface PricingEstimationStateError { 9 | type: 'error'; 10 | } 11 | 12 | export interface PricingEstimationStateLoading { 13 | type: 'loading'; 14 | } 15 | 16 | export interface PricingEstimationStateLoaded { 17 | type: 'loaded'; 18 | runtimePrices: Array; 19 | countablePrices: Array; 20 | } 21 | 22 | export interface FormattedRuntimePrice { 23 | priceId: string; 24 | price: number; 25 | } 26 | 27 | export interface RuntimePlanWithQuantity extends Plan { 28 | quantity: number; 29 | } 30 | 31 | export interface CountablePlanWithQuantity extends ConsumptionPlan { 32 | quantity: number; 33 | sections: PricingSection[]; 34 | } 35 | -------------------------------------------------------------------------------- /web-test-runner/esbuild-bundle-plugin.js: -------------------------------------------------------------------------------- 1 | import esbuild from 'esbuild'; 2 | 3 | // /!\ This is an experimental plugin for now 4 | // We created this because some of our deps have way to many separated ES module files (Leaflet, chart.js...) 5 | export function esbuildBundlePlugin({ pathsToBundle }) { 6 | return { 7 | async transform(context) { 8 | if (pathsToBundle.includes(context.request.url)) { 9 | const bundle = esbuild.buildSync({ 10 | entryPoints: [context.request.url.slice(1)], 11 | bundle: true, 12 | format: 'esm', 13 | minify: true, 14 | write: false, 15 | // prevents esbuild from bundling types instead of the actual package 16 | // because of the `paths` option within the regular `tsconfig.json` file 17 | tsconfig: 'src/lib/leaflet/tsconfig-empty.json', 18 | }); 19 | 20 | const code = bundle.outputFiles[0].text; 21 | 22 | return code; 23 | } 24 | }, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/components/cc-addon-backups/cc-addon-backups.types.d.ts: -------------------------------------------------------------------------------- 1 | export type AddonBackupsState = AddonBackupsStateLoaded | AddonBackupsStateLoading | AddonBackupsStateError; 2 | 3 | export interface AddonBackupsStateLoaded { 4 | type: 'loaded'; 5 | backups: Backup[]; 6 | providerId: ProviderId; 7 | passwordForCommand: string; 8 | } 9 | 10 | export interface AddonBackupsStateLoading { 11 | type: 'loading'; 12 | } 13 | 14 | export interface AddonBackupsStateError { 15 | type: 'error'; 16 | } 17 | 18 | export interface Backup { 19 | createdAt: string | number; // date as a string or timestamp 20 | expiresAt?: string | number; // date as a string or timestamp 21 | url: string; 22 | restoreCommand?: string; 23 | deleteCommand?: string; 24 | } 25 | 26 | export type OverlayType = 'restore' | 'delete'; 27 | 28 | export type ProviderId = 29 | | 'es-addon' 30 | | 'es-addon-old' 31 | | 'postgresql-addon' 32 | | 'mysql-addon' 33 | | 'mongodb-addon' 34 | | 'redis-addon' 35 | | 'jenkins'; 36 | -------------------------------------------------------------------------------- /tsconfig.ci.json: -------------------------------------------------------------------------------- 1 | { 2 | // this file is used for typechecking in the CI context 3 | // as opposed to the `tsconfig.json` file used for typechecking within IDEs 4 | // Every file passing typechecking should be added in the `include` array below 5 | "include": [ 6 | ".storybook/**/*.js", 7 | "src/lib/**/*.js", 8 | "src/components/**/*.js", 9 | "src/controllers/*.js", 10 | "src/templates/*.js", 11 | "src/translations/**/*.js", 12 | "tasks/typechecking-stats.js", 13 | "src/lib/events-map.types.d.ts" 14 | ], 15 | "exclude": ["src/controllers/*.stories.js", "src/components/**/*.test.js", "src/components/**/*.stories.js"], 16 | "extends": "./tsconfig.json", 17 | "compilerOptions": { 18 | // FIXME: 19 | // This means our `d.ts` files are not checked in CI context 20 | // This needs to be set to `true` at least until we can upgrade TypeScript 21 | // see https://github.com/CleverCloud/clever-components/issues/972 22 | "skipLibCheck": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/cc-env-var-form/cc-env-var-form.types.d.ts: -------------------------------------------------------------------------------- 1 | import { EnvVar, EnvVarValidationMode } from '../common.types.js'; 2 | 3 | export type EnvVarFormState = 4 | | EnvVarFormStateLoading 5 | | EnvVarFormStateLoaded 6 | | EnvVarFormStateSaving 7 | | EnvVarFormStateError; 8 | 9 | export interface EnvVarFormStateLoading { 10 | type: 'loading'; 11 | } 12 | 13 | export interface EnvVarFormStateLoaded { 14 | type: 'loaded'; 15 | variables: Array; 16 | validationMode: EnvVarValidationMode; 17 | } 18 | 19 | export interface EnvVarFormStateSaving { 20 | type: 'saving'; 21 | variables: Array; 22 | validationMode: EnvVarValidationMode; 23 | } 24 | 25 | export interface EnvVarFormStateError { 26 | type: 'error'; 27 | } 28 | 29 | type EnvVarFormContextType = 30 | | 'env-var-app' 31 | | 'env-var-simple' 32 | | 'env-var-addon' 33 | | 'exposed-config' 34 | | 'config-provider' 35 | | 'linked-app' 36 | | 'linked-addon'; 37 | 38 | export type EnvVarFormMode = 'SIMPLE' | 'EXPERT' | 'JSON'; 39 | -------------------------------------------------------------------------------- /src/translations/translation.types.d.ts: -------------------------------------------------------------------------------- 1 | import { translations as enTranslations } from './translations.en.js'; 2 | import { translations as frTranslations } from './translations.fr.js'; 3 | 4 | type Translations = typeof frTranslations & typeof enTranslations; 5 | type TranslationKeys = keyof Translations; 6 | type ArrowFunction = (...args: any) => any; 7 | 8 | export type I18nFunction = ( 9 | // the rest of the arguments depends on the type of the TranslationPropertyValue which can be either a function or a string (see (i18n.types.d.ts).Translation) 10 | // if it's a string, we do not allow any arguments 11 | // if it's a function, we allow one argument with the same type as the one expected by the function 12 | ...args: TranslationPropertyValue extends ArrowFunction ? [Key, Parameters[0]] : [Key] 13 | ) => TranslationPropertyValue extends ArrowFunction ? ReturnType : TranslationPropertyValue; 14 | -------------------------------------------------------------------------------- /src/lib/form/form.types.d.ts: -------------------------------------------------------------------------------- 1 | import { EventWithTarget } from '../events.types.js'; 2 | import { Validity } from './validation.types.js'; 3 | 4 | export type FormControlData = null | File | string | FormData; 5 | 6 | export type FormDataMap = { [key: string]: FormControlData | Array }; 7 | 8 | export interface FormControlElementLike { 9 | get willValidate(): boolean; 10 | checkValidity: () => boolean; 11 | get validationMessage(): string; 12 | } 13 | 14 | export type OnValidCallback = (formData: FormDataMap, formElement: HTMLFormElement) => void; 15 | export type OnInvalidCallback = (formValidity: FormValidity, formElement: HTMLFormElement) => void; 16 | 17 | export interface SubmitHandlerCallbacks { 18 | onValid?: OnValidCallback; 19 | onInvalid?: OnInvalidCallback; 20 | } 21 | 22 | export type HTMLFormElementEvent = EventWithTarget; 23 | 24 | export type FormValidity = Array; 25 | 26 | interface FormControlValidity { 27 | name: string; 28 | validity: Validity; 29 | } 30 | -------------------------------------------------------------------------------- /src/assets/info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/cc-logs-loading-progress/cc-logs-loading-progress.types.d.ts: -------------------------------------------------------------------------------- 1 | export type LogsLoadingProgressState = 2 | | LogsLoadingProgressStateIdle 3 | | LogsLoadingProgressStateRunning 4 | | LogsLoadingProgressStatePaused 5 | | LogsLoadingProgressStateOverflowLimitReached 6 | | LogsLoadingProgressStateCompleted; 7 | 8 | export interface LogsLoadingProgressStateIdle { 9 | type: 'idle'; 10 | } 11 | 12 | export interface LogsLoadingProgressStateRunning { 13 | type: 'running'; 14 | value: number; 15 | percent?: number; 16 | overflowing: boolean; 17 | } 18 | 19 | export interface LogsLoadingProgressStatePaused { 20 | type: 'paused'; 21 | value: number; 22 | percent?: number; 23 | overflowing: boolean; 24 | } 25 | 26 | export interface LogsLoadingProgressStateOverflowLimitReached { 27 | type: 'overflowLimitReached'; 28 | value: number; 29 | percent?: number; 30 | } 31 | 32 | export interface LogsLoadingProgressStateCompleted { 33 | type: 'completed'; 34 | value: number; 35 | overflowing: boolean; 36 | } 37 | -------------------------------------------------------------------------------- /test/dom/dom.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 16 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /web-test-runner/story-file-to-a11y-tests-file-plugin.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@web/test-runner').TestRunnerPlugin} */ 2 | export const storyFileToA11yTestsFilePlugin = { 3 | name: 'story-file-to-a11y-tests-file', 4 | async transformImport({ source, context }) { 5 | // if `.stories.js` is imported by WTR itself, then we change it to import the test file 6 | if (context.request.url.startsWith('/?wtr-session-id=') && source.includes('.stories.js?wtr-session')) { 7 | return source.replace('.stories.js', '.stories.test.js'); 8 | } 9 | }, 10 | async serve(context) { 11 | // test files are generated on the fly and they import story modules 12 | if (context.path.endsWith('.stories.test.js')) { 13 | const testFileContent = ` 14 | import { runA11yTests } from '/test/helpers/a11y-tests.js'; 15 | import * as storiesModule from '${context.path.replace('.stories.test.js', '.stories.js')}'; 16 | 17 | runA11yTests(storiesModule); 18 | `; 19 | return testFileContent; 20 | } 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/cc-zone-input/cc-zone-input.types.d.ts: -------------------------------------------------------------------------------- 1 | import { ZoneModeType, ZoneStateLoaded } from '../cc-zone/cc-zone.types.js'; 2 | import { Point, Zone } from '../common.types.js'; 3 | 4 | export type ZoneInputState = ZoneInputStateLoaded | ZoneInputStateLoading | ZoneInputStateError; 5 | 6 | export interface ZoneInputStateLoaded { 7 | type: 'loaded'; 8 | zones: Zone[]; 9 | } 10 | 11 | export interface ZoneInputStateLoading { 12 | type: 'loading'; 13 | } 14 | 15 | export interface ZoneInputStateError { 16 | type: 'error'; 17 | } 18 | 19 | // FIXME: the `Point` type has a different type for `marker` & `tooltip` properties 20 | // maybe we could add this as an alternative within the original `Point` interface? 21 | export interface ZoneInputPoint extends Omit { 22 | marker: { tag: 'cc-map-marker-server'; state: ZonePointMarkerState; keyboard: false }; 23 | tooltip: { tag: 'cc-zone'; state: ZoneStateLoaded; mode: ZoneModeType }; 24 | } 25 | 26 | export type ZonePointMarkerState = 'selected' | 'hovered' | 'default'; 27 | -------------------------------------------------------------------------------- /src/components/cc-addon-admin/cc-addon-admin.types.d.ts: -------------------------------------------------------------------------------- 1 | export type AddonAdminState = 2 | | AddonAdminStateLoaded 3 | | AddonAdminStateLoading 4 | | AddonAdminStateError 5 | | AddonAdminStateSaving; 6 | 7 | export interface AddonAdminStateLoaded extends AddonAdminStateBase { 8 | type: 'loaded'; 9 | } 10 | 11 | export interface AddonAdminStateLoading { 12 | type: 'loading'; 13 | } 14 | 15 | export interface AddonAdminStateError { 16 | type: 'error'; 17 | } 18 | 19 | export type AddonAdminStateSaving = AddonAdminStateDeleting | AddonAdminStateUpdatingName | AddonAdminStateUpdatingTags; 20 | 21 | export interface AddonAdminStateDeleting extends AddonAdminStateBase { 22 | type: 'deleting'; 23 | } 24 | 25 | export interface AddonAdminStateUpdatingName extends AddonAdminStateBase { 26 | type: 'updating-name'; 27 | } 28 | 29 | export interface AddonAdminStateUpdatingTags extends AddonAdminStateBase { 30 | type: 'updating-tags'; 31 | } 32 | 33 | interface AddonAdminStateBase { 34 | id: string; 35 | name: string; 36 | tags: string[]; 37 | } 38 | -------------------------------------------------------------------------------- /src/components/cc-orga-member-list/cc-orga-member-list.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { InviteMember } from './cc-orga-member-list.types.js' 5 | * @import { OrgaMember } from '../cc-orga-member-card/cc-orga-member-card.types.js' 6 | */ 7 | 8 | /** 9 | * Dispatched when an organisation member invitation is requested. 10 | * @extends {CcEvent} 11 | */ 12 | export class CcOrgaMemberInviteEvent extends CcEvent { 13 | static TYPE = 'cc-orga-member-invite'; 14 | 15 | /** 16 | * @param {InviteMember} detail 17 | */ 18 | constructor(detail) { 19 | super(CcOrgaMemberInviteEvent.TYPE, detail); 20 | } 21 | } 22 | 23 | /** 24 | * Dispatched when a member has left the organisation. 25 | * @extends {CcEvent} 26 | */ 27 | export class CcOrgaMemberLeftEvent extends CcEvent { 28 | static TYPE = 'cc-orga-member-left'; 29 | 30 | /** 31 | * @param {OrgaMember} detail 32 | */ 33 | constructor(detail) { 34 | super(CcOrgaMemberLeftEvent.TYPE, detail); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /eslint/lit/eslint-config-lit-clever-cloud.js: -------------------------------------------------------------------------------- 1 | import litPlugin from 'eslint-plugin-lit'; 2 | 3 | export default { 4 | name: 'lit-cc', 5 | files: ['**/*.js'], 6 | plugins: { 7 | lit: litPlugin, 8 | }, 9 | rules: { 10 | ...litPlugin.configs['flat/recommended'].rules, 11 | 'lit/attribute-names': 'error', 12 | 'lit/lifecycle-super': 'error', 13 | 'lit/ban-attributes': ['error', 'checked'], 14 | 'lit/no-classfield-shadowing': 'error', 15 | 'lit/no-invalid-escape-sequences': 'error', 16 | 'lit/no-legacy-imports': 'error', 17 | 'lit/no-legacy-template-syntax': 'error', 18 | 'lit/no-native-attributes': 'error', 19 | 'lit/no-private-properties': ['error', { private: '^[_$]' }], 20 | 'lit/no-property-change-update': 'error', 21 | 'lit/no-template-bind': 'error', 22 | 'lit/no-this-assign-in-render': 'error', 23 | 'lit/no-useless-template-literals': 'error', 24 | 'lit/no-value-attribute': 'error', 25 | 'lit/prefer-static-styles': 'error', 26 | 'lit/value-after-constraints': 'error', 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/cc-tcp-redirection/cc-tcp-redirection.events.js: -------------------------------------------------------------------------------- 1 | import { CcEvent } from '../../lib/events.js'; 2 | 3 | /** 4 | * @import { CreateTcpRedirection, DeleteTcpRedirection } from './cc-tcp-redirection.types.js' 5 | */ 6 | 7 | /** 8 | * Dispatched when a tcp redirection creation is requested. 9 | * @extends {CcEvent} 10 | */ 11 | export class CcTcpRedirectionCreateEvent extends CcEvent { 12 | static TYPE = 'cc-tcp-redirection-create'; 13 | 14 | /** 15 | * @param {CreateTcpRedirection} detail 16 | */ 17 | constructor(detail) { 18 | super(CcTcpRedirectionCreateEvent.TYPE, detail); 19 | } 20 | } 21 | 22 | /** 23 | * Dispatched when a tcp redirection deletion is requested. 24 | * @extends {CcEvent} 25 | */ 26 | export class CcTcpRedirectionDeleteEvent extends CcEvent { 27 | static TYPE = 'cc-tcp-redirection-delete'; 28 | 29 | /** 30 | * @param {DeleteTcpRedirection} detail 31 | */ 32 | constructor(detail) { 33 | super(CcTcpRedirectionDeleteEvent.TYPE, detail); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /web-test-runner/visual-tests/story-file-to-visual-tests-file-plugin.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@web/test-runner').TestRunnerPlugin} */ 2 | export const storyFileToVisualTestsFilePlugin = { 3 | name: 'story-file-to-visual-test-file', 4 | async transformImport({ source, context }) { 5 | // if `.stories.js` is imported by WTR itself, then we change it to import the test file 6 | if (context.request.url.startsWith('/?wtr-session-id=') && source.includes('.stories.js?wtr-session')) { 7 | return source.replace('.stories.js', '.stories.test.js'); 8 | } 9 | }, 10 | async serve(context) { 11 | // test files are generated on the fly and they import story modules 12 | if (context.path.endsWith('.stories.test.js')) { 13 | const testFileContent = ` 14 | import { runVisualTests } from '/test/helpers/visual-tests.js'; 15 | import * as storiesModule from '${context.path.replace('.stories.test.js', '.stories.js')}'; 16 | 17 | runVisualTests(storiesModule); 18 | `; 19 | return testFileContent; 20 | } 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/cc-visual-tests-report/visual-tests-report.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface VisualTestResult { 2 | id: string; 3 | componentTagName: string; 4 | storyName: string; 5 | viewportType: ViewportType; 6 | browserName: BrowserName; 7 | screenshots: VisualTestScreenshots; 8 | } 9 | 10 | export type BrowserName = 'chrome' | 'chromium' | 'firefox' | 'safari' | 'webkit'; 11 | 12 | export interface VisualTestScreenshots { 13 | expectationScreenshotUrl: string; 14 | diffScreenshotUrl: string; 15 | actualScreenshotUrl: string; 16 | } 17 | 18 | export type ViewportType = 'mobile' | 'desktop'; 19 | 20 | export interface VisualTestsReport { 21 | expectationMetadata: { 22 | commitReference: string; 23 | lastUpdated: string; 24 | }; 25 | actualMetadata: { 26 | commitReference: string; 27 | lastUpdated: string; 28 | }; 29 | workflowId: string; 30 | prNumber: string; 31 | branchName: string; 32 | repositoryName: string; 33 | repositoryOwner: string; 34 | impactedComponents: Array; 35 | results: VisualTestResult[]; 36 | } 37 | -------------------------------------------------------------------------------- /src/components/cc-logs/cc-logs.types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Log { 2 | id: string; 3 | date: Date; 4 | message: string; 5 | metadata: Array; 6 | } 7 | 8 | export interface Metadata { 9 | name: string; 10 | value: string; 11 | } 12 | 13 | export type MetadataRenderer = MetadataRenderingProvider | MetadataRendering; 14 | 15 | export type MetadataRenderingProvider = (metadata: Metadata) => MetadataRendering; 16 | 17 | export interface MetadataRendering { 18 | hidden?: boolean; 19 | intent?: MetadataIntent; 20 | showName?: boolean; 21 | size?: 'auto' | number; 22 | strong?: boolean; 23 | text?: string; 24 | } 25 | 26 | export type MetadataIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger'; 27 | 28 | export interface MetadataFilter { 29 | metadata: string; 30 | value: string; 31 | } 32 | 33 | export type LogMessageFilterMode = 'loose' | 'strict' | 'regex'; 34 | 35 | export interface LogFilter { 36 | message: LogMessageFilter; 37 | metadata: Array; 38 | } 39 | 40 | export interface LogMessageFilter { 41 | type: string; 42 | value: string; 43 | } 44 | -------------------------------------------------------------------------------- /src/styles/undefined-components.css: -------------------------------------------------------------------------------- 1 | /* This is a work in progress */ 2 | 3 | cc-block:not(:defined) { 4 | border-radius: 0.25em; 5 | border: 1px solid #bcc2d1; 6 | display: grid; 7 | grid-gap: 1em; 8 | padding: 1em; 9 | } 10 | 11 | cc-block:not(:defined) > [slot='title'] { 12 | color: #3a3871; 13 | font-size: 1.2em; 14 | font-weight: 700; 15 | margin-bottom: 0.5em; 16 | } 17 | 18 | cc-block[icon]:not(:defined) > [slot='title'] { 19 | padding-left: 2.5em; 20 | } 21 | 22 | cc-input-text:not(:defined) { 23 | background: #eee; 24 | border-radius: 0.25em; 25 | display: inline-block; 26 | height: 2em; 27 | min-width: 18em; 28 | vertical-align: top; 29 | } 30 | 31 | cc-tcp-redirection-form:not(:defined) { 32 | background: #eee; 33 | border-radius: 0.25em; 34 | display: block; 35 | height: calc(3.8em - 2px); 36 | } 37 | 38 | cc-toggle:not(:defined) { 39 | background: #eee; 40 | border-radius: 0.15em; 41 | display: inline-block; 42 | height: 2em; 43 | min-width: 10em; 44 | vertical-align: top; 45 | } 46 | 47 | cc-toggle:not(:defined)::after { 48 | content: '\00a0'; 49 | } 50 | -------------------------------------------------------------------------------- /src/lib/form/form-error-focus-controller.js: -------------------------------------------------------------------------------- 1 | import { focusFirstFormControlWithError } from './form-utils.js'; 2 | 3 | /** 4 | * @import { LitElement } from 'lit' 5 | * @import { Ref } from 'lit/directives/ref.js' 6 | */ 7 | 8 | /** 9 | * This reactive controller handles the focus after a form submission. 10 | * When there is an error, it waits for the next render and then focus the first form control with error. 11 | */ 12 | export class FormErrorFocusController { 13 | /** 14 | * 15 | * @param {LitElement} host 16 | * @param {Ref} formRef 17 | * @param {() => Object} getErrors 18 | */ 19 | constructor(host, formRef, getErrors) { 20 | this._host = host; 21 | this._host.addController(this); 22 | this._formRef = formRef; 23 | this._getErrors = getErrors; 24 | } 25 | 26 | hostUpdated() { 27 | const errors = this._getErrors(); 28 | if (errors != null && Object.values(errors).some((value) => value != null)) { 29 | this._host.updateComplete.then(() => { 30 | focusFirstFormControlWithError(this._formRef.value); 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/adr/adr-0004-why-wrap-input-textarea.md: -------------------------------------------------------------------------------- 1 | --- 2 | kind: '📌 Architecture Decision Records' 3 | --- 4 | 5 | # ADR 0004: Why do we wrap `` and `