Move frontend to Vite 5 (#2775)

* merge squashed

- A couple of CJS modules into ESM (config mostly)
- Vite complains about node.js modules: fixed `useIsMatchingLocation.ts`
	> or use rollupOptions in vite.config.ts
	> ref: f0e4f59d97/vite.config.js (L6)
- Adjust Storybook to work with Vite: use @storybook/test
- Use SWC for jest tranformations
- Remove unused deps:
	- ts-jest: replaced with @swc/jest, typecheck by `tsc`
	- babel plugins
	- @svgr/plugin-jsx: not used
	- @testing-library/user-event: handled by @storybook/test
	- @typescript-eslint/utils: was not plugged in
	- tsup, esbuild-plugin-svgr: will look into that later
- Install Vite required deps, and remove craco/webpack deps
- Adjust SVG to work with Vite as components
- Fixed `Step.tsx`: I dont know if one should be swaped for the other,
  but there should be no slash
- Initial formating and linting:
	- removed empty object params
	- sorting imports, etc..

* prettier: fix pattern

* coverage: sb coverage report isnt working

* Add missing pieces

* `yarn lint --fix`

* fix: scripts permissions

* tsc: cut errors in half

* fix: remove `react-app-env.d.ts`

* tsc: all fixed, except `react-data-grid` types issue

* eslint: ignore env-config.js

* eslint: Align ci with config

* msw: bypass testing warnings

ref: https://stackoverflow.com/questions/68024935/msw-logging-warnings-for-unhandled-supertest-requests

* rebase: and fix things

* Adjust to current `graphql-codegen` no ESM support

* Remove vite plugin and use built-in methods

* rebase: and some fixes

* quick fix + `corepack use yarn@1.22.19`

* Fix build errors

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Aasim Attia
2023-12-10 17:22:43 +02:00
committed by GitHub
parent f24541beda
commit a70a9281eb
132 changed files with 4428 additions and 8978 deletions

View File

@@ -145,7 +145,7 @@ jobs:
- name: Front / Install Dependencies - name: Front / Install Dependencies
run: cd front && yarn run: cd front && yarn
- name: Front / Run linter - name: Front / Run linter
run: cd front && yarn lint --config .eslintrc-ci.js run: cd front && yarn lint --config .eslintrc-ci.cjs
front-jest: front-jest:
needs: front-yarn-install needs: front-yarn-install
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -38,5 +38,11 @@
"cSpell.words": [ "cSpell.words": [
"twentyhq" "twentyhq"
], ],
"typescript.preferences.importModuleSpecifier": "non-relative" "typescript.preferences.importModuleSpecifier": "non-relative",
"[javascript][typescript][typescriptreact]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.addMissingImports": "always"
}
}
} }

View File

@@ -8,7 +8,7 @@ module.exports = {
}, },
], ],
extends: [ extends: [
'./.eslintrc.js' './.eslintrc.cjs'
], ],
rules: { rules: {
'no-console': 'error', 'no-console': 'error',

View File

@@ -1,37 +1,118 @@
module.exports = { module.exports = {
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
ecmaVersion: "2023"
},
plugins: [
'@typescript-eslint/eslint-plugin',
'unused-imports',
'simple-import-sort',
'prefer-arrow',
'import',
'twenty',
],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:storybook/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
root: true, root: true,
env: { env: {
browser: true,
node: true, node: true,
jest: true, jest: true,
}, },
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'twenty/effect-components': 'error',
'twenty/no-hardcoded-colors': 'error',
'twenty/matching-state-variable': 'error',
'twenty/component-props-naming': 'error',
'twenty/sort-css-properties-alphabetically': 'error',
'twenty/styled-components-prefixed-with-styled': 'error',
'twenty/no-state-useref': 'error',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
'no-unused-vars': 'off',
'react/jsx-props-no-spreading': [
'error',
{
explicitSpread: 'ignore',
},
],
'react-hooks/exhaustive-deps': [
'warn',
{
additionalHooks: 'useRecoilCallback',
},
],
'unused-imports/no-unused-imports': 'warn',
'unused-imports/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['@tabler/icons-react'],
message: 'Icon imports are only allowed for `@/ui/icon`',
},
{
group: ['react-hotkeys-web-hook'],
importNames: ['useHotkeys'],
message: 'Please use the custom wrapper: `useScopedHotkeys`',
},
],
},
],
'@typescript-eslint/consistent-type-imports': [
'error',
{ prefer: 'no-type-imports' },
],
'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }],
// 'react-refresh/only-export-components': [
// 'warn',
// { allowConstantExport: true },
// ],
},
settings: {
react: {
version: 'detect',
},
},
extends: [
'plugin:@typescript-eslint/recommended',
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended',
'plugin:storybook/recommended',
],
plugins: [
'@typescript-eslint/eslint-plugin',
'simple-import-sort',
'unused-imports',
'prefer-arrow',
'twenty',
'react-refresh',
],
ignorePatterns: [
'mockServiceWorker.js',
'**/generated*/*',
'.eslintrc.cjs',
'*.config.cjs',
'*.config.ts',
'*config.js',
'codegen*',
],
overrides: [ overrides: [
{ {
files: ['*.stories.tsx', '*.test.ts'], files: ['*.stories.tsx', '*.test.ts'],
rules: { rules: {
'no-console': 'off', 'no-console': 'off',
} },
}, },
{ {
files: ['*.js', '*.jsx', '*.ts', '*.tsx'], files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
@@ -43,7 +124,7 @@ module.exports = {
'react/jsx-uses-react': 'off', 'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off', 'react/react-in-jsx-scope': 'off',
'no-control-regex': 0, 'no-control-regex': 0,
'import/no-duplicates': ["error", {"considerQueryString": true}], 'no-undef': 'off',
'simple-import-sort/imports': [ 'simple-import-sort/imports': [
'error', 'error',
{ {
@@ -53,76 +134,19 @@ module.exports = {
['^\\u0000'], ['^\\u0000'],
['^\\.\\.(?!/?$)', '^\\.\\./?$'], ['^\\.\\.(?!/?$)', '^\\.\\./?$'],
['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
['^.+\\.?(css)$'] ['^.+\\.?(css)$'],
] ],
} },
], ],
'prefer-arrow/prefer-arrow-functions': [ 'prefer-arrow/prefer-arrow-functions': [
'error', 'error',
{ {
"disallowPrototype": true, disallowPrototype: true,
"singleReturnOnly": false, singleReturnOnly: false,
"classPropertiesAllowed": false classPropertiesAllowed: false,
}
]
}
},
],
ignorePatterns: ['.eslintrc.js', 'codegen*.js', '**/generated*/*', '*.config.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'twenty/effect-components': 'error',
'twenty/no-hardcoded-colors': 'error',
'twenty/matching-state-variable': 'error',
'twenty/component-props-naming': 'error',
'twenty/sort-css-properties-alphabetically': 'error',
'twenty/styled-components-prefixed-with-styled': 'error',
'twenty/no-state-useref': 'error',
'func-style':['error', 'declaration', { 'allowArrowFunctions': true }],
"@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off",
"react/jsx-props-no-spreading": [
"error", {
"explicitSpread": "ignore",
}
],
"react-hooks/exhaustive-deps": [
"warn", {
"additionalHooks": "useRecoilCallback"
}
],
"unused-imports/no-unused-imports": "warn",
"unused-imports/no-unused-vars": [
"warn",
{ "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
],
'no-restricted-imports': [
'error',
{
'patterns': [
{
'group': ['@tabler/icons-react'],
'message': 'Icon imports are only allowed for `@/ui/icon`',
},
{
'group': ['react-hotkeys-web-hook'],
"importNames": ["useHotkeys"],
'message': 'Please use the custom wrapper: `useScopedHotkeys`',
}, },
], ],
}, },
], },
"@typescript-eslint/consistent-type-imports": ["error", { "prefer": "no-type-imports" }], ],
'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }],
},
settings: {
"react": {
"version": "detect"
}
}
}; };

30
front/.gitignore vendored
View File

@@ -1,7 +1,15 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# dependencies # dependencies
/node_modules /node_modules
/coverage*
/.pnp /.pnp
.pnp.js .pnp.js
@@ -12,16 +20,22 @@ build-storybook.log
# production # production
/build /build
dist
dist-ssr
# misc # env
.DS_Store
.env.local .env.local
.env.development.local .env.development.local
.env.test.local .env.test.local
.env.production.local .env.production.local
npm-debug.log* # Editor directories and files
yarn-debug.log* .vscode/*
yarn-error.log* !.vscode/extensions.json
.idea
.nyc_output .DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

3
front/.prettierignore Normal file
View File

@@ -0,0 +1,3 @@
**/generated*/
*.lock
*.yaml

View File

@@ -2,4 +2,4 @@
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"endOfLine": "auto" "endOfLine": "auto"
} }

View File

@@ -1,94 +0,0 @@
const path = require('path');
computeStoriesGlob = () => {
if (process.env.STORYBOOK_SCOPE === 'pages') {
return [
'../src/pages/**/*.stories.@(js|jsx|ts|tsx)',
'../src/__stories__/*.stories.@(js|jsx|ts|tsx)',
'../src/pages/**/*.docs.mdx',
'../src/__stories__/*.docs.mdx'
]
}
if (process.env.STORYBOOK_SCOPE === 'modules') {
return ['../src/modules/**/*.stories.@(js|jsx|ts|tsx)', '../src/modules/**/*.docs.mdx']
}
if (process.env.STORYBOOK_SCOPE === 'ui-docs') {
return ['../src/modules/ui/**/*.docs.mdx'];
}
return ['../src/**/*.stories.@(js|jsx|ts|tsx)', '../src/**/*.docs.mdx']
};
module.exports = {
webpackFinal: (config) => {
config.module.rules.push({
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [
require('@babel/preset-typescript').default,
[
require('@babel/preset-react').default,
{
runtime: 'automatic',
},
],
require('@babel/preset-env').default,
],
},
},
],
});
config.resolve.extensions.push('.ts', '.tsx');
config.module.rules.push({
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
});
config.module.rules.push({
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
},
{
loader: 'file-loader',
options: {
name: 'static/media/[path][name].[ext]',
},
},
],
type: 'javascript/auto',
issuer: {
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
},
});
config.resolve.extensions.push('.mjs');
config.resolve.alias = {
...config.resolve.alias,
'~': path.resolve(__dirname, '../src'),
'@': path.resolve(__dirname, '../src/modules'),
};
return config;
},
stories: computeStoriesGlob(),
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-coverage',
'@storybook/addon-styling',
'storybook-addon-pseudo-states',
'storybook-addon-cookie',
],
docs: { autodocs: false },
framework: {
name: '@storybook/react-webpack5',
options: {},
},
};

