Add a custom rule to prevent colors from being hardcoded outside of theme (#288)

* Add a custom rule to prevent colors from being hardcoded in ESLint

* Refactor colors

* Create packages folder and fix colors

* Remove external dependency for css alphabetical order linting

* Fix install with yarn

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Félix Malfait 2023-06-14 16:56:29 +02:00 committed by GitHub
parent bf6fb0ba70
commit 31f3950439
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 31490 additions and 62652 deletions

View File

@ -6,5 +6,5 @@
"ghcr.io/devcontainers-contrib/features/jshint:2": {} "ghcr.io/devcontainers-contrib/features/jshint:2": {}
}, },
"forwardPorts": [3000, 3001, 5432], "forwardPorts": [3000, 3001, 5432],
"postCreateCommand": "cd front && npm install && cd ../server && npm install" "postCreateCommand": "cd front && yarn && cd ../server && yarn"
} }

View File

@ -16,17 +16,6 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: "18" node-version: "18"
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Front / Write .env - name: Front / Write .env
run: | run: |
cd front cd front
@ -34,7 +23,7 @@ jobs:
echo "REACT_APP_API_URL: $REACT_APP_API_URL" >> .env echo "REACT_APP_API_URL: $REACT_APP_API_URL" >> .env
echo "REACT_APP_AUTH_URL: $REACT_APP_AUTH_URL" >> .env echo "REACT_APP_AUTH_URL: $REACT_APP_AUTH_URL" >> .env
- name: Front / Install Dependencies - name: Front / Install Dependencies
run: cd front && npm install run: cd front && yarn
- name: Publish to Chromatic - name: Publish to Chromatic
uses: chromaui/action@v1 uses: chromaui/action@v1
with: with:

View File

@ -10,18 +10,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: "18" node-version: "18"
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Docs / Install Dependencies - name: Docs / Install Dependencies
run: cd docs && npm install run: cd docs && yarn
- name: Docs / Build Documentation - name: Docs / Build Documentation
run: cd docs && npm run build run: cd docs && yarn build

View File

@ -13,17 +13,6 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: "18" node-version: "18"
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Front / Write .env - name: Front / Write .env
run: | run: |
cd front cd front
@ -31,18 +20,18 @@ jobs:
echo "REACT_APP_API_URL: $REACT_APP_API_URL" >> .env echo "REACT_APP_API_URL: $REACT_APP_API_URL" >> .env
echo "REACT_APP_AUTH_URL: $REACT_APP_AUTH_URL" >> .env echo "REACT_APP_AUTH_URL: $REACT_APP_AUTH_URL" >> .env
- name: Front / Install Dependencies - name: Front / Install Dependencies
run: cd front && npm install run: cd front && yarn
- name: Front / Install Playwright - name: Front / Install Playwright
run: cd front && npx playwright install --with-deps run: cd front && npx playwright install --with-deps
- name: Front / Run linter - name: Front / Run linter
run: cd front && npm run lint run: cd front && yarn lint
- name: Front / Build Storybook - name: Front / Build Storybook
run: cd front && npm run build-storybook --quiet run: cd front && yarn build-storybook --quiet
- name: Front / Run storybook tests - name: Front / Run storybook tests
run: | run: |
cd front && npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \ cd front && npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
"npx http-server storybook-static --silent --port 6006" \ "npx http-server storybook-static --silent --port 6006" \
"npm run coverage" "yarn coverage"
- name: Front / Run jest tests - name: Front / Run jest tests
run: | run: |
cd front && npm run test cd front && yarn test

View File

@ -10,21 +10,10 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: "18" node-version: "18"
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Server / Install Dependencies - name: Server / Install Dependencies
run: cd server && npm install run: cd server && yarn install
- name: Server / Run linter - name: Server / Run linter
run: cd server && npm run lint run: cd server && yarn lint
- name: Server / Run jest tests - name: Server / Run jest tests
run: | run: |
cd server && npm run test cd server && yarn test

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
**/**/.env **/**/.env
.DS_Store .DS_Store
node_modules/

View File

