diff --git a/.eslintignore b/.eslintignore
index d9eb23ba..bbbe62b6 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,4 +2,5 @@ build/*
node_modules/*
src/react-app-env.d.ts
src/declarations.d.ts
-src/components/Atomic/Icon/components/*
\ No newline at end of file
+src/components/Atomic/Icon/components/*
+!.storybook
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
index 72fbf269..c506005a 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -93,7 +93,18 @@ module.exports = {
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'warn'
}
- }],
+ },
+ {
+ // or whatever matches stories specified in .storybook/main.js
+ "files": ['*.stories.@(ts|tsx|js|jsx|mjs|cjs)'],
+ "rules": {
+ // example of overriding a rule
+ 'storybook/hierarchy-separator': 'error',
+ // example of disabling a rule
+ 'storybook/default-exports': 'off',
+ }
+ }
+ ],
rules: {
// http://eslint.org/docs/rules/
'array-callback-return': 'warn',
diff --git a/.gitignore b/.gitignore
index 3c76345c..5f572149 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,6 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+
+*storybook.log
+test-report.xml
\ No newline at end of file
diff --git a/.husky/pre-push b/.husky/pre-push
new file mode 100755
index 00000000..92c7fff5
--- /dev/null
+++ b/.husky/pre-push
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+. "$(dirname "$0")/_/husky.sh"
+
+npm run test
\ No newline at end of file
diff --git a/.storybook/main.ts b/.storybook/main.ts
index c307562e..aaa1848c 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -1,54 +1,45 @@
-import { dirname, join } from "path";
-import type { StorybookConfig } from '@storybook/react-webpack5';
+import type { StorybookConfig } from '@storybook/react-webpack5'
+import { join, dirname } from 'path'
+
+/**
+ * This function is used to resolve the absolute path of a package.
+ * It is needed in projects that use Yarn PnP or are set up within a monorepo.
+ */
+function getAbsolutePath(value: string): any {
+ return dirname(require.resolve(join(value, 'package.json')))
+}
const config: StorybookConfig = {
- stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
- addons: [
- getAbsolutePath("@storybook/preset-scss"),
- getAbsolutePath("@storybook/addon-links"),
- getAbsolutePath("@storybook/addon-essentials"),
- getAbsolutePath("@storybook/addon-interactions"),
- {
- name: '@storybook/addon-styling',
- options: {
- sass: {
- // Require your Sass preprocessor here
- implementation: require('sass'),
+ stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
+ addons: [
+ getAbsolutePath('@storybook/addon-webpack5-compiler-swc'),
+ getAbsolutePath('@storybook/addon-onboarding'),
+ getAbsolutePath('@storybook/addon-links'),
+ getAbsolutePath('@storybook/addon-essentials'),
+ getAbsolutePath('@chromatic-com/storybook'),
+ getAbsolutePath('@storybook/addon-interactions'),
+ getAbsolutePath('@storybook/addon-themes'),
+ ],
+ framework: {
+ name: getAbsolutePath('@storybook/react-webpack5'),
+ options: {},
+ },
+ babel: async (options:any) => {
+ options.plugins.push('babel-plugin-inline-react-svg')
+ return options;
+ },
+ swc: () => ({
+ jsc: {
+ transform: {
+ react: {
+ runtime: 'automatic',
+ },
+ },
},
- },
+ }),
+ staticDirs: ['../public'],
+ docs: {
+ autodocs: false,
},
- getAbsolutePath("storybook-addon-themes")
- ],
- framework: {
- name: getAbsolutePath("@storybook/react-webpack5"),
-
- options: {
- builder: {
- fsCache: true,
- lazyCompilation: true
- }
- }
- },
- babel: async (options:any) => {
- options.plugins.push('babel-plugin-inline-react-svg')
- return options;
- },
- // webpackFinal: async config => {
- // config.resolve.alias = {
- // ...(config.resolve.alias || [])
- // };
- // config.resolve.extensions.push('.ts', '.tsx')
- // return config
- // },
- core: {},
- staticDirs: ['../public'],
- docs: {
- autodocs: false
- }
}
-
export default config
-
-function getAbsolutePath(value: string): any {
- return dirname(require.resolve(join(value, "package.json")));
-}
\ No newline at end of file
diff --git a/.storybook/preview-body.html b/.storybook/preview-body.html
index 50296b87..e69de29b 100644
--- a/.storybook/preview-body.html
+++ b/.storybook/preview-body.html
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.storybook/preview.js b/.storybook/preview.js
deleted file mode 100644
index def506f0..00000000
--- a/.storybook/preview.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { ThemeProvider } from '@emotion/react'
-import { addons } from '@storybook/addons'
-import { useEffect, useState } from 'react'
-import { CHANGE } from 'storybook-addon-themes/src/constants'
-
-import plgd from '../src/components/Atomic/_theme/plgd'
-import siemens from '../src/components/Atomic/_theme/siemens'
-
-import 'bootstrap/dist/css/bootstrap.min.css'
-import 'bootstrap/dist/js/bootstrap.bundle'
-// @import '@/assets/fonts/fontawesome/css/all.min.css';
-import '../../../src/assets/fonts/fontawesome/css/all.min.css';
-
-import '../src/common/styles/colors.scss'
-import '../src/common/styles/default.scss'
-import '../src/common/styles/animations.scss'
-import '../src/common/styles/form.scss'
-
-
-export const parameters = {
- actions: { argTypesRegex: "^on[A-Z].*" },
- controls: {
- matchers: {
- color: /(background|color)$/i,
- date: /Date$/,
- },
- },
- themes: {
- default: 'plgd',
- list: [
- { name: 'plgd', class: ['theme-plgd', 'plgd-mode'], color: '#00aced' },
- // { name: 'dark', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
- { name: 'siemens', class: ['theme-siemens', 'siemens-mode'], color: '#000028' },
- ],
- },
-}
-
-const channel = addons.getChannel()
-
-const withTheme = (StoryFn, context) => {
- const { themes } = context.parameters
-
- const [themeName, setThemeName] = useState(() => {
- const lastValue = channel.last(CHANGE);
- return (lastValue && lastValue[0]) || themes.default
- })
-
- const getThemeByKey = (themeName) => themeName === 'plgd' ? plgd : siemens
-
- useEffect(() => {
- channel.on(CHANGE, setThemeName);
- return () => channel.removeListener(CHANGE, setThemeName)
- }, [setThemeName])
-
- return (
-
-
-
- )
-}
-
-// export all decorators that should be globally applied in an array
-export const decorators = [withTheme]
\ No newline at end of file
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
new file mode 100644
index 00000000..f9c3ae47
--- /dev/null
+++ b/.storybook/preview.tsx
@@ -0,0 +1,44 @@
+import React from 'react'
+import type { Preview } from '@storybook/react'
+import {ThemeProvider} from "@emotion/react";
+import { withThemeByClassName } from '@storybook/addon-themes'
+
+import plgd from '../src/components/Atomic/_theme/plgd'
+import siemens from "../src/components/Atomic/_theme/siemens";
+import Aoo from "../src/components/Atomic/App/App";
+
+const preview: Preview = {
+ parameters: {
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/i,
+ },
+ },
+ },
+}
+
+export default preview
+
+
+const withTheme = (StoryFn: any, context: any) => {
+ const getThemeByKey = (themeName: string) => themeName === 'plgd' ? plgd : siemens
+
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export const decorators = [withTheme, withThemeByClassName({
+ themes: {
+ plgd: 'plgd-theme',
+ siemens: 'siemens-theme',
+ },
+ defaultTheme: 'plgd',
+})]
\ No newline at end of file
diff --git a/.storybook/webpack.config.ts b/.storybook/webpack.config.ts
new file mode 100644
index 00000000..43b15e7d
--- /dev/null
+++ b/.storybook/webpack.config.ts
@@ -0,0 +1,14 @@
+const path = require("path");
+
+module.exports = function({ config }: any) {
+ config.module.rules.push({
+ test: /\.(ts|tsx)$/,
+ loader: require.resolve("babel-loader"),
+ options: {
+ presets: [["react-app", { flow: false, typescript: true }], require.resolve("@emotion/babel-preset-css-prop")],
+ },
+ });
+
+ config.resolve.extensions.push(".ts", ".tsx");
+ return config;
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index d9feead0..a5e2c405 100644
--- a/package.json
+++ b/package.json
@@ -24,13 +24,13 @@
":lint:eslint": "eslint --ext .js,.jsx,.ts,.tsx -c .eslintrc.js --max-warnings 0 --fix --format=pretty ./src",
":lint:prettier": "prettier ./src --check",
"prebuild": "rimraf build",
- "storybook": "storybook dev -p 6006",
- "build-storybook": "storybook build",
- "deploy-storybook": "storybook-to-ghpages --dry-run",
"icons:create": "npx @svgr/cli --config-file ./config/.svgrrc.js -d ./src/components/Atomic/Icon/components ./src/components/Atomic/Icon/assets",
":generate:theme:build": "node ./scripts/build.theme.js",
":generate:theme:clean": "rimraf ./build/lib",
- ":generate:theme": "npm-run-all :generate:theme:build :generate:theme:clean"
+ ":generate:theme": "npm-run-all :generate:theme:build :generate:theme:clean",
+ "storybook": "storybook dev -p 6006",
+ "build-storybook": "storybook build",
+ "deploy-storybook": "storybook-to-ghpages --dry-run"
},
"dependencies": {
"@babel/core": "^7.23.3",
@@ -58,7 +58,6 @@
"@opentelemetry/instrumentation-xml-http-request": "^0.45.1",
"@opentelemetry/sdk-trace-base": "^1.18.1",
"@opentelemetry/sdk-trace-web": "^1.18.1",
- "@storybook/addons": "^7.6.13",
"@types/convert-units": "^2.3.9",
"@types/dompurify": "^3.0.2",
"@types/lodash": "^4.14.202",
@@ -119,17 +118,18 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/plugin-transform-runtime": "^7.23.7",
"@babel/runtime": "^7.23.8",
+ "@chromatic-com/storybook": "^1.3.2",
"@emotion/jest": "^11.11.0",
- "@storybook/addon-actions": "^7.6.13",
- "@storybook/addon-essentials": "^7.6.13",
- "@storybook/addon-interactions": "^7.6.13",
- "@storybook/addon-links": "^7.6.13",
- "@storybook/addon-styling": "^1.3.7",
- "@storybook/preset-scss": "^1.0.3",
- "@storybook/react": "^7.6.13",
- "@storybook/react-webpack5": "^7.6.13",
- "@storybook/storybook-deployer": "^2.8.16",
- "@storybook/testing-library": "^0.2.2",
+ "@storybook/addon-essentials": "^8.0.8",
+ "@storybook/addon-interactions": "^8.0.8",
+ "@storybook/addon-links": "^8.0.8",
+ "@storybook/addon-onboarding": "^8.0.8",
+ "@storybook/addon-themes": "^8.0.8",
+ "@storybook/addon-webpack5-compiler-swc": "^1.0.2",
+ "@storybook/blocks": "^8.0.8",
+ "@storybook/react": "^8.0.8",
+ "@storybook/react-webpack5": "^8.0.8",
+ "@storybook/test": "^8.0.8",
"@svgr/cli": "^8.1.0",
"@svgr/webpack": "^8.1.0",
"@testing-library/jest-dom": "^6.1.4",
@@ -152,7 +152,7 @@
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-storybook": "^0.6.15",
+ "eslint-plugin-storybook": "^0.8.0",
"eslint-plugin-testing-library": "^6.0.2",
"fast-glob": "^3.3.2",
"fs-extra": "^11.1.1",
@@ -171,8 +171,7 @@
"rimraf": "^5.0.5",
"sass": "^1.69.5",
"sass-loader": "^13.3.2",
- "storybook": "^7.6.13",
- "storybook-addon-themes": "^6.1.0",
+ "storybook": "^8.0.8",
"style-loader": "^3.3.3",
"ts-jest": "^29.1.1",
"util": "^0.12.5",
diff --git a/src/components/Atomic/CodeEditor/CodeEditor.test.tsx b/src/components/Atomic/CodeEditor/CodeEditor.test.tsx
new file mode 100644
index 00000000..c1cd74c7
--- /dev/null
+++ b/src/components/Atomic/CodeEditor/CodeEditor.test.tsx
@@ -0,0 +1,23 @@
+import { render } from '@testing-library/react'
+import CodeEditor from './CodeEditor'
+
+describe('', () => {
+ it('renders without crashing', () => {
+ const { container, asFragment } = render()
+ expect(container).toBeInTheDocument()
+
+ expect(asFragment()).toMatchSnapshot()
+ })
+
+ it('displays placeholder text when value is empty', () => {
+ const { getByText, asFragment } = render()
+ expect(getByText('Placeholder')).toBeInTheDocument()
+
+ expect(asFragment()).toMatchSnapshot()
+ })
+
+ it('does not display placeholder text when value is not empty', () => {
+ const { queryByText } = render()
+ expect(queryByText('Placeholder')).not.toBeInTheDocument()
+ })
+})
diff --git a/src/components/Atomic/CodeEditor/CodeEditor.tsx b/src/components/Atomic/CodeEditor/CodeEditor.tsx
index e9f10223..dcb5ffc5 100644
--- a/src/components/Atomic/CodeEditor/CodeEditor.tsx
+++ b/src/components/Atomic/CodeEditor/CodeEditor.tsx
@@ -76,6 +76,7 @@ const CodeEditor: FC = (props) => {
extensions={extensions}
height={getSizeInPx(height!)}
onChange={(v) => handleChange(v)}
+ readOnly={disabled === true}
theme={theme}
value={value}
/>
@@ -83,7 +84,7 @@ const CodeEditor: FC = (props) => {
-
{placeholderText}
+ {showPlaceholder &&
{placeholderText}
}
)}
diff --git a/src/components/Atomic/CodeEditor/__snapshots__/CodeEditor.test.tsx.snap b/src/components/Atomic/CodeEditor/__snapshots__/CodeEditor.test.tsx.snap
new file mode 100644
index 00000000..c9769bff
--- /dev/null
+++ b/src/components/Atomic/CodeEditor/__snapshots__/CodeEditor.test.tsx.snap
@@ -0,0 +1,345 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` displays placeholder text when value is empty 1`] = `
+
+ .emotion-0 {
+ position: relative;
+}
+
+.emotion-1 {
+ border: 1px solid;
+ border-radius: 8px;
+ overflow: hidden;
+ position: relative;
+ z-index: 2;
+}
+
+.emotion-1 .cm-editor {
+ background: transparent;
+ -webkit-transition: all 0.3s;
+ transition: all 0.3s;
+}
+
+.emotion-1 .cm-gutters {
+ border: 0;
+}
+
+.emotion-1 .cm-lineNumbers .cm-gutterElement {
+ text-align: center;
+ padding: 0 16px 0 16px;
+}
+
+.emotion-1 .cm-gutterElement {
+ color: !important;
+}
+
+.emotion-1 .cm-content {
+ padding: 16px 0;
+}
+
+.emotion-1 .cm-line {
+ padding: 0 16px;
+ line-height: 1.6;
+}
+
+.emotion-2 {
+ position: absolute;
+ border-radius: 8px;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+}
+
+.emotion-3 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-transition: all 0.3s;
+ transition: all 0.3s;
+ opacity: 1;
+}
+
+.emotion-4 {
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 22px;
+}
+
+
+
+
+
+
+
+ Placeholder
+
+
+
+
+
+`;
+
+exports[` renders without crashing 1`] = `
+
+ .emotion-0 {
+ position: relative;
+}
+
+.emotion-1 {
+ border: 1px solid;
+ border-radius: 8px;
+ overflow: hidden;
+ position: relative;
+ z-index: 2;
+}
+
+.emotion-1 .cm-editor {
+ background: transparent;
+ -webkit-transition: all 0.3s;
+ transition: all 0.3s;
+}
+
+.emotion-1 .cm-gutters {
+ border: 0;
+}
+
+.emotion-1 .cm-lineNumbers .cm-gutterElement {
+ text-align: center;
+ padding: 0 16px 0 16px;
+}
+
+.emotion-1 .cm-gutterElement {
+ color: !important;
+}
+
+.emotion-1 .cm-content {
+ padding: 16px 0;
+}
+
+.emotion-1 .cm-line {
+ padding: 0 16px;
+ line-height: 1.6;
+}
+
+
+
+`;
diff --git a/src/stories/Alert.stories.jsx b/src/stories/Alert.stories.jsx
index bea285f4..09db61f8 100644
--- a/src/stories/Alert.stories.jsx
+++ b/src/stories/Alert.stories.jsx
@@ -25,6 +25,8 @@ const Template = (args) => (
Alert text
+
+
Before adding a remote client, verify their TLS certificate for security. To proceed, open the URL in your browser, verify and accept the
diff --git a/src/stories/CaPool.stories.jsx b/src/stories/CaPool.stories.jsx
deleted file mode 100644
index b4a95ce8..00000000
--- a/src/stories/CaPool.stories.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react'
-import CaPool from '../components/Organisms/CaPool'
-
-export default {
- title: 'Example/CaPool',
- component: CaPool,
- argTypes: {},
-}
-
-const Template = (args) => (
-
-
-
-)
-
-export const Default = Template.bind({})
-Default.args = {}
diff --git a/src/stories/CaPool.stories.tsx b/src/stories/CaPool.stories.tsx
new file mode 100644
index 00000000..ca671fe9
--- /dev/null
+++ b/src/stories/CaPool.stories.tsx
@@ -0,0 +1,63 @@
+import React, { useCallback, useState } from 'react'
+import cloneDeep from 'lodash/cloneDeep'
+import { StoryFn } from '@storybook/react'
+
+import CaPool from '../components/Organisms/CaPool'
+
+export default {
+ title: 'Example/CaPool',
+ component: CaPool,
+ argTypes: {},
+}
+
+const i18n = {
+ title: 'title',
+ download: 'download',
+ edit: 'edit',
+ delete: 'delete',
+ search: 'search',
+ view: 'view',
+ showMore: 'showMore',
+ update: 'update',
+}
+
+const Template = (args: any) => {
+ const [data, setData] = useState([
+ { id: 0, name: 'ca-item-0', data: {} },
+ { id: 1, name: 'ca-item-1', data: {} },
+ { id: 2, name: 'ca-item-2', data: {} },
+ { id: 3, name: 'ca-item-3', data: {} },
+ { id: 4, name: 'ca-item-4', data: {} },
+ ])
+
+ const handleDeleteCaItem = useCallback(
+ (id: string) => {
+ const newData = cloneDeep(data)
+ newData.splice(parseInt(id, 10), 1)
+ setData(newData)
+ },
+ [data]
+ )
+
+ return (
+
+ {
+ alert('handle add modal')
+ setData([...data, { id: data.length, name: `ca-item-${data.length}`, data: {} }])
+ }}
+ onDelete={handleDeleteCaItem}
+ onDownload={() => alert('handle download')}
+ onEdit={() => alert('handle edit')}
+ onView={() => alert('handle view')}
+ />
+
+ )
+}
+
+export const Default: StoryFn = Template.bind({})
+Default.args = {}
diff --git a/src/stories/CodeEditor.stories.jsx b/src/stories/CodeEditor.stories.jsx
new file mode 100644
index 00000000..46df1ea3
--- /dev/null
+++ b/src/stories/CodeEditor.stories.jsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import CodeEditor from '../components/Atomic/CodeEditor'
+
+export default {
+ title: 'Example/CodeEditor',
+ component: CodeEditor,
+ argTypes: {},
+}
+
+const Template = (args) => (
+
+
+
+)
+
+export const Default = Template.bind({})
+Default.args = {}
diff --git a/src/stories/header.css b/src/stories/header.css
deleted file mode 100644
index d13ec050..00000000
--- a/src/stories/header.css
+++ /dev/null
@@ -1,32 +0,0 @@
-.wrapper {
- font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
- padding: 15px 20px;
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-
-svg {
- /*display: inline-block;*/
- /*vertical-align: top;*/
-}
-
-h1 {
- font-weight: 900;
- font-size: 20px;
- line-height: 1;
- margin: 6px 0 6px 10px;
- display: inline-block;
- vertical-align: top;
-}
-
-button + button {
- margin-left: 10px;
-}
-
-.welcome {
- color: #333;
- font-size: 14px;
- margin-right: 10px;
-}
diff --git a/test-report.xml b/test-report.xml
index 6c0f571a..4d8d615d 100644
--- a/test-report.xml
+++ b/test-report.xml
@@ -1,113 +1,118 @@
-
-
-
+
+
-
-
-
-
+
-
+
-
+
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
-
-
+
+
-
-
+
+
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
+
-
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
\ No newline at end of file