45
front/.storybook/main.ts Normal file
View File

@@ -0,0 +1,45 @@
import type { StorybookConfig } from '@storybook/react-vite';
const computeStoriesGlob = () => {
if (process.env.STORYBOOK_SCOPE === 'pages') {
return [
'../src/pages/**/*.stories.@(js|jsx|ts|tsx)',
'../src/__stories__/*.stories.@(js|jsx|ts|tsx)',
'../src/pages/**/*.docs.mdx',
'../src/__stories__/*.docs.mdx'
]
}
if (process.env.STORYBOOK_SCOPE === 'modules') {
return ['../src/modules/**/*.stories.@(js|jsx|ts|tsx)', '../src/modules/**/*.docs.mdx']
}
if (process.env.STORYBOOK_SCOPE === 'ui-docs') {
return ['../src/modules/ui/**/*.docs.mdx'];
}
return ['../src/**/*.docs.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)']
};
const config: StorybookConfig = {
stories: computeStoriesGlob(),
staticDirs: ['../public'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
'@storybook/addon-coverage',
'@storybook/addon-themes',
'storybook-addon-cookie',
'storybook-addon-pseudo-states',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: false,
},
};
export default config;

View File

@@ -2,7 +2,12 @@
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.7/iframeResizer.contentWindow.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.7/iframeResizer.contentWindow.min.js"></script>
<!-- <script>
window.global = window;
</script> -->
<style type="text/css"> <style type="text/css">
body { body {
margin: 0; margin: 0;

View File

@@ -1,18 +1,19 @@
import { initialize, mswLoader } from 'msw-storybook-addon';
import { Preview } from '@storybook/react';
import { ThemeProvider } from '@emotion/react'; import { ThemeProvider } from '@emotion/react';
import { withThemeFromJSXProvider } from '@storybook/addon-styling'; import { Preview, ReactRenderer } from '@storybook/react';
import { lightTheme, darkTheme } from '../src/modules/ui/theme/constants/theme'; import { withThemeFromJSXProvider } from "@storybook/addon-themes";
import { RootDecorator } from '../src/testing/decorators/RootDecorator'; import { initialize, mswLoader } from 'msw-storybook-addon';
import 'react-loading-skeleton/dist/skeleton.css';
import { mockedUserJWT } from '../src/testing/mock-data/jwt';
import { rest } from 'msw'
initialize(); import { RootDecorator } from '../src/testing/decorators/RootDecorator';
import { mockedUserJWT } from '../src/testing/mock-data/jwt';
import { lightTheme, darkTheme } from '../src/modules/ui/theme/constants/theme';
import 'react-loading-skeleton/dist/skeleton.css';
initialize({ onUnhandledRequest: 'bypass' });
const preview: Preview = { const preview: Preview = {
decorators: [ decorators: [
withThemeFromJSXProvider({ withThemeFromJSXProvider<ReactRenderer>({
themes: { themes: {
light: lightTheme, light: lightTheme,
dark: darkTheme, dark: darkTheme,
@@ -30,16 +31,16 @@ const preview: Preview = {
date: /Date$/, date: /Date$/,
}, },
}, },
cookie: {
tokenPair: `{%22accessToken%22:{%22token%22:%22${mockedUserJWT}%22%2C%22expiresAt%22:%222023-07-18T15:06:40.704Z%22%2C%22__typename%22:%22AuthToken%22}%2C%22refreshToken%22:{%22token%22:%22${mockedUserJWT}%22%2C%22expiresAt%22:%222023-10-15T15:06:41.558Z%22%2C%22__typename%22:%22AuthToken%22}%2C%22__typename%22:%22AuthTokenPair%22}`,
},
options: { options: {
storySort: { storySort: {
order: ['UI', 'Modules', 'Pages'], order: ['UI', 'Modules', 'Pages'],
}, },
}, },
cookie: {
tokenPair: `{%22accessToken%22:{%22token%22:%22${mockedUserJWT}%22%2C%22expiresAt%22:%222023-07-18T15:06:40.704Z%22%2C%22__typename%22:%22AuthToken%22}%2C%22refreshToken%22:{%22token%22:%22${mockedUserJWT}%22%2C%22expiresAt%22:%222023-10-15T15:06:41.558Z%22%2C%22__typename%22:%22AuthToken%22}%2C%22__typename%22:%22AuthTokenPair%22}`,
},
loaders: [mswLoader],
}, },
loaders: [mswLoader],
}; };
export default preview; export default preview;

View File

@@ -1,13 +1,13 @@
const { getJestConfig } = require('@storybook/test-runner'); import { getJestConfig } from "@storybook/test-runner";
/** /**
* @type {import('@jest/types').Config.InitialOptions} * @type {import('@jest/types').Config.InitialOptions}
*/ */
module.exports = { export default {
// The default configuration comes from @storybook/test-runner // The default configuration comes from @storybook/test-runner
...getJestConfig(), ...getJestConfig(),
/** Add your own overrides below /** Add your own overrides below
* @see https://jestjs.io/docs/configuration * @see https://jestjs.io/docs/configuration
*/ */
testTimeout: process.env.STORYBOOK_SCOPE=== 'pages' ? 60000 : 15000, testTimeout: process.env.STORYBOOK_SCOPE === 'pages' ? 60000 : 15000,
}; };

31
front/.swcrc Normal file
View File

@@ -0,0 +1,31 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": false
},
"transform": {
"react": {
"pragma": "React.createElement",
"pragmaFrag": "React.Fragment",
"throwIfNamespace": true,
"development": false,
"useBuiltins": false,
"runtime": "automatic"
},
"hidden": {
"jest": true
}
}
},
"module": {
"type": "commonjs",
"strict": false,
"strictMode": true,
"lazy": false,
"noInterop": false
}
}

1
front/README.md Normal file
View File

@@ -0,0 +1 @@
Run `yarn dev` while server running on port `3000`

View File

@@ -1,48 +0,0 @@
const path = require("path");
module.exports = {
devServer: {
client: {
overlay: {
runtimeErrors: (error) => {
switch (error.message) {
case "ResizeObserver loop limit exceeded":
case "Unauthenticated":
return false;
default:
return true;
}
},
},
}
},
webpack: {
alias: {
'~': path.resolve(__dirname, 'src'),
'@': path.resolve(__dirname, 'src/modules'),
'@testing': path.resolve(__dirname, 'src/testing'),
},
// TODO: remove this workaround by resolving source map errors with @sniptt/guards
configure: {
module: {
rules: [
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
},
],
},
ignoreWarnings: [/Failed to parse source map/],
},
},
jest: {
configure: {
moduleNameMapper: {
'~/(.+)': "<rootDir>/src/$1",
'@/(.+)': "<rootDir>/src/modules/$1",
'@testing/(.+)': "<rootDir>/src/testing/$1",
}
},
},
};

View File

@@ -1,23 +1,18 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="UTF-8" />
<link
rel="icon" <link rel="icon" href="/icons/android/android-launchericon-48-48.png" />
href="%PUBLIC_URL%/icons/android/android-launchericon-48-48.png" <link rel="apple-touch-icon" href="/icons/ios/192.png" />
/>
<link <meta name="viewport" content="width=device-width, initial-scale=1.0" />
rel="apple-touch-icon"
href="%PUBLIC_URL%/icons/ios/icon-192x192.png"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="A modern open-source CRM" /> <meta name="description" content="A modern open-source CRM" />
<meta <meta
property="og:image" property="og:image"
content="https://raw.githubusercontent.com/twentyhq/twenty/main/docs/static/img/social-card.png" content="https://raw.githubusercontent.com/twentyhq/twenty/main/docs/static/img/social-card.png"
/> />
<meta property="og:description" content="A modern open-source CRM" /> <meta property="og:description" content="A modern open-source CRM" />
<meta property="og:title" content="Twenty" /> <meta property="og:title" content="Twenty" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
@@ -28,18 +23,17 @@
<meta name="twitter:description" content="A modern open-source CRM" /> <meta name="twitter:description" content="A modern open-source CRM" />
<meta name="twitter:title" content="Twenty" /> <meta name="twitter:title" content="Twenty" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link <link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
rel="stylesheet" rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
/> />
<title>Twenty</title> <title>Twenty</title>
<script src="%PUBLIC_URL%/env-config.js"></script> <script src="/env-config.js"></script>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,17 @@
const { createJestConfig } = require("@craco/craco"); export default {
const cracoConfig = require("./craco.config.js"); setupFilesAfterEnv: ["./src/setupTests.ts"],
const jestConfig = createJestConfig(cracoConfig); testEnvironment: "jsdom",
transform: {
module.exports = jestConfig; "^.+\\.(ts|js|tsx|jsx)$": "@swc/jest",
},
moduleNameMapper: {
'~/(.+)': "<rootDir>/src/$1",
'@/(.+)': "<rootDir>/src/modules/$1",
'@testing/(.+)': "<rootDir>/src/testing/$1",
},
extensionsToTreatAsEsm: ['.ts', '.tsx'],
// collectCoverage: true,
// collectCoverageFrom: ['<rootDir>/src/**/*.{ts,tsx}'],
// coveragePathIgnorePatterns: ['(tests/.*.mock).(jsx?|tsx?)$', '(.*).d.ts$'],
// coverageDirectory: '<rootDir>/coverage/',
}

View File

@@ -26,10 +26,10 @@ const pagesCoverage = {
] ]
}; };
const storybookStoriesFolders = process.env.STORYBOOK_SCOPE; const storybookStoriesFolders = process.env.STORYBOOK_SCOPE;
module.exports = storybookStoriesFolders === 'pages' ? module.exports = storybookStoriesFolders === 'pages'
pagesCoverage : storybookStoriesFolders === 'modules' ? modulesCoverage ? pagesCoverage
: globalCoverage; : storybookStoriesFolders === 'modules'
? modulesCoverage
: globalCoverage;

View File