@ -88,16 +88,16 @@ Most default value should work out of the box, but don't forget to update the da
On the frontend: On the frontend:
``` ```
cd front cd front
npm install yarn
``` ```
On the server side: On the server side:
``` ```
cd server cd server
npm install yarn
npm run prisma:migrate yarn prisma:migrate
``` ```
You can also add `npm run prisma:seed` to seed the database with mock data. You can also add `yarn prisma:seed` to seed the database with mock data.
### 5. Auth Setup ### 5. Auth Setup
Right now the only way to authenticate yourself is to setup Google Sign-in in `server/.env` Right now the only way to authenticate yourself is to setup Google Sign-in in `server/.env`
@ -107,10 +107,10 @@ We will add an easier option soon.
On the frontend: On the frontend:
``` ```
cd front cd front
npm run start yarn start
``` ```
On the server side: On the server side:
``` ```
cd server cd server
npm run start yarn start
``` ```

13378
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

8061
docs/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ module.exports = {
tsconfigRootDir: __dirname, tsconfigRootDir: __dirname,
sourceType: 'module', sourceType: 'module',
}, },
plugins: ['@typescript-eslint/eslint-plugin', 'simple-import-sort', 'better-styled-components'], plugins: ['@typescript-eslint/eslint-plugin', 'simple-import-sort', 'twenty'],
extends: [ extends: [
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended', 'plugin:prettier/recommended',
@ -45,6 +45,7 @@ module.exports = {
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
'simple-import-sort/imports': 'error', 'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error', 'simple-import-sort/exports': 'error',
'better-styled-components/sort-declarations-alphabetically': 2 'twenty/sort-css-properties-alphabetically': 'error',
}, 'twenty/no-hardcoded-colors': 'error'
}
}; };

View File

@ -6,7 +6,7 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
In the project directory, you can run: In the project directory, you can run:
### `npm start` ### `yarn start`
Runs the app in the development mode.\ Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
@ -14,12 +14,12 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\ The page will reload if you make edits.\
You will also see any lint errors in the console. You will also see any lint errors in the console.
### `npm test` ### `yarn test`
Launches the test runner in the interactive watch mode.\ Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build` ### `yarn build`
Builds the app for production to the `build` folder.\ Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance. It correctly bundles React in production mode and optimizes the build for the best performance.
@ -29,7 +29,7 @@ Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject` ### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!** **Note: this is a one-way operation. Once you `eject`, you cant go back!**

39485
front/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@apollo/client": "^3.7.5", "@apollo/client": "^3.7.5",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.5", "@emotion/styled": "^11.10.5",
"@hello-pangea/dnd": "^16.2.0", "@hello-pangea/dnd": "^16.2.0",
@ -115,7 +116,6 @@
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"eslint-config-standard-with-typescript": "^23.0.0", "eslint-config-standard-with-typescript": "^23.0.0",
"eslint-plugin-better-styled-components": "^1.1.2",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.5.1", "eslint-plugin-n": "^15.5.1",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
@ -123,6 +123,7 @@
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.31.11",
"eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-storybook": "^0.6.11", "eslint-plugin-storybook": "^0.6.11",
"eslint-plugin-twenty": "file:../packages/eslint-plugin-twenty",
"http-server": "^14.1.1", "http-server": "^14.1.1",
"mock-apollo-client": "^1.2.1", "mock-apollo-client": "^1.2.1",
"msw": "^1.2.1", "msw": "^1.2.1",

View File