@@ -2,6 +2,37 @@
"name": "twenty", "name": "twenty",
"version": "0.2.1", "version": "0.2.1",
"private": true, "private": true,
"type": "module",
"scripts": {
"dev": "vite",
"dev:clean": "yarn dev --force",
"build": "tsc && vite build && yarn build:inject-runtime-env",
"build:inject-runtime-env": "./scripts/inject-runtime-env.sh",
"preview": "vite preview",
"eslint-plugin:setup": "cd ../packages/eslint-plugin-twenty/ && yarn && yarn build && cd ../../front/ && yarn upgrade eslint-plugin-twenty",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"fmt:fix": "prettier --cache --write \"src/**/*.ts\" \"src/**/*.tsx\"",
"fmt": "prettier --check \"src/**/*.ts\" \"src/**/*.tsx\"",
"test": "jest",
"coverage": "jest --coverage",
"storybook:modules:dev": "STORYBOOK_SCOPE=modules yarn storybook:dev",
"storybook:dev": "storybook dev -p 6006 --no-open",
"storybook:pages:dev": "STORYBOOK_SCOPE=pages yarn storybook:dev",
"storybook:docs:dev": "STORYBOOK_SCOPE=ui-docs yarn storybook:dev",
"storybook:build": "storybook build",
"storybook:modules:build": "STORYBOOK_SCOPE=modules yarn storybook:build",
"storybook:pages:build": "STORYBOOK_SCOPE=pages yarn storybook:build",
"storybook:docs:build": "STORYBOOK_SCOPE=ui-docs yarn storybook:build",
"storybook:test": "test-storybook",
"storybook:test-slow": "test-storybook --maxWorkers=3",
"storybook:coverage": "yarn storybook:test-slow --coverage && npx nyc report --reporter=lcov -t coverage/storybook --report-dir coverage/storybook --check-coverage",
"storybook:modules:coverage": "STORYBOOK_SCOPE=modules yarn storybook:coverage",
"storybook:pages:coverage": "STORYBOOK_SCOPE=pages yarn storybook:coverage",
"graphql:data:generate": "dotenv cross-var graphql-codegen -- --config codegen.cjs",
"graphql:metadata:generate": "dotenv cross-var graphql-codegen -- --config codegen-metadata.cjs",
"chromatic": "dotenv cross-var npx chromatic --project-token=$CHROMATIC_PROJECT_TOKEN",
"install": "yarn eslint-plugin:setup"
},
"dependencies": { "dependencies": {
"@air/react-drag-to-select": "^5.0.8", "@air/react-drag-to-select": "^5.0.8",
"@apollo/client": "^3.7.17", "@apollo/client": "^3.7.17",
@@ -15,11 +46,9 @@
"@hello-pangea/dnd": "^16.2.0", "@hello-pangea/dnd": "^16.2.0",
"@hookform/resolvers": "^3.1.1", "@hookform/resolvers": "^3.1.1",
"@sniptt/guards": "^0.2.0", "@sniptt/guards": "^0.2.0",
"@swc/core": "^1.3.100",
"@swc/jest": "^0.2.29",
"@tabler/icons-react": "^2.30.0", "@tabler/icons-react": "^2.30.0",
"@types/node": "^16.18.4",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"@types/react-helmet-async": "^1.0.3",
"afterframe": "^1.0.2", "afterframe": "^1.0.2",
"apollo-upload-client": "^17.0.0", "apollo-upload-client": "^17.0.0",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
@@ -57,43 +86,79 @@
"ts-key-enum": "^2.0.12", "ts-key-enum": "^2.0.12",
"type-fest": "^4.1.0", "type-fest": "^4.1.0",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"vite-tsconfig-paths": "^4.2.1",
"xlsx-ugnis": "^0.19.3", "xlsx-ugnis": "^0.19.3",
"zod": "^3.22.2" "zod": "^3.22.2"
}, },
"scripts": { "devDependencies": {
"start": "PORT=3001 craco start --max-warnings=0", "@graphql-codegen/cli": "^3.3.1",
"build:inject-runtime-env": "./scripts/inject-runtime-env.sh", "@graphql-codegen/client-preset": "^4.1.0",
"build": "craco build && yarn build:inject-runtime-env", "@graphql-codegen/typescript": "^3.0.4",
"test": "craco test", "@graphql-codegen/typescript-operations": "^3.0.4",
"coverage": "craco test --coverage .", "@graphql-codegen/typescript-react-apollo": "^3.3.7",
"lint": "eslint src --max-warnings=0", "@storybook/addon-actions": "^7.6.3",
"eslint-plugin:setup": "cd ../packages/eslint-plugin-twenty/ && yarn && yarn build && cd ../../front/ && yarn upgrade eslint-plugin-twenty", "@storybook/addon-coverage": "^1.0.0",
"storybook:dev": "storybook dev -p 6006 -s ../public", "@storybook/addon-essentials": "^7.6.3",
"storybook:test": "test-storybook", "@storybook/addon-interactions": "^7.6.3",
"storybook:test-slow": "test-storybook --maxWorkers=3", "@storybook/addon-links": "^7.6.3",
"storybook:build": "storybook build -s public", "@storybook/addon-onboarding": "^1.0.9",
"storybook:coverage": "test-storybook --coverage --maxWorkers=3 && npx nyc report --reporter=lcov -t coverage/storybook --report-dir coverage/storybook --check-coverage", "@storybook/addon-themes": "^7.6.3",
"storybook:modules:dev": "STORYBOOK_SCOPE=modules yarn storybook:dev", "@storybook/blocks": "^7.6.3",
"storybook:pages:dev": "STORYBOOK_SCOPE=pages yarn storybook:dev", "@storybook/react": "^7.6.3",
"storybook:docs:dev": "STORYBOOK_SCOPE=ui-docs yarn storybook:dev", "@storybook/react-vite": "^7.6.3",
"storybook:modules:build": "STORYBOOK_SCOPE=modules yarn storybook:build", "@storybook/test": "^7.6.3",
"storybook:pages:build": "STORYBOOK_SCOPE=pages yarn storybook:build", "@storybook/test-runner": "^0.16.0",
"storybook:docs:build": "STORYBOOK_SCOPE=ui-docs yarn storybook:build", "@testing-library/jest-dom": "^6.1.5",
"storybook:modules:coverage": "STORYBOOK_SCOPE=modules yarn storybook:coverage", "@testing-library/react": "^13.4.0",
"storybook:pages:coverage": "STORYBOOK_SCOPE=pages yarn storybook:coverage", "@types/apollo-upload-client": "^17.0.2",
"graphql:data:generate": "dotenv cross-var graphql-codegen -- --config codegen.js", "@types/deep-equal": "^1.0.1",
"graphql:metadata:generate": "dotenv cross-var graphql-codegen -- --config codegen-metadata.js", "@types/jest": "^29.5.10",
"chromatic": "dotenv cross-var npx chromatic --project-token=$CHROMATIC_PROJECT_TOKEN", "@types/js-cookie": "^3.0.3",
"install": "yarn eslint-plugin:setup" "@types/lodash.camelcase": "^4.3.7",
"@types/lodash.debounce": "^4.0.7",
"@types/lodash.kebabcase": "^4.1.7",
"@types/lodash.snakecase": "^4.1.9",
"@types/luxon": "^3.3.0",
"@types/node": "^20.10.0",
"@types/react": "^18.2.39",
"@types/react-datepicker": "^4.11.2",
"@types/react-dom": "^18.2.15",
"@types/scroll-into-view": "^1.16.0",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitejs/plugin-react-swc": "^3.5.0",
"chromatic": "^6.18.0",
"concurrently": "^8.0.1",
"cross-var": "^1.1.0",
"dotenv-cli": "^7.2.1",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.4",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-storybook": "^0.6.15",
"eslint-plugin-twenty": "file:../packages/eslint-plugin-twenty",
"eslint-plugin-unused-imports": "^3.0.0",
"http-server": "^14.1.1",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"msw": "1.3.2",
"msw-storybook-addon": "^1.10.0",
"prettier": "^3.1.0",
"storybook": "^7.6.3",
"storybook-addon-cookie": "^3.1.0",
"storybook-addon-pseudo-states": "^2.1.2",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"vite-plugin-svgr": "^4.2.0"
}, },
"overrides": { "engines": {
"react-refresh": "0.14.0" "node": "^18.16.0",
}, "npm": "please-use-yarn"
"jest": {
"testMatch": [
"<rootDir>/**/*.test.ts",
"<rootDir>/**/*.test.tsx"
]
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
@@ -107,76 +172,8 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@craco/craco": "^7.1.0",
"@graphql-codegen/cli": "^3.3.1",
"@graphql-codegen/client-preset": "^4.1.0",
"@graphql-codegen/typescript": "^3.0.4",
"@graphql-codegen/typescript-operations": "^3.0.4",
"@graphql-codegen/typescript-react-apollo": "^3.3.7",
"@storybook/addon-actions": "^7.0.22",
"@storybook/addon-coverage": "^0.0.8",
"@storybook/addon-essentials": "^7.0.22",
"@storybook/addon-interactions": "^7.0.22",
"@storybook/addon-links": "^7.0.22",
"@storybook/addon-styling": "^1.3.0",
"@storybook/jest": "^0.1.0",
"@storybook/node-logger": "^7.0.22",
"@storybook/react": "^7.0.22",
"@storybook/react-webpack5": "^7.0.22",
"@storybook/test-runner": "^0.10.0",
"@storybook/testing-library": "^0.1.0",
"@svgr/plugin-jsx": "^8.1.0",
"@svgr/webpack": "^8.0.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/apollo-upload-client": "^17.0.2",
"@types/deep-equal": "^1.0.1",
"@types/jest": "^27.5.2",
"@types/js-cookie": "^3.0.3",
"@types/lodash.camelcase": "^4.3.7",
"@types/lodash.debounce": "^4.0.7",
"@types/lodash.kebabcase": "^4.1.7",
"@types/lodash.snakecase": "^4.1.9",
"@types/luxon": "^3.3.0",
"@types/react-datepicker": "^4.11.2",
"@types/scroll-into-view": "^1.16.0",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@typescript-eslint/utils": "^6.7.0",
"babel-plugin-named-exports-order": "^0.0.2",
"chromatic": "^6.18.0",
"concurrently": "^8.0.1",
"cross-var": "^1.1.0",
"dotenv-cli": "^7.2.1",
"esbuild-plugin-svgr": "^2.1.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard-with-typescript": "^23.0.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-storybook": "^0.6.12",
"eslint-plugin-twenty": "file:../packages/eslint-plugin-twenty",
"eslint-plugin-unused-imports": "^3.0.0",
"http-server": "^14.1.1",
"msw": "1.3.2",
"msw-storybook-addon": "^1.10.0",
"prettier": "^2.8.0",
"react-scripts": "5.0.1",
"storybook": "^7.0.22",
"storybook-addon-cookie": "^3.0.1",
"storybook-addon-pseudo-states": "^2.1.0",
"ts-jest": "^29.1.0",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"webpack": "^5.75.0"
},
"msw": { "msw": {
"workerDirectory": "public" "workerDirectory": "public"
} },
} "packageManager": "yarn@1.22.19+sha256.732620bac8b1690d507274f025f3c6cfdc3627a84d9642e38a07452cc00e0f2e"
}