@ -2,7 +2,7 @@
/* tslint:disable */ /* tslint:disable */
/** /**
* Mock Service Worker (1.2.1). * Mock Service Worker (1.2.2).
* @see https://github.com/mswjs/msw * @see https://github.com/mswjs/msw
* - Please do NOT modify this file. * - Please do NOT modify this file.
* - Please do NOT serve this file on production. * - Please do NOT serve this file on production.

View File

@ -49,9 +49,11 @@ const StyledDate = styled.div`
const StyledTooltip = styled(Tooltip)` const StyledTooltip = styled(Tooltip)`
background-color: ${(props) => props.theme.primaryBackground}; background-color: ${(props) => props.theme.primaryBackground};
box-shadow: 0px 2px 4px 3px rgba(0, 0, 0, 0.04); box-shadow: 0px 2px 4px 3px
${(props) => props.theme.lightBackgroundTransparent};
box-shadow: 2px 4px 16px 6px rgba(0, 0, 0, 0.12); box-shadow: 2px 4px 16px 6px
${(props) => props.theme.lightBackgroundTransparent};
color: ${(props) => props.theme.text100}; color: ${(props) => props.theme.text100};

View File

@ -4,7 +4,7 @@ import { Command } from 'cmdk';
export const StyledDialog = styled(Command.Dialog)` export const StyledDialog = styled(Command.Dialog)`
background: ${(props) => props.theme.primaryBackground}; background: ${(props) => props.theme.primaryBackground};
border-radius: ${(props) => props.theme.borderRadius}; border-radius: ${(props) => props.theme.borderRadius};
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.09); box-shadow: ${(props) => props.theme.modalBoxShadow};
font-family: ${(props) => props.theme.fontFamily}; font-family: ${(props) => props.theme.fontFamily};
left: 50%; left: 50%;
max-width: 640px; max-width: 640px;
@ -45,7 +45,7 @@ export const StyledItem = styled(Command.Item)`
transition-property: none; transition-property: none;
user-select: none; user-select: none;
&:hover { &:hover {
background: ${(props) => props.theme.clickableElementBackgroundHover}; background: ${(props) => props.theme.lightBackgroundTransparent};
} }
&[data-selected='true'] { &[data-selected='true'] {
background: ${(props) => props.theme.secondaryBackground}; background: ${(props) => props.theme.secondaryBackground};

View File

@ -2,7 +2,7 @@ import styled from '@emotion/styled';
export const HoverableMenuItem = styled.div` export const HoverableMenuItem = styled.div`
align-items: center; align-items: center;
background: rgba(0, 0, 0, 0); background: ${(props) => props.theme.primaryBackground};
border-radius: 4px; border-radius: 4px;
box-sizing: border-box; box-sizing: border-box;
cursor: pointer; cursor: pointer;
@ -14,6 +14,6 @@ export const HoverableMenuItem = styled.div`
width: 100%; width: 100%;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.04); background: ${(props) => props.theme.lightBackgroundTransparent};
} }
`; `;

View File

@ -26,7 +26,7 @@ const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
background: ${(props) => props.theme.secondaryBackground}; background: ${(props) => props.theme.secondaryBackground};
border: 1px solid ${(props) => props.theme.primaryBorder}; border: 1px solid ${(props) => props.theme.primaryBorder};
border-radius: 8px; border-radius: 8px;
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.09); box-shadow: ${(props) => props.theme.modalBoxShadow};
left: -10px; left: -10px;
position: absolute; position: absolute;
top: 10px; top: 10px;

View File

@ -127,7 +127,7 @@ const StyledContainer = styled.div`
margin: 2px; margin: 2px;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.04); background: ${(props) => props.theme.lightBackgroundTransparent};
} }
&:first-of-type { &:first-of-type {
@ -172,7 +172,7 @@ const StyledContainer = styled.div`
border-radius: 4px; border-radius: 4px;
padding-top: 6px; padding-top: 6px;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.04); background: ${(props) => props.theme.lightBackgroundTransparent};
} }
} }
& .react-datepicker__navigation--previous { & .react-datepicker__navigation--previous {

View File

@ -90,7 +90,7 @@ const StyledDropdownItem = styled.li`
width: calc(160px - ${(props) => props.theme.spacing(4)}); width: calc(160px - ${(props) => props.theme.spacing(4)});
&:hover { &:hover {
background: rgba(0, 0, 0, 0.04); background: ${(props) => props.theme.lightBackgroundTransparent};
} }
`; `;
@ -112,7 +112,7 @@ const StyledDropdownTopOption = styled.li`
calc(${(props) => props.theme.spacing(2)}); calc(${(props) => props.theme.spacing(2)});
&:hover { &:hover {
background: rgba(0, 0, 0, 0.04); background: ${(props) => props.theme.lightBackgroundTransparent};
} }
user-select: none; user-select: none;
`; `;

View File

@ -22,7 +22,8 @@ type StyledItemProps = {
const StyledItem = styled.button<StyledItemProps>` const StyledItem = styled.button<StyledItemProps>`
align-items: center; align-items: center;
background: ${(props) => (props.active ? 'rgba(0, 0, 0, 0.04)' : 'inherit')}; background: ${(props) =>
props.active ? props.theme.lightBackgroundTransparent : 'inherit'};
border: none; border: none;
border-radius: 4px; border-radius: 4px;
color: ${(props) => { color: ${(props) => {
@ -47,7 +48,7 @@ const StyledItem = styled.button<StyledItemProps>`
padding-top: ${(props) => props.theme.spacing(1)}; padding-top: ${(props) => props.theme.spacing(1)};
pointer-events: ${(props) => (props.soon ? 'none' : 'auto')}; pointer-events: ${(props) => (props.soon ? 'none' : 'auto')};
:hover { :hover {
background: rgba(0, 0, 0, 0.04); background: ${(props) => props.theme.lightBackgroundTransparent};
color: ${(props) => (props.danger ? props.theme.red : props.theme.text100)}; color: ${(props) => (props.danger ? props.theme.red : props.theme.text100)};
} }
user-select: none; user-select: none;
@ -67,7 +68,7 @@ const StyledSoonPill = styled.div`
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 50px; border-radius: 50px;
background-color: rgba(0, 0, 0, 0.04); background-color: ${(props) => props.theme.lightBackgroundTransparent};
font-size: ${(props) => props.theme.fontSizeExtraSmall}; font-size: ${(props) => props.theme.fontSizeExtraSmall};
padding: ${(props) => props.theme.spacing(1)} padding: ${(props) => props.theme.spacing(1)}
${(props) => props.theme.spacing(2)} ${(props) => props.theme.spacing(1)} ${(props) => props.theme.spacing(2)} ${(props) => props.theme.spacing(1)}

View File

@ -20,7 +20,7 @@ const StyledButton = styled.button`
width: 24px; width: 24px;
&:hover { &:hover {
background: ${(props) => props.theme.clickableElementBackgroundHover}; background: ${(props) => props.theme.lightBackgroundTransparent};
} }
svg { svg {
color: ${(props) => props.theme.text40}; color: ${(props) => props.theme.text40};

View File

@ -48,12 +48,15 @@ const lightThemeSpecific = {
primaryBackgroundTransparent: 'rgba(255, 255, 255, 0.8)', primaryBackgroundTransparent: 'rgba(255, 255, 255, 0.8)',
secondaryBackgroundTransparent: 'rgba(252, 252, 252, 0.8)', secondaryBackgroundTransparent: 'rgba(252, 252, 252, 0.8)',
strongBackgroundTransparent: 'rgba(0, 0, 0, 0.16)',
mediumBackgroundTransparent: 'rgba(0, 0, 0, 0.08)',
lightBackgroundTransparent: 'rgba(0, 0, 0, 0.04)',
lighterBackgroundTransparent: 'rgba(0, 0, 0, 0.02)',
primaryBorder: 'rgba(0, 0, 0, 0.08)', primaryBorder: 'rgba(0, 0, 0, 0.08)',
lightBorder: '#f5f5f5', lightBorder: '#f5f5f5',
mediumBorder: '#ebebeb', mediumBorder: '#ebebeb',
clickableElementBackgroundHover: 'rgba(0, 0, 0, 0.04)',
clickableElementBackgroundTransition: 'background 0.1s ease', clickableElementBackgroundTransition: 'background 0.1s ease',
text100: '#000', text100: '#000',
@ -93,8 +96,11 @@ const darkThemeSpecific: typeof lightThemeSpecific = {
primaryBackgroundTransparent: 'rgba(20, 20, 20, 0.8)', primaryBackgroundTransparent: 'rgba(20, 20, 20, 0.8)',
secondaryBackgroundTransparent: 'rgba(23, 23, 23, 0.8)', secondaryBackgroundTransparent: 'rgba(23, 23, 23, 0.8)',
strongBackgroundTransparent: 'rgba(255, 255, 255, 0.09)',
mediumBackgroundTransparent: 'rgba(255, 255, 255, 0.06)',
lightBackgroundTransparent: 'rgba(255, 255, 255, 0.03)',
lighterBackgroundTransparent: 'rgba(255, 255, 255, 0.02)',
clickableElementBackgroundHover: 'rgba(0, 0, 0, 0.04)',
clickableElementBackgroundTransition: 'background 0.1s ease', clickableElementBackgroundTransition: 'background 0.1s ease',
primaryBorder: 'rgba(255, 255, 255, 0.08)', primaryBorder: 'rgba(255, 255, 255, 0.08)',
@ -148,7 +154,7 @@ export const hoverBackground = (props: any) =>
css` css`
transition: background 0.1s ease; transition: background 0.1s ease;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.04); background: ${props.theme.lightBackgroundTransparent};
} }
`; `;

17119
front/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,25 +15,25 @@ sh:
@docker-compose exec twenty-dev sh @docker-compose exec twenty-dev sh
front-start: front-start:
@docker-compose exec twenty-dev sh -c "cd /app/front && npm run start" @docker-compose exec twenty-dev sh -c "cd /app/front && yarn start"
front-test: front-test:
@docker-compose exec twenty-dev sh -c "cd /app/front && npm run test" @docker-compose exec twenty-dev sh -c "cd /app/front && yarn test"
front-graphql-generate: front-graphql-generate:
@docker-compose exec twenty-dev sh -c "cd /app/server && npm run graphql:generate" @docker-compose exec twenty-dev sh -c "cd /app/server && yarn graphql:generate"
front-storybook: front-storybook:
@docker-compose exec twenty-dev sh -c "cd /app/front && npm run storybook" @docker-compose exec twenty-dev sh -c "cd /app/front && yarn storybook"
server-start: server-start:
@docker-compose exec twenty-dev sh -c "cd /app/server && npm run start:dev" @docker-compose exec twenty-dev sh -c "cd /app/server && yarn start:dev"
server-prisma-generate: server-prisma-generate:
@docker-compose exec twenty-dev sh -c "cd /app/server && npm run prisma:generate" @docker-compose exec twenty-dev sh -c "cd /app/server && yarn prisma:generate"
server-prisma-migrate: server-prisma-migrate:
@docker-compose exec twenty-dev sh -c "cd /app/server && npm run prisma:migrate" @docker-compose exec twenty-dev sh -c "cd /app/server && yarn prisma:migrate"
server-prisma-seed: server-prisma-seed:
@docker-compose exec twenty-dev sh -c "cd /app/server && npm run prisma:seed" @docker-compose exec twenty-dev sh -c "cd /app/server && yarn prisma:seed"

6
infra/dev/package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "dev",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@ -1,17 +1,19 @@
FROM node:18.16.0 as front FROM node:18.16-bullseye as front
COPY /../../packages /app/packages
WORKDIR /app/front WORKDIR /app/front
COPY ../../front/package.json . COPY ../../front/package.json .
COPY ../../front/package-lock.json . COPY ../../front/yarn.lock .
RUN npm install RUN yarn install
RUN npx playwright install-deps RUN npx playwright install-deps
WORKDIR /app/server WORKDIR /app/server
COPY ../../server/package.json . COPY ../../server/package.json .
COPY ../../server/package-lock.json . COPY ../../server/yarn.lock .
RUN npm install RUN yarn install
WORKDIR /app WORKDIR /app

View File

@ -1,10 +1,10 @@
FROM node:18.16.0-alpine as docs FROM node:18.16-bullseye as docs
WORKDIR /app/docs WORKDIR /app/docs
COPY ../../docs/package.json . COPY ../../docs/package.json .
COPY ../../docs/package-lock.json . COPY ../../docs/yarn.lock .
RUN npm install RUN yarn
COPY ../../docs . COPY ../../docs .

View File

@ -3,12 +3,12 @@ FROM node:18.16.0-alpine as docs
WORKDIR /app/docs WORKDIR /app/docs
COPY ./docs/package.json . COPY ./docs/package.json .
COPY ./docs/package-lock.json . COPY ./docs/yarn.lock .
RUN npm install RUN yarn install
COPY ./docs . COPY ./docs .
RUN npm run build RUN npm run build
RUN npm install -g serve RUN yarn install -g serve
CMD ["serve", "-s", "./build"] CMD ["serve", "-s", "./build"]

View File

@ -6,9 +6,9 @@ ARG REACT_APP_AUTH_URL
WORKDIR /app/front WORKDIR /app/front
COPY ./front . COPY ./front .
RUN npm install RUN yarn install --install-links
RUN npm run build RUN yarn build
RUN npm install -g serve RUN yarn install -g serve
CMD ["serve", "-s", "build"] CMD ["serve", "-s", "build"]

View File

@ -2,12 +2,12 @@ FROM node:18.16.0-alpine as server
WORKDIR /app/server WORKDIR /app/server
COPY ./server/package.json ./ COPY ./server/package.json ./
COPY ./server/package-lock.json ./ COPY ./server/yarn.lock ./
RUN npm install RUN yarn install
COPY ./server . COPY ./server .
RUN npx prisma generate RUN npx prisma generate
RUN npm run build RUN yarn build
CMD ["node", "dist/main"] CMD ["node", "dist/main"]

View File

@ -0,0 +1,10 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const noHardcodedColors = require('./rules/no-hardcoded-colors');
const cssAlphabetically = require('./rules/sort-css-properties-alphabetically');
module.exports = {
rules: {
'no-hardcoded-colors': noHardcodedColors,
'sort-css-properties-alphabetically': cssAlphabetically,
},
};

View File

@ -0,0 +1,8 @@
{
"name": "eslint-plugin-twenty",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"postcss": "^8.4.24"
}
}

View File

@ -0,0 +1,24 @@
module.exports = {
create: function (context) {
return {
TaggedTemplateExpression(node) {
if (context.getFilename().endsWith('themes.ts')) {
return;
}
node.quasi.quasis.forEach((quasi) => {
const colorRegex =
/(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(,\s*\d+\.?\d*)?\))|(?:#[0-9a-fA-F]{6})/i;
if (colorRegex.test(quasi.value.raw)) {
context.report({
node,
message:
'Do not use hardcoded RGBA or Hex colors. Please use a color from the theme file.',
});
}
});
},
};
},
};

View File

@ -0,0 +1,208 @@
"use strict";
const postcss = require("postcss");
function isStyledTagname(node) {
return (
(node.tag.type === "Identifier" && node.tag.name === "css") ||
(node.tag.type === "MemberExpression" &&
node.tag.object.name === "styled") ||
(node.tag.type === "CallExpression" &&
(node.tag.callee.name === "styled" ||
(node.tag.callee.object &&
((node.tag.callee.object.callee &&
node.tag.callee.object.callee.name === "styled") ||
(node.tag.callee.object.object &&
node.tag.callee.object.object.name === "styled")))))
);
}
/**
* An atomic rule is a rule without nested rules.
*/
function isValidAtomicRule(rule) {
const decls = rule.nodes.filter(node => node.type === "decl");
if (decls.length < 0) {
return { isValid: true };
}
for (let i = 1; i < decls.length; i++) {
const current = decls[i].prop;
const prev = decls[i - 1].prop;
if (current < prev) {
const loc = {
start: {
line: decls[i - 1].source.start.line,
column: decls[i - 1].source.start.column - 1
},
end: {
line: decls[i].source.end.line,
column: decls[i].source.end.column - 1
}
};
return { isValid: false, loc };
}
}
return { isValid: true };
}
function isValidRule(rule) {
// check each rule recursively
const { isValid, loc } = rule.nodes.reduce(
(map, node) => {
return node.type === "rule" ? isValidRule(node) : map;
},
{ isValid: true }
);
// if there is any invalid rule, return result
if (!isValid) {
return { isValid, loc };
}
// check declarations
return isValidAtomicRule(rule);
}
function getNodeStyles(node) {
const [firstQuasi, ...quasis] = node.quasi.quasis;
// remove line break added to the first quasi
const lineBreakCount = node.quasi.loc.start.line - 1;
let styles = `${"\n".repeat(lineBreakCount)}${" ".repeat(
node.quasi.loc.start.column + 1
)}${firstQuasi.value.raw}`;
// replace expression by spaces and line breaks
quasis.forEach(({ value, loc }, idx) => {
const prevLoc = idx === 0 ? firstQuasi.loc : quasis[idx - 1].loc;
const lineBreaksCount = loc.start.line - prevLoc.end.line;
const spacesCount =
loc.start.line === prevLoc.end.line
? loc.start.column - prevLoc.end.column + 2
: loc.start.column + 1;
styles = `${styles}${" "}${"\n".repeat(lineBreaksCount)}${" ".repeat(
spacesCount
)}${value.raw}`;
});
return styles;
}
function create(context) {
return {
TaggedTemplateExpression(node) {
if (isStyledTagname(node)) {
try {
const root = postcss.parse(getNodeStyles(node));
const { isValid, loc } = isValidRule(root);
if (!isValid) {
return context.report({
node,
messageId: "sort-css-properties-alphabetically",
loc,
fix: fixer =>
fix({
rule: root,
fixer,
src: context.getSourceCode()
})
});
}
} catch (e) {
return true;
}
}
}
};
}
function fix({ rule, fixer, src }) {
let fixings = [];
// concat fixings recursively
rule.nodes.forEach(node => {
if (node.type === "rule") {
fixings = [...fixings, ...fix({ rule: node, fixer, src })];
}
});
const declarations = rule.nodes.filter(node => node.type === "decl");
const sortedDeclarations = sortDeclarations(declarations);
declarations.forEach((decl, idx) => {
if (!areSameDeclarations(decl, sortedDeclarations[idx])) {
try {
const range = getDeclRange({ decl, src });
const sortedDeclText = getDeclText({
decl: sortedDeclarations[idx],
src
});
fixings.push(fixer.removeRange([range.startIdx, range.endIdx + 1]));
fixings.push(
fixer.insertTextAfterRange(
[range.startIdx, range.startIdx],
sortedDeclText
)
);
} catch (e) {
console.log(e);
}
}
});
return fixings;
}
function areSameDeclarations(a, b) {
return (
a.source.start.line === b.source.start.line &&
a.source.start.column === b.source.start.column
);
}
function getDeclRange({ decl, src }) {
const loc = {
start: {
line: decl.source.start.line,
column: decl.source.start.column - 1
},
end: {
line: decl.source.end.line,
column: decl.source.end.column - 1
}
};
const startIdx = src.getIndexFromLoc(loc.start);
const endIdx = src.getIndexFromLoc(loc.end);
return { startIdx, endIdx };
}
function getDeclText({ decl, src }) {
const { startIdx, endIdx } = getDeclRange({ decl, src });
return src.getText().substring(startIdx, endIdx + 1);
}
function sortDeclarations(declarations) {
return declarations
.slice()
.sort((declA, declB) => (declA.prop > declB.prop ? 1 : -1));
}
module.exports = {
meta: {
docs: {
description: "Styles are sorted alphabetically.",
category: "Fill me in",
recommended: false
},
messages: {
"sort-css-properties-alphabetically":
"Declarations should be sorted alphabetically."
},
fixable: "code"
},
create
};

View File

@ -0,0 +1,27 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
nanoid@^3.3.6:
version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@^8.4.24:
version "8.4.24"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df"
integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==

View File

@ -36,26 +36,26 @@ $ npm install
```bash ```bash
# development # development
$ npm run start $ npm start
# watch mode # watch mode
$ npm run start:dev $ npm start:dev
# production mode # production mode
$ npm run start:prod $ npm start:prod
``` ```
## Test ## Test
```bash ```bash
# unit tests # unit tests
$ npm run test $ npm test
# e2e tests # e2e tests
$ npm run test:e2e $ npm test:e2e
# test coverage # test coverage
$ npm run test:cov $ npm test:cov
``` ```
## Support ## Support

9667
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -24,10 +24,12 @@
"prisma:seed": "npx prisma db seed" "prisma:seed": "npx prisma db seed"
}, },
"dependencies": { "dependencies": {
"@apollo/server": "^4.7.3",
"@nestjs/apollo": "^11.0.5", "@nestjs/apollo": "^11.0.5",
"@nestjs/common": "^9.0.0", "@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.3.2", "@nestjs/config": "^2.3.2",
"@nestjs/core": "^9.0.0", "@nestjs/core": "^9.0.0",
"@nestjs/graphql": "^11.0.6",
"@nestjs/jwt": "^10.0.3", "@nestjs/jwt": "^10.0.3",
"@nestjs/passport": "^9.0.3", "@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^9.0.0",

5933
server/yarn.lock Normal file

File diff suppressed because it is too large Load Diff