View File

@@ -1,3 +1,3 @@
window._env_ = { window._env_ = {
// This file should stay empty. It will be overwritten by the build process. // This file should stay empty. It will be overwritten by the build process.
} }

View File

@@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow: /

View File

@@ -1,6 +1,5 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { matchPath, useLocation } from 'react-router-dom'; import { matchPath, useLocation } from 'react-router-dom';
import { parse } from 'url';
import { AppBasePath } from '@/types/AppBasePath'; import { AppBasePath } from '@/types/AppBasePath';
@@ -10,7 +9,7 @@ export const useIsMatchingLocation = () => {
return useCallback( return useCallback(
(path: string, basePath?: AppBasePath) => { (path: string, basePath?: AppBasePath) => {
const constructedPath = basePath const constructedPath = basePath
? parse(`${basePath}/${path}`).pathname ?? '' ? new URL(basePath + path, document.location.origin).pathname ?? ''
: path; : path;
return !!matchPath(constructedPath, location.pathname); return !!matchPath(constructedPath, location.pathname);

View File

@@ -26,9 +26,7 @@ import '@emotion/react';
import './index.css'; import './index.css';
import 'react-loading-skeleton/dist/skeleton.css'; import 'react-loading-skeleton/dist/skeleton.css';
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(document.getElementById('root')!);
document.getElementById('root') as HTMLElement,
);
root.render( root.render(
<RecoilRoot> <RecoilRoot>
@@ -68,6 +66,5 @@ root.render(
); );
declare module '@emotion/react' { declare module '@emotion/react' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Theme extends ThemeType {} export interface Theme extends ThemeType {}
} }

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-loop-func */
import { import {
ApolloClient, ApolloClient,
ApolloClientOptions, ApolloClientOptions,

View File

@@ -14,7 +14,7 @@ const parseQuery = (queryString: string) => {
const queryObj = gql` const queryObj = gql`
${queryString} ${queryString}
`; `;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { name } = queryObj.definitions[0] as any; const { name } = queryObj.definitions[0] as any;
return [name ? name.value : 'Generic', queryString.trim()]; return [name ? name.value : 'Generic', queryString.trim()];
}; };
@@ -25,10 +25,10 @@ export const loggerLink = (getSchemaName: (operation: Operation) => string) =>
operation.setContext({ start: Date.now() }); operation.setContext({ start: Date.now() });
const { variables } = operation; const { variables } = operation;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const operationType = (operation.query.definitions[0] as any).operation; const operationType = (operation.query.definitions[0] as any).operation;
const headers = operation.getContext().headers; const headers = operation.getContext().headers;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const [queryName, query] = parseQuery(operation.query.loc!.source.body); const [queryName, query] = parseQuery(operation.query.loc!.source.body);
if (operationType === 'subscription') { if (operationType === 'subscription') {
@@ -65,7 +65,6 @@ export const loggerLink = (getSchemaName: (operation: Operation) => string) =>
getGroup(!hasError)(...titleArgs); getGroup(!hasError)(...titleArgs);
if (errors) { if (errors) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
errors.forEach((err: any) => { errors.forEach((err: any) => {
logDebug( logDebug(
`%c${err.message}`, `%c${err.message}`,

View File

@@ -219,8 +219,8 @@ export const SignInUpForm = () => {
SignInUpStep.Init SignInUpStep.Init
? false ? false
: signInUpStep === SignInUpStep.Email : signInUpStep === SignInUpStep.Email
? !watch('email') ? !watch('email')
: !watch('email') || !watch('password') || isSubmitting : !watch('email') || !watch('password') || isSubmitting
} }
fullWidth fullWidth
/> />

View File

@@ -176,124 +176,128 @@ export const CommandMenu = () => {
.concat(activities.map((activity) => activity.id)); .concat(activities.map((activity) => activity.id));
return ( return (
isCommandMenuOpened && ( <>
<StyledDialog> {isCommandMenuOpened && (
<StyledInput <StyledDialog>
value={search} <StyledInput
placeholder="Search" value={search}
onChange={handleSearchChange} placeholder="Search"
/> onChange={handleSearchChange}
<StyledList> />
<ScrollWrapper> <StyledList>
<StyledInnerList> <ScrollWrapper>
<SelectableList <StyledInnerList>
selectableListId="command-menu-list" <SelectableList
selectableItemIds={[selectableItemIds]} selectableListId="command-menu-list"
hotkeyScope={AppHotkeyScope.CommandMenu} selectableItemIds={[selectableItemIds]}
onEnter={(_itemId) => {}} hotkeyScope={AppHotkeyScope.CommandMenu}
> onEnter={(_itemId) => {}}
{!matchingCreateCommand.length && >
!matchingNavigateCommand.length && {!matchingCreateCommand.length &&
!people.length && !matchingNavigateCommand.length &&
!companies.length && !people.length &&
!activities.length && ( !companies.length &&
<StyledEmpty>No results found</StyledEmpty> !activities.length && (
)} <StyledEmpty>No results found</StyledEmpty>
<CommandGroup heading="Create"> )}
{matchingCreateCommand.map((cmd) => ( <CommandGroup heading="Create">
<SelectableItem itemId={cmd.id} key={cmd.id}> {matchingCreateCommand.map((cmd) => (
<CommandMenuItem <SelectableItem itemId={cmd.id} key={cmd.id}>
id={cmd.id} <CommandMenuItem
to={cmd.to} id={cmd.id}
key={cmd.id} to={cmd.to}
Icon={cmd.Icon} key={cmd.id}
label={cmd.label} Icon={cmd.Icon}
onClick={cmd.onCommandClick} label={cmd.label}
firstHotKey={cmd.firstHotKey} onClick={cmd.onCommandClick}
secondHotKey={cmd.secondHotKey} firstHotKey={cmd.firstHotKey}
/> secondHotKey={cmd.secondHotKey}
</SelectableItem> />
))} </SelectableItem>
</CommandGroup> ))}
<CommandGroup heading="Navigate"> </CommandGroup>
{matchingNavigateCommand.map((cmd) => ( <CommandGroup heading="Navigate">
<SelectableItem itemId={cmd.id} key={cmd.id}> {matchingNavigateCommand.map((cmd) => (
<CommandMenuItem <SelectableItem itemId={cmd.id} key={cmd.id}>
id={cmd.id} <CommandMenuItem
to={cmd.to} id={cmd.id}
key={cmd.id} to={cmd.to}
label={cmd.label} key={cmd.id}
Icon={cmd.Icon} label={cmd.label}
onClick={cmd.onCommandClick} Icon={cmd.Icon}
firstHotKey={cmd.firstHotKey} onClick={cmd.onCommandClick}
secondHotKey={cmd.secondHotKey} firstHotKey={cmd.firstHotKey}
/> secondHotKey={cmd.secondHotKey}
</SelectableItem> />
))} </SelectableItem>
</CommandGroup> ))}
<CommandGroup heading="People"> </CommandGroup>
{people.map((person) => ( <CommandGroup heading="People">
<SelectableItem itemId={person.id} key={person.id}> {people.map((person) => (
<CommandMenuItem <SelectableItem itemId={person.id} key={person.id}>
id={person.id} <CommandMenuItem
key={person.id} id={person.id}
to={`object/person/${person.id}`} key={person.id}
label={ to={`object/person/${person.id}`}
person.name.firstName + ' ' + person.name.lastName label={
} person.name.firstName + ' ' + person.name.lastName
Icon={() => ( }
<Avatar Icon={() => (
type="rounded" <Avatar
avatarUrl={null} type="rounded"
colorId={person.id} avatarUrl={null}
placeholder={ colorId={person.id}
person.name.firstName + ' ' + person.name.lastName placeholder={
} person.name.firstName +
/> ' ' +
)} person.name.lastName
/> }
</SelectableItem> />
))} )}
</CommandGroup> />
<CommandGroup heading="Companies"> </SelectableItem>
{companies.map((company) => ( ))}
<SelectableItem itemId={company.id} key={company.id}> </CommandGroup>
<CommandMenuItem <CommandGroup heading="Companies">
id={company.id} {companies.map((company) => (
key={company.id} <SelectableItem itemId={company.id} key={company.id}>
label={company.name} <CommandMenuItem
to={`object/company/${company.id}`} id={company.id}
Icon={() => ( key={company.id}
<Avatar label={company.name}
colorId={company.id} to={`object/company/${company.id}`}
placeholder={company.name} Icon={() => (
avatarUrl={getLogoUrlFromDomainName( <Avatar
company.domainName, colorId={company.id}
)} placeholder={company.name}
/> avatarUrl={getLogoUrlFromDomainName(
)} company.domainName,
/> )}
</SelectableItem> />
))} )}
</CommandGroup> />
<CommandGroup heading="Notes"> </SelectableItem>
{activities.map((activity) => ( ))}
<SelectableItem itemId={activity.id} key={activity.id}> </CommandGroup>
<CommandMenuItem <CommandGroup heading="Notes">
id={activity.id} {activities.map((activity) => (
Icon={IconNotes} <SelectableItem itemId={activity.id} key={activity.id}>
key={activity.id} <CommandMenuItem
label={activity.title ?? ''} id={activity.id}
onClick={() => openActivityRightDrawer(activity.id)} Icon={IconNotes}
/> key={activity.id}
</SelectableItem> label={activity.title ?? ''}
))} onClick={() => openActivityRightDrawer(activity.id)}
</CommandGroup> />
</SelectableList> </SelectableItem>
</StyledInnerList> ))}
</ScrollWrapper> </CommandGroup>
</StyledList> </SelectableList>
</StyledDialog> </StyledInnerList>
) </ScrollWrapper>
</StyledList>
</StyledDialog>
)}
</>
); );
}; };

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, userEvent, within } from '@storybook/test';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { CommandType } from '@/command-menu/types/Command'; import { CommandType } from '@/command-menu/types/Command';

View File

@@ -17,14 +17,14 @@ export const mapFavorites = (favorites: any) => {
link: `/object/person/${favorite.person.id}`, link: `/object/person/${favorite.person.id}`,
} }
: isDefined(favorite?.company) : isDefined(favorite?.company)
? { ? {
id: favorite.company.id, id: favorite.company.id,
labelIdentifier: favorite.company.name, labelIdentifier: favorite.company.name,
avatarUrl: getLogoUrlFromDomainName(favorite.company.domainName), avatarUrl: getLogoUrlFromDomainName(favorite.company.domainName),
avatarType: 'squared', avatarType: 'squared',
link: `/object/company/${favorite.company.id}`, link: `/object/company/${favorite.company.id}`,
} }
: undefined; : undefined;
return { return {
...recordInformation, ...recordInformation,

View File

@@ -42,19 +42,21 @@ export const KeyboardShortcutMenu = () => {
); );
return ( return (
isKeyboardShortcutMenuOpened && ( <>
<KeyboardMenuDialog onClose={toggleKeyboardShortcutMenu}> {isKeyboardShortcutMenuOpened && (
<KeyboardMenuGroup heading="Table"> <KeyboardMenuDialog onClose={toggleKeyboardShortcutMenu}>
{keyboardShortcutsTable.map((TableShortcut) => ( <KeyboardMenuGroup heading="Table">
<KeyboardMenuItem shortcut={TableShortcut} /> {keyboardShortcutsTable.map((TableShortcut) => (
))} <KeyboardMenuItem shortcut={TableShortcut} />
</KeyboardMenuGroup> ))}
<KeyboardMenuGroup heading="General"> </KeyboardMenuGroup>
{keyboardShortcutsGeneral.map((GeneralShortcut) => ( <KeyboardMenuGroup heading="General">
<KeyboardMenuItem shortcut={GeneralShortcut} /> {keyboardShortcutsGeneral.map((GeneralShortcut) => (
))} <KeyboardMenuItem shortcut={GeneralShortcut} />
</KeyboardMenuGroup> ))}
</KeyboardMenuDialog> </KeyboardMenuGroup>
) </KeyboardMenuDialog>
)}
</>
); );
}; };

View File

@@ -34,12 +34,12 @@ export const MobileNavigationBar = () => {
const activeItemName = isNavigationDrawerOpen const activeItemName = isNavigationDrawerOpen
? currentMobileNavigationDrawer ? currentMobileNavigationDrawer
: isCommandMenuOpened : isCommandMenuOpened
? 'search' ? 'search'
: isTasksPage : isTasksPage
? 'tasks' ? 'tasks'
: isSettingsPage : isSettingsPage
? 'settings' ? 'settings'
: 'main'; : 'main';
const items: { const items: {
name: NavigationBarItemName; name: NavigationBarItemName;

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-console */
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ApolloClient, InMemoryCache } from '@apollo/client'; import { ApolloClient, InMemoryCache } from '@apollo/client';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';

View File

@@ -54,18 +54,18 @@ const formatFieldMetadataItemAsFilterDefinition = ({
field.type === FieldMetadataType.DateTime field.type === FieldMetadataType.DateTime
? 'DATE_TIME' ? 'DATE_TIME'
: field.type === FieldMetadataType.Link : field.type === FieldMetadataType.Link
? 'LINK' ? 'LINK'
: field.type === FieldMetadataType.FullName : field.type === FieldMetadataType.FullName
? 'FULL_NAME' ? 'FULL_NAME'
: field.type === FieldMetadataType.Number : field.type === FieldMetadataType.Number
? 'NUMBER' ? 'NUMBER'
: field.type === FieldMetadataType.Currency : field.type === FieldMetadataType.Currency
? 'CURRENCY' ? 'CURRENCY'
: field.type === FieldMetadataType.Email : field.type === FieldMetadataType.Email
? 'TEXT' ? 'TEXT'
: field.type === FieldMetadataType.Phone : field.type === FieldMetadataType.Phone
? 'TEXT' ? 'TEXT'
: field.type === FieldMetadataType.Relation : field.type === FieldMetadataType.Relation
? 'RELATION' ? 'RELATION'
: 'TEXT', : 'TEXT',
}); });

View File

@@ -72,8 +72,8 @@ export const RecordShowPage = () => {
objectMetadataItem?.nameSingular === 'company' objectMetadataItem?.nameSingular === 'company'
? 'Company' ? 'Company'
: objectMetadataItem?.nameSingular === 'person' : objectMetadataItem?.nameSingular === 'person'
? 'Person' ? 'Person'
: 'Custom'; : 'Custom';
const useUpdateOneObjectRecordMutation: () => [ const useUpdateOneObjectRecordMutation: () => [
(params: any) => any, (params: any) => any,
@@ -117,14 +117,14 @@ export const RecordShowPage = () => {
recordId: record.id, recordId: record.id,
} }
: objectNameSingular === 'company' : objectNameSingular === 'company'
? { ? {
labelIdentifier: record.name, labelIdentifier: record.name,
avatarUrl: getLogoUrlFromDomainName(record.domainName ?? ''), avatarUrl: getLogoUrlFromDomainName(record.domainName ?? ''),
avatarType: 'squared', avatarType: 'squared',
link: `/object/companyV2/${record.id}`, link: `/object/companyV2/${record.id}`,
recordId: record.id, recordId: record.id,
} }
: {}; : {};
createFavorite(record.id, additionalData); createFavorite(record.id, additionalData);
} }
}; };
@@ -256,8 +256,8 @@ export const RecordShowPage = () => {
objectMetadataItem?.nameSingular === 'company' objectMetadataItem?.nameSingular === 'company'
? 'Company' ? 'Company'
: objectMetadataItem?.nameSingular === 'person' : objectMetadataItem?.nameSingular === 'person'
? 'Person' ? 'Person'
: 'Custom', : 'Custom',
}} }}
timeline timeline
tasks tasks

View File

@@ -29,8 +29,8 @@ export const useLinkField = () => {
const initialValue: FieldLinkValue = fieldInitialValue?.isEmpty const initialValue: FieldLinkValue = fieldInitialValue?.isEmpty
? { url: '', label: '' } ? { url: '', label: '' }
: fieldInitialValue?.value : fieldInitialValue?.value
? { url: fieldInitialValue.value, label: '' } ? { url: fieldInitialValue.value, label: '' }
: fieldValue; : fieldValue;
const persistField = usePersistField(); const persistField = usePersistField();

View File

@@ -44,8 +44,8 @@ export const useNumberField = () => {
const initialValue = fieldInitialValue?.isEmpty const initialValue = fieldInitialValue?.isEmpty
? null ? null
: !isNaN(Number(fieldInitialValue?.value)) : !isNaN(Number(fieldInitialValue?.value))
? Number(fieldInitialValue?.value) ? Number(fieldInitialValue?.value)
: null ?? fieldValue; : null ?? fieldValue;
return { return {
fieldDefinition, fieldDefinition,

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
import { useBooleanField } from '../../../hooks/useBooleanField'; import { useBooleanField } from '../../../hooks/useBooleanField';
@@ -61,7 +60,7 @@ export default meta;
type Story = StoryObj<typeof BooleanFieldInputWithContext>; type Story = StoryObj<typeof BooleanFieldInputWithContext>;
const submitJestFn = jest.fn(); const submitJestFn = fn();
export const Default: Story = {}; export const Default: Story = {};

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -65,9 +64,9 @@ const DateFieldInputWithContext = ({
); );
}; };
const escapeJestFn = jest.fn(); const escapeJestFn = fn();
const enterJestFn = jest.fn(); const enterJestFn = fn();
const clickOutsideJestFn = jest.fn(); const clickOutsideJestFn = fn();
const meta: Meta = { const meta: Meta = {
title: 'UI/Data/Field/Input/DateFieldInput', title: 'UI/Data/Field/Input/DateFieldInput',

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -68,11 +67,11 @@ const EmailFieldInputWithContext = ({
); );
}; };
const enterJestFn = jest.fn(); const enterJestFn = fn();
const escapeJestfn = jest.fn(); const escapeJestfn = fn();
const clickOutsideJestFn = jest.fn(); const clickOutsideJestFn = fn();
const tabJestFn = jest.fn(); const tabJestFn = fn();
const shiftTabJestFn = jest.fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -68,11 +67,11 @@ const NumberFieldInputWithContext = ({
); );
}; };
const enterJestFn = jest.fn(); const enterJestFn = fn();
const escapeJestfn = jest.fn(); const escapeJestfn = fn();
const clickOutsideJestFn = jest.fn(); const clickOutsideJestFn = fn();
const tabJestFn = jest.fn(); const tabJestFn = fn();
const shiftTabJestFn = jest.fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -69,11 +68,11 @@ const PhoneFieldInputWithContext = ({
); );
}; };
const enterJestFn = jest.fn(); const enterJestFn = fn();
const escapeJestfn = jest.fn(); const escapeJestfn = fn();
const clickOutsideJestFn = jest.fn(); const clickOutsideJestFn = fn();
const tabJestFn = jest.fn(); const tabJestFn = fn();
const shiftTabJestFn = jest.fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
@@ -60,7 +59,7 @@ const RatingFieldInputWithContext = ({
); );
}; };
const submitJestFn = jest.fn(); const submitJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -66,8 +65,8 @@ const RelationFieldInputWithContext = ({
); );
}; };
const submitJestFn = jest.fn(); const submitJestFn = fn();
const cancelJestFn = jest.fn(); const cancelJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library'; import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -68,11 +67,11 @@ const TextFieldInputWithContext = ({
); );
}; };
const enterJestFn = jest.fn(); const enterJestFn = fn();
const escapeJestfn = jest.fn(); const escapeJestfn = fn();
const clickOutsideJestFn = jest.fn(); const clickOutsideJestFn = fn();
const tabJestFn = jest.fn(); const tabJestFn = fn();
const shiftTabJestFn = jest.fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -22,30 +22,32 @@ type AssertFieldMetadataFunction = <
T extends E extends 'BOOLEAN' T extends E extends 'BOOLEAN'
? FieldBooleanMetadata ? FieldBooleanMetadata
: E extends 'CURRENCY' : E extends 'CURRENCY'
? FieldCurrencyMetadata ? FieldCurrencyMetadata
: E extends 'FULL_NAME' : E extends 'FULL_NAME'
? FieldFullNameMetadata ? FieldFullNameMetadata
: E extends 'DATE_TIME' : E extends 'DATE_TIME'
? FieldDateTimeMetadata ? FieldDateTimeMetadata
: E extends 'EMAIL' : E extends 'EMAIL'
? FieldEmailMetadata ? FieldEmailMetadata
: E extends 'SELECT' : E extends 'SELECT'
? FieldSelectMetadata ? FieldSelectMetadata
: E extends 'LINK' : E extends 'RATING'
? FieldLinkMetadata ? FieldRatingMetadata
: E extends 'NUMBER' : E extends 'LINK'
? FieldNumberMetadata ? FieldLinkMetadata
: E extends 'PHONE' : E extends 'NUMBER'
? FieldPhoneMetadata ? FieldNumberMetadata
: E extends 'RATING' : E extends 'PHONE'
? FieldRatingMetadata ? FieldPhoneMetadata
: E extends 'RELATION' : E extends 'PROBABILITY'
? FieldRelationMetadata ? FieldRatingMetadata
: E extends 'TEXT' : E extends 'RELATION'
? FieldTextMetadata ? FieldRelationMetadata
: E extends 'UUID' : E extends 'TEXT'
? FieldUuidMetadata ? FieldTextMetadata
: never, : E extends 'UUID'
? FieldUuidMetadata
: never,
>( >(
fieldType: E, fieldType: E,
fieldTypeGuard: ( fieldTypeGuard: (

View File

@@ -65,4 +65,4 @@ export const getRecordOptimisticEffectDefinition = ({
}, },
isUsingFlexibleBackend: true, isUsingFlexibleBackend: true,
objectMetadataItem, objectMetadataItem,
} satisfies OptimisticEffectDefinition); }) satisfies OptimisticEffectDefinition;

View File

@@ -22,10 +22,10 @@ export const useGenerateFindManyRecordsQuery = ({
query FindMany${capitalize( query FindMany${capitalize(
objectMetadataItem.namePlural, objectMetadataItem.namePlural,
)}($filter: ${capitalize( )}($filter: ${capitalize(
objectMetadataItem.nameSingular, objectMetadataItem.nameSingular,
)}FilterInput, $orderBy: ${capitalize( )}FilterInput, $orderBy: ${capitalize(
objectMetadataItem.nameSingular, objectMetadataItem.nameSingular,
)}OrderByInput, $lastCursor: String, $limit: Float = 30) { )}OrderByInput, $lastCursor: String, $limit: Float = 30) {
${ ${
objectMetadataItem.namePlural objectMetadataItem.namePlural
}(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor){ }(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor){

View File

@@ -12,7 +12,7 @@ export type RecordBoardInternalEffectProps = {
onFieldsChange: (fields: any) => void; onFieldsChange: (fields: any) => void;
}; };
export const RecordBoardInternalEffect = ({}) => { export const RecordBoardInternalEffect = () => {
const updateCompanyColumnsBoardInternal = const updateCompanyColumnsBoardInternal =
useUpdateCompanyBoardColumnsInternal(); useUpdateCompanyBoardColumnsInternal();
const { setActionBarEntries } = useRecordBoardActionBarEntriesInternal(); const { setActionBarEntries } = useRecordBoardActionBarEntriesInternal();

View File

@@ -22,13 +22,14 @@ export const useBoardColumnsInternal = () => {
if (!stages.length) return; if (!stages.length) return;
return Promise.all( return Promise.all(
stages.map((stage) => stages.map(
updateOnePipelineStep?.({ (stage) =>
idToUpdate: stage.id, updateOnePipelineStep?.({
input: { idToUpdate: stage.id,
position: stage.position, input: {
}, position: stage.position,
}), },
}),
), ),
); );
}; };

View File

@@ -161,8 +161,8 @@ export const RecordBoardOptionsDropdownContent = ({
viewEditMode === 'create' viewEditMode === 'create'
? 'New view' ? 'New view'
: viewEditMode === 'edit' : viewEditMode === 'edit'
? 'View name' ? 'View name'
: '' : ''
} }
defaultValue={viewEditMode === 'create' ? '' : currentView?.name} defaultValue={viewEditMode === 'create' ? '' : currentView?.name}
/> />

View File

@@ -109,8 +109,8 @@ export const TableOptionsDropdownContent = ({
viewEditMode === 'create' viewEditMode === 'create'
? 'New view' ? 'New view'
: viewEditMode === 'edit' : viewEditMode === 'edit'
? 'View name' ? 'View name'
: '' : ''
} }
defaultValue={viewEditMode === 'create' ? '' : currentView?.name} defaultValue={viewEditMode === 'create' ? '' : currentView?.name}
/> />

View File

@@ -18,8 +18,8 @@ export const allRowsSelectedStatusSelector = selector<AllRowsSelectedStatus>({
numberOfSelectedRows === 0 numberOfSelectedRows === 0
? 'none' ? 'none'
: numberOfRows === numberOfSelectedRows : numberOfRows === numberOfSelectedRows
? 'all' ? 'all'
: 'some'; : 'some';
return allRowsSelectedStatus; return allRowsSelectedStatus;
}, },

View File

@@ -1,6 +1,5 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, userEvent, within } from '@storybook/test';
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker'; import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
import { IconUserCircle } from '@/ui/display/icon'; import { IconUserCircle } from '@/ui/display/icon';

View File

@@ -1,6 +1,6 @@
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { userEvent, within } from '@storybook/test';
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider'; import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';

View File

@@ -67,7 +67,7 @@ export const useFieldPreview = ({
fieldMetadata.type === FieldMetadataType.Relation fieldMetadata.type === FieldMetadataType.Relation
? relationValue ? relationValue
: fieldMetadata.type === FieldMetadataType.Select : fieldMetadata.type === FieldMetadataType.Select
? selectValue || defaultSelectValue ? selectValue || defaultSelectValue
: firstRecordFieldValue || settingsFieldMetadataType?.defaultValue, : firstRecordFieldValue || settingsFieldMetadataType?.defaultValue,
}; };
}; };

View File

@@ -1,13 +1,12 @@
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { SettingsObjectDisabledMenuDropDown } from '../SettingsObjectDisabledMenuDropDown'; import { SettingsObjectDisabledMenuDropDown } from '../SettingsObjectDisabledMenuDropDown';
const handleActivateMockFunction = jest.fn(); const handleActivateMockFunction = fn();
const handleEraseMockFunction = jest.fn(); const handleEraseMockFunction = fn();
const ClearMocksDecorator: Decorator = (Story, context) => { const ClearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks) {

View File

@@ -1,3 +1,4 @@
// @ts-expect-error // Todo: remove usage of react-data-grid
import DataGrid, { DataGridProps } from 'react-data-grid'; import DataGrid, { DataGridProps } from 'react-data-grid';
import styled from '@emotion/styled'; import styled from '@emotion/styled';

View File

@@ -1,3 +1,4 @@
// @ts-expect-error // Todo: remove usage of react-data-grid
import { Column, FormatterProps, useRowSelection } from 'react-data-grid'; import { Column, FormatterProps, useRowSelection } from 'react-data-grid';
import { RawData } from '@/spreadsheet-import/types'; import { RawData } from '@/spreadsheet-import/types';

View File

@@ -20,20 +20,21 @@ export const SelectHeaderTable = ({
return ( return (
<Table <Table
rowKeyGetter={(row) => data.indexOf(row)} // Todo: remove usage of react-data-grid
rowKeyGetter={(row: any) => data.indexOf(row)}
rows={data} rows={data}
columns={columns} columns={columns}
selectedRows={selectedRows} selectedRows={selectedRows}
onSelectedRowsChange={(newRows) => { onSelectedRowsChange={(newRows: any) => {
// allow selecting only one row // allow selecting only one row
newRows.forEach((value) => { newRows.forEach((value: any) => {
if (!selectedRows.has(value as number)) { if (!selectedRows.has(value as number)) {
setSelectedRows(new Set([value as number])); setSelectedRows(new Set([value as number]));
return; return;
} }
}); });
}} }}
onRowClick={(row) => { onRowClick={(row: any) => {
setSelectedRows(new Set([data.indexOf(row)])); setSelectedRows(new Set([data.indexOf(row)]));
}} }}
headerRowHeight={0} headerRowHeight={0}

View File

@@ -44,9 +44,17 @@ const StyledContainer = styled.div`
${theme.font.color.primary} 20px ${theme.font.color.primary} 20px
); );
`}; `};
background-position: 0 0, 0 0, 100% 0, 0 100%; background-position:
0 0,
0 0,
100% 0,
0 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 2px 100%, 100% 2px, 2px 100%, 100% 2px; background-size:
2px 100%,
100% 2px,
2px 100%,
100% 2px;
border-radius: ${({ theme }) => theme.border.radius.sm}; border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex; display: flex;
flex: 1; flex: 1;

View File

@@ -1,3 +1,4 @@
// @ts-expect-error // Todo: remove usage of react-data-grid
import { Column } from 'react-data-grid'; import { Column } from 'react-data-grid';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
@@ -48,7 +49,7 @@ export const generateColumns = <T extends string>(fields: Fields<T>) =>
)} )}
</StyledHeaderContainer> </StyledHeaderContainer>
), ),
formatter: ({ row }) => ( formatter: ({ row }: any) => (
<StyledDefaultContainer>{row[column.key]}</StyledDefaultContainer> <StyledDefaultContainer>{row[column.key]}</StyledDefaultContainer>
), ),
}), }),

View File

@@ -1,4 +1,5 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
// @ts-expect-error Todo: remove usage of react-data-grid
import { RowsChangeData } from 'react-data-grid'; import { RowsChangeData } from 'react-data-grid';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
@@ -105,14 +106,18 @@ export const ValidationStep = <T extends string>({
rows: typeof data, rows: typeof data,
changedData?: RowsChangeData<(typeof data)[number]>, changedData?: RowsChangeData<(typeof data)[number]>,
) => { ) => {
const changes = changedData?.indexes.reduce((acc, index) => { const changes = changedData?.indexes.reduce(
// when data is filtered val !== actual index in data // Todo: remove usage of react-data-grid
const realIndex = data.findIndex( (acc: any, index: any) => {
(value) => value.__index === rows[index].__index, // when data is filtered val !== actual index in data
); const realIndex = data.findIndex(
acc[realIndex] = rows[index]; (value) => value.__index === rows[index].__index,
return acc; );
}, {} as Record<number, (typeof data)[number]>); acc[realIndex] = rows[index];
return acc;
},
{} as Record<number, (typeof data)[number]>,
);
const newData = Object.assign([], data, changes); const newData = Object.assign([], data, changes);
updateData(newData); updateData(newData);
}, },

View File

@@ -1,3 +1,4 @@
// @ts-expect-error // Todo: remove usage of react-data-grid
import { Column, useRowSelection } from 'react-data-grid'; import { Column, useRowSelection } from 'react-data-grid';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
@@ -71,7 +72,7 @@ export const generateColumns = <T extends string>(
resizable: false, resizable: false,
sortable: false, sortable: false,
frozen: true, frozen: true,
formatter: (props) => { formatter: (props: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
const [isRowSelected, onRowSelectionChange] = useRowSelection(); const [isRowSelected, onRowSelectionChange] = useRowSelection();
@@ -116,7 +117,8 @@ export const generateColumns = <T extends string>(
</StyledHeaderContainer> </StyledHeaderContainer>
), ),
editable: column.fieldType.type !== 'checkbox', editable: column.fieldType.type !== 'checkbox',
editor: ({ row, onRowChange, onClose }) => { // Todo: remove usage of react-data-grid
editor: ({ row, onRowChange, onClose }: any) => {
const columnKey = column.key as keyof (Data<T> & Meta); const columnKey = column.key as keyof (Data<T> & Meta);
let component; let component;
@@ -162,7 +164,8 @@ export const generateColumns = <T extends string>(
editorOptions: { editorOptions: {
editOnClick: true, editOnClick: true,
}, },
formatter: ({ row, onRowChange }) => { // Todo: remove usage of react-data-grid
formatter: ({ row, onRowChange }: { row: any; onRowChange: any }) => {
const columnKey = column.key as keyof (Data<T> & Meta); const columnKey = column.key as keyof (Data<T> & Meta);
let component; let component;

View File

@@ -6,8 +6,9 @@ export const findUnmatchedRequiredFields = <T extends string>(
columns: Columns<T>, columns: Columns<T>,
) => ) =>
fields fields
.filter((field) => .filter(
field.validations?.some((validation) => validation.rule === 'required'), (field) =>
field.validations?.some((validation) => validation.rule === 'required'),
) )
.filter( .filter(
(field) => (field) =>

View File

@@ -7,8 +7,11 @@ const titleMap: Record<Field<string>['fieldType']['type'], string> = {
}; };
export const generateExampleRow = <T extends string>(fields: Fields<T>) => [ export const generateExampleRow = <T extends string>(fields: Fields<T>) => [
fields.reduce((acc, field) => { fields.reduce(
acc[field.key as T] = field.example || titleMap[field.fieldType.type]; (acc, field) => {
return acc; acc[field.key as T] = field.example || titleMap[field.fieldType.type];
}, {} as Record<T, string>), return acc;
},
{} as Record<T, string>,
),
]; ];

View File

@@ -41,8 +41,8 @@ const StyledContainer = styled.div<Partial<ChipProps>>`
variant === ChipVariant.Highlighted variant === ChipVariant.Highlighted
? theme.background.transparent.light ? theme.background.transparent.light
: variant === ChipVariant.Rounded : variant === ChipVariant.Rounded
? theme.background.transparent.lighter ? theme.background.transparent.lighter
: 'transparent'}; : 'transparent'};
border-color: ${({ theme, variant }) => border-color: ${({ theme, variant }) =>
variant === ChipVariant.Rounded ? theme.border.color.medium : 'none'}; variant === ChipVariant.Rounded ? theme.border.color.medium : 'none'};
border-radius: ${({ theme, variant }) => border-radius: ${({ theme, variant }) =>
@@ -56,14 +56,14 @@ const StyledContainer = styled.div<Partial<ChipProps>>`
disabled disabled
? theme.font.color.light ? theme.font.color.light
: accent === ChipAccent.TextPrimary : accent === ChipAccent.TextPrimary
? theme.font.color.primary ? theme.font.color.primary
: theme.font.color.secondary}; : theme.font.color.secondary};
cursor: ${({ clickable, disabled, variant }) => cursor: ${({ clickable, disabled, variant }) =>
disabled || variant === ChipVariant.Transparent disabled || variant === ChipVariant.Transparent
? 'inherit' ? 'inherit'
: clickable : clickable
? 'pointer' ? 'pointer'
: 'inherit'}; : 'inherit'};
display: inline-flex; display: inline-flex;
font-weight: ${({ theme, accent }) => font-weight: ${({ theme, accent }) =>
accent === ChipAccent.TextSecondary ? theme.font.weight.medium : 'inherit'}; accent === ChipAccent.TextSecondary ? theme.font.weight.medium : 'inherit'};
@@ -85,8 +85,8 @@ const StyledContainer = styled.div<Partial<ChipProps>>`
(variant === ChipVariant.Highlighted (variant === ChipVariant.Highlighted
? theme.background.transparent.medium ? theme.background.transparent.medium
: variant === ChipVariant.Regular : variant === ChipVariant.Regular
? theme.background.transparent.light ? theme.background.transparent.light
: 'transparent') + : 'transparent') +
';' ';'
); );
} }
@@ -100,8 +100,8 @@ const StyledContainer = styled.div<Partial<ChipProps>>`
(variant === ChipVariant.Highlighted (variant === ChipVariant.Highlighted
? theme.background.transparent.strong ? theme.background.transparent.strong
: variant === ChipVariant.Regular : variant === ChipVariant.Regular
? theme.background.transparent.medium ? theme.background.transparent.medium
: 'transparent') + : 'transparent') +
';' ';'
); );
} }

View File

@@ -1,6 +1,6 @@
import { TablerIconsProps } from '@/ui/display/icon'; import { TablerIconsProps } from '@/ui/display/icon';
import { ReactComponent as IconAddressBookRaw } from '../assets/address-book.svg'; import IconAddressBookRaw from '../assets/address-book.svg?react';
type IconAddressBookProps = TablerIconsProps; type IconAddressBookProps = TablerIconsProps;

View File

@@ -1,6 +1,6 @@
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import { ReactComponent as IconGoogleRaw } from '../assets/google-icon.svg'; import IconGoogleRaw from '../assets/google-icon.svg?react';
interface IconGoogleProps { interface IconGoogleProps {
size?: number; size?: number;

View File

@@ -1,6 +1,6 @@
import { TablerIconsProps } from '@/ui/display/icon'; import { TablerIconsProps } from '@/ui/display/icon';
import { ReactComponent as IconTwentyStarRaw } from '../assets/twenty-star.svg'; import IconTwentyStarRaw from '../assets/twenty-star.svg?react';
type IconTwentyStarProps = TablerIconsProps; type IconTwentyStarProps = TablerIconsProps;

View File

@@ -1,6 +1,6 @@
import { TablerIconsProps } from '@/ui/display/icon'; import { TablerIconsProps } from '@/ui/display/icon';
import { ReactComponent as IconTwentyStarFilledRaw } from '../assets/twenty-star-filled.svg'; import IconTwentyStarFilledRaw from '../assets/twenty-star-filled.svg?react';
type IconTwentyStarFilledProps = TablerIconsProps; type IconTwentyStarFilledProps = TablerIconsProps;

View File

@@ -1,6 +1,5 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { mainColorNames, ThemeColor } from '@/ui/theme/constants/colors'; import { mainColorNames, ThemeColor } from '@/ui/theme/constants/colors';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator'; import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
@@ -23,7 +22,7 @@ type Story = StoryObj<typeof Status>;
export const Default: Story = { export const Default: Story = {
args: { args: {
color: 'red', color: 'red',
onClick: jest.fn(), onClick: fn(),
}, },
decorators: [ComponentDecorator], decorators: [ComponentDecorator],
play: async ({ canvasElement, args }) => { play: async ({ canvasElement, args }) => {

View File

@@ -1,6 +1,5 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { mainColorNames, ThemeColor } from '@/ui/theme/constants/colors'; import { mainColorNames, ThemeColor } from '@/ui/theme/constants/colors';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator'; import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
@@ -23,7 +22,7 @@ type Story = StoryObj<typeof Tag>;
export const Default: Story = { export const Default: Story = {
args: { args: {
color: 'red', color: 'red',
onClick: jest.fn(), onClick: fn(),
}, },
decorators: [ComponentDecorator], decorators: [ComponentDecorator],
play: async ({ canvasElement, args }) => { play: async ({ canvasElement, args }) => {

View File

@@ -1,5 +1,5 @@
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { userEvent, within } from '@storybook/test';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';

View File

@@ -142,8 +142,8 @@ const StyledButton = styled.button<
? theme.color.blue ? theme.color.blue
: theme.background.transparent.light : theme.background.transparent.light
: focus : focus
? theme.color.blue ? theme.color.blue
: 'transparent' : 'transparent'
}; };
border-width: ${!disabled && focus ? '1px 1px !important' : 0}; border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${ box-shadow: ${
@@ -178,8 +178,8 @@ const StyledButton = styled.button<
? theme.color.blue ? theme.color.blue
: theme.color.blue20 : theme.color.blue20
: focus : focus
? theme.color.blue ? theme.color.blue
: 'transparent' : 'transparent'
}; };
border-width: ${!disabled && focus ? '1px 1px !important' : 0}; border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${ box-shadow: ${
@@ -210,8 +210,8 @@ const StyledButton = styled.button<
? theme.color.red ? theme.color.red
: theme.border.color.danger : theme.border.color.danger
: focus : focus
? theme.color.red ? theme.color.red
: 'transparent' : 'transparent'
}; };
border-width: ${!disabled && focus ? '1px 1px !important' : 0}; border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${ box-shadow: ${

View File

@@ -40,8 +40,8 @@ const StyledButton = styled.button<
focus ? `,0 0 0 3px ${theme.color.blue10}` : '' focus ? `,0 0 0 3px ${theme.color.blue10}` : ''
}` }`
: focus : focus
? `0 0 0 3px ${theme.color.blue10}` ? `0 0 0 3px ${theme.color.blue10}`
: 'none'}; : 'none'};
color: ${({ theme, disabled, focus }) => { color: ${({ theme, disabled, focus }) => {
return !disabled return !disabled
? focus ? focus

View File

@@ -33,9 +33,7 @@ const StyledButton = styled.button<
align-items: center; align-items: center;
backdrop-filter: ${({ applyBlur }) => (applyBlur ? 'blur(20px)' : 'none')}; backdrop-filter: ${({ applyBlur }) => (applyBlur ? 'blur(20px)' : 'none')};
background: ${({ theme, isActive }) => background: ${({ theme, isActive }) =>
!!isActive isActive ? theme.background.transparent.medium : theme.background.primary};
? theme.background.transparent.medium
: theme.background.primary};
border: ${({ focus, theme }) => border: ${({ focus, theme }) =>
focus ? `1px solid ${theme.color.blue}` : 'transparent'}; focus ? `1px solid ${theme.color.blue}` : 'transparent'};
border-radius: ${({ position, theme }) => { border-radius: ${({ position, theme }) => {
@@ -56,8 +54,8 @@ const StyledButton = styled.button<
theme.background.transparent.medium theme.background.transparent.medium
}${focus ? `,0 0 0 3px ${theme.color.blue10}` : ''}` }${focus ? `,0 0 0 3px ${theme.color.blue10}` : ''}`
: focus : focus
? `0 0 0 3px ${theme.color.blue10}` ? `0 0 0 3px ${theme.color.blue10}`
: 'none'}; : 'none'};
box-sizing: border-box; box-sizing: border-box;
color: ${({ theme, disabled, focus }) => { color: ${({ theme, disabled, focus }) => {
return !disabled return !disabled

View File

@@ -42,10 +42,10 @@ export const FloatingIconButtonGroup = ({
iconButtons.length === 1 iconButtons.length === 1
? 'standalone' ? 'standalone'
: index === 0 : index === 0
? 'left' ? 'left'
: index === iconButtons.length - 1 : index === iconButtons.length - 1
? 'right' ? 'right'
: 'middle'; : 'middle';
return ( return (
<FloatingIconButton <FloatingIconButton

View File

@@ -137,8 +137,8 @@ const StyledButton = styled.button<
? theme.color.blue ? theme.color.blue
: theme.background.transparent.light : theme.background.transparent.light
: focus : focus
? theme.color.blue ? theme.color.blue
: 'transparent' : 'transparent'
}; };
border-width: ${!disabled && focus ? '1px 1px !important' : 0}; border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${ box-shadow: ${
@@ -173,8 +173,8 @@ const StyledButton = styled.button<
? theme.color.blue ? theme.color.blue
: theme.color.blue20 : theme.color.blue20
: focus : focus
? theme.color.blue ? theme.color.blue
: 'transparent' : 'transparent'
}; };
border-width: ${!disabled && focus ? '1px 1px !important' : 0}; border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${ box-shadow: ${
@@ -201,8 +201,8 @@ const StyledButton = styled.button<
variant === 'secondary' variant === 'secondary'
? theme.border.color.danger ? theme.border.color.danger
: focus : focus
? theme.color.red ? theme.color.red
: 'transparent' : 'transparent'
}; };
border-width: ${!disabled && focus ? '1px 1px !important' : 0}; border-width: ${!disabled && focus ? '1px 1px !important' : 0};
box-shadow: ${ box-shadow: ${

View File

@@ -34,8 +34,8 @@ export const IconButtonGroup = ({
index === 0 index === 0
? 'left' ? 'left'
: index === iconButtons.length - 1 : index === iconButtons.length - 1
? 'right' ? 'right'
: 'middle'; : 'middle';
return ( return (
<IconButton <IconButton

View File

@@ -33,14 +33,14 @@ const StyledButton = styled.button<
return active || focus return active || focus
? theme.color.blue ? theme.color.blue
: !disabled : !disabled
? theme.font.color.secondary ? theme.font.color.secondary
: theme.font.color.extraLight; : theme.font.color.extraLight;
case 'tertiary': case 'tertiary':
return active || focus return active || focus
? theme.color.blue ? theme.color.blue
: !disabled : !disabled
? theme.font.color.tertiary ? theme.font.color.tertiary
: theme.font.color.extraLight; : theme.font.color.extraLight;
} }
}}; }};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};

View File

@@ -38,14 +38,14 @@ const StyledButton = styled.button<
return active || focus return active || focus
? theme.color.blue ? theme.color.blue
: !disabled : !disabled
? theme.font.color.secondary ? theme.font.color.secondary
: theme.font.color.extraLight; : theme.font.color.extraLight;
case 'tertiary': case 'tertiary':
return active || focus return active || focus
? theme.color.blue ? theme.color.blue
: !disabled : !disabled
? theme.font.color.tertiary ? theme.font.color.tertiary
: theme.font.color.extraLight; : theme.font.color.extraLight;
} }
}}; }};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};

View File

@@ -19,7 +19,9 @@ const StyledIconButton = styled.button`
outline: none; outline: none;
padding: 0; padding: 0;
transition: color 0.1s ease-in-out, background 0.1s ease-in-out; transition:
color 0.1s ease-in-out,
background 0.1s ease-in-out;
&:disabled { &:disabled {
background: ${({ theme }) => theme.background.quaternary}; background: ${({ theme }) => theme.background.quaternary};

View File

@@ -1,13 +1,12 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { IconBrandGoogle } from '@/ui/display/icon'; import { IconBrandGoogle } from '@/ui/display/icon';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { MainButton } from '../MainButton'; import { MainButton } from '../MainButton';
const clickJestFn = jest.fn(); const clickJestFn = fn();
const meta: Meta<typeof MainButton> = { const meta: Meta<typeof MainButton> = {
title: 'UI/Input/Button/MainButton', title: 'UI/Input/Button/MainButton',

View File

@@ -1,13 +1,12 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { IconArrowRight } from '@/ui/display/icon'; import { IconArrowRight } from '@/ui/display/icon';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { RoundedIconButton } from '../RoundedIconButton'; import { RoundedIconButton } from '../RoundedIconButton';
const clickJestFn = jest.fn(); const clickJestFn = fn();
const meta: Meta<typeof RoundedIconButton> = { const meta: Meta<typeof RoundedIconButton> = {
title: 'UI/Input/Button/RoundedIconButton', title: 'UI/Input/Button/RoundedIconButton',

View File

@@ -1,6 +1,5 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';

View File

@@ -1,6 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { userEvent, within } from '@storybook/test';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';

View File

@@ -1,6 +1,5 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';

View File

@@ -1,8 +1,7 @@
import { useState } from 'react'; import { useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { expect } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library'; import { expect, userEvent, waitFor, within } from '@storybook/test';
import { PlayFunction } from '@storybook/types'; import { PlayFunction } from '@storybook/types';
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';

View File

@@ -23,8 +23,8 @@ const StyledTab = styled.div<{ active?: boolean; disabled?: boolean }>`
active active
? theme.font.color.primary ? theme.font.color.primary
: disabled : disabled
? theme.font.color.light ? theme.font.color.light
: theme.font.color.secondary}; : theme.font.color.secondary};
cursor: pointer; cursor: pointer;
display: flex; display: flex;

View File

@@ -1,6 +1,5 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { within } from '@storybook/testing-library'; import { expect, within } from '@storybook/test';
import { IconCheckbox } from '@/ui/display/icon'; import { IconCheckbox } from '@/ui/display/icon';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';

View File

@@ -14,8 +14,8 @@ const StyledTableCell = styled.div<TableCellProps>`
align === 'right' align === 'right'
? 'flex-end' ? 'flex-end'
: align === 'center' : align === 'center'
? 'center' ? 'center'
: 'flex-start'}; : 'flex-start'};
padding: 0 ${({ theme }) => theme.spacing(2)}; padding: 0 ${({ theme }) => theme.spacing(2)};
text-align: ${({ align }) => align ?? 'left'}; text-align: ${({ align }) => align ?? 'left'};
`; `;

View File

@@ -11,8 +11,8 @@ const StyledTableHeader = styled.div<{ align?: 'left' | 'center' | 'right' }>`
align === 'right' align === 'right'
? 'flex-end' ? 'flex-end'
: align === 'center' : align === 'center'
? 'center' ? 'center'
: 'flex-start'}; : 'flex-start'};
padding: 0 ${({ theme }) => theme.spacing(2)}; padding: 0 ${({ theme }) => theme.spacing(2)};
text-align: ${({ align }) => align ?? 'left'}; text-align: ${({ align }) => align ?? 'left'};
`; `;

View File

@@ -32,7 +32,8 @@ const StyledSection = styled.div<{ isExpanded: boolean }>`
max-height: ${({ isExpanded }) => (isExpanded ? '1000px' : 0)}; max-height: ${({ isExpanded }) => (isExpanded ? '1000px' : 0)};
opacity: ${({ isExpanded }) => (isExpanded ? 1 : 0)}; opacity: ${({ isExpanded }) => (isExpanded ? 1 : 0)};
overflow: hidden; overflow: hidden;
transition: max-height ${({ theme }) => theme.animation.duration.normal}s, transition:
max-height ${({ theme }) => theme.animation.duration.normal}s,
opacity ${({ theme }) => theme.animation.duration.normal}s; opacity ${({ theme }) => theme.animation.duration.normal}s;
`; `;

View File

@@ -1,5 +1,5 @@
import { jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
@@ -18,7 +18,7 @@ const meta: Meta<typeof ContactLink> = {
export default meta; export default meta;
type Story = StoryObj<typeof ContactLink>; type Story = StoryObj<typeof ContactLink>;
const clickJestFn = jest.fn(); const clickJestFn = fn();
export const Email: Story = { export const Email: Story = {
args: { args: {

View File

@@ -1,6 +1,5 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
@@ -19,7 +18,7 @@ const meta: Meta<typeof RawLink> = {
export default meta; export default meta;
type Story = StoryObj<typeof RawLink>; type Story = StoryObj<typeof RawLink>;
const clickJestFn = jest.fn(); const clickJestFn = fn();
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

@@ -1,6 +1,5 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
@@ -18,7 +17,7 @@ const meta: Meta<typeof RoundedLink> = {
export default meta; export default meta;
type Story = StoryObj<typeof RoundedLink>; type Story = StoryObj<typeof RoundedLink>;
const clickJestFn = jest.fn(); const clickJestFn = fn();
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

@@ -1,6 +1,5 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
@@ -18,7 +17,7 @@ const meta: Meta<typeof SocialLink> = {
export default meta; export default meta;
type Story = StoryObj<typeof SocialLink>; type Story = StoryObj<typeof SocialLink>;
const clickJestFn = jest.fn(); const clickJestFn = fn();
const linkedin: LinkType = LinkType.LinkedIn; const linkedin: LinkType = LinkType.LinkedIn;
const twitter: LinkType = LinkType.Twitter; const twitter: LinkType = LinkType.Twitter;

View File

@@ -80,8 +80,8 @@ export const NavigationDrawer = ({
const desktopWidth = !isNavigationDrawerOpen const desktopWidth = !isNavigationDrawerOpen
? 12 ? 12
: isSubMenu : isSubMenu
? desktopNavDrawerWidths.submenu ? desktopNavDrawerWidths.submenu
: desktopNavDrawerWidths.menu; : desktopNavDrawerWidths.menu;
const mobileWidth = isNavigationDrawerOpen ? '100%' : 0; const mobileWidth = isNavigationDrawerOpen ? '100%' : 0;

Some files were not shown because too many files have changed in this diff Show More