Reorganize frontend and install Craco to alias modules (#190)

This commit is contained in:
Charles Bochet
2023-06-04 11:23:09 +02:00
committed by GitHub
parent bbc80cd543
commit 7b858fd7c9
149 changed files with 3441 additions and 1158 deletions

View File

@ -5,7 +5,7 @@ module.exports = {
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
plugins: ['@typescript-eslint/eslint-plugin', 'simple-import-sort'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
@ -17,12 +17,33 @@ module.exports = {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js', 'codegen.js', '**/generated/*'],
overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
['^react', '^@?\\w'],
['^(@|~)(/.*|$)'],
['^\\u0000'],
['^\\.\\.(?!/?$)', '^\\.\\./?$'],
['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
['^.+\\.?(css)$']
]
}
]
}
},
],
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'
},
};

View File

@ -1,3 +1,5 @@
const path = require('path');
module.exports = {
webpackFinal: config => {
config.module.rules.push({
@ -19,6 +21,11 @@ module.exports = {
type: 'javascript/auto'
});
config.resolve.extensions.push('.mjs');
config.resolve.alias = {
...config.resolve.alias,
'~': path.resolve(__dirname, "../src"),
'@': path.resolve(__dirname, "../src/modules"),
};
return config;
},
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],

20
front/craco.config.js Normal file
View File

@ -0,0 +1,20 @@
const path = require("path");
module.exports = {
webpack: {
alias: {
'~': path.resolve(__dirname, 'src'),
'@': path.resolve(__dirname, 'src/modules'),
'@testing': path.resolve(__dirname, 'src/testing'),
}
},
jest: {
configure: {
"moduleNameMapper": {
'~/(.+)': "<rootDir>/src/$1",
'@/(.+)': "<rootDir>/src/modules/$1",
'@testing/(.+)': "<rootDir>/src/testing/$1",
}
}
},
};

5
front/jest.config.js Normal file
View File

@ -0,0 +1,5 @@
const { createJestConfig } = require("@craco/craco");
const cracoConfig = require("./craco.config.js");
const jestConfig = createJestConfig(cracoConfig);
module.exports = jestConfig;

3478
front/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -27,10 +27,9 @@
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "PORT=3001 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "PORT=3001 craco start",
"build": "craco build",
"test": "craco test",
"lint": "eslint src --max-warnings=0",
"storybook": "storybook dev -p 6006 -s ../public",
"test-storybook": "test-storybook",
@ -77,6 +76,7 @@
]
},
"devDependencies": {
"@craco/craco": "^7.1.0",
"@graphql-codegen/cli": "^3.3.1",
"@graphql-codegen/typescript": "^3.0.4",
"@graphql-codegen/typescript-operations": "^3.0.4",
@ -114,6 +114,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-storybook": "^0.6.11",
"http-server": "^14.1.1",
"mock-apollo-client": "^1.2.1",
@ -123,6 +124,7 @@
"prop-types": "^15.8.1",
"react-scripts": "5.0.1",
"storybook": "^7.0.2",
"ts-jest": "^29.1.0",
"typescript": "^4.9.3",
"webpack": "^5.75.0"
},

View File

@ -1,17 +1,18 @@
import React, { useEffect, useState } from 'react';
import People from './pages/people/People';
import Companies from './pages/companies/Companies';
import AuthCallback from './pages/auth/Callback';
import Login from './pages/auth/Login';
import AppLayout from './layout/AppLayout';
import { Routes, Route, Navigate } from 'react-router-dom';
import RequireAuth from './components/auth/RequireAuth';
import Opportunities from './pages/opportunities/Opportunities';
import { User, mapToUser } from './interfaces/entities/user.interface';
import { useGetCurrentUserQuery } from './services/api/users';
import { getUserIdFromToken } from './services/auth/AuthService';
import { Navigate, Route, Routes } from 'react-router-dom';
function App() {
import { RequireAuth } from './modules/auth/components/RequireAuth';
import { getUserIdFromToken } from './modules/auth/services/AuthService';
import { AppLayout } from './modules/ui/layout/AppLayout';
import { mapToUser, User } from './modules/users/interfaces/user.interface';
import { useGetCurrentUserQuery } from './modules/users/services';
import AuthCallback from './pages/auth/Callback';
import { Login } from './pages/auth/Login';
import { Companies } from './pages/companies/Companies';
import { Opportunities } from './pages/opportunities/Opportunities';
import { People } from './pages/people/People';
export function App() {
const [user, setUser] = useState<User | undefined>(undefined);
const userIdFromToken = getUserIdFromToken();
@ -68,5 +69,3 @@ function App() {
</>
);
}
export default App;

View File

@ -1,15 +1,15 @@
import type { Meta, StoryObj } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { ThemeProvider } from '@emotion/react';
import { MemoryRouter } from 'react-router-dom';
import { ApolloProvider } from '@apollo/client';
import { ThemeProvider } from '@emotion/react';
import type { Meta, StoryObj } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import App from '../App';
import { FullHeightStorybookLayout } from '../testing/FullHeightStorybookLayout';
import { lightTheme } from '../layout/styles/themes';
import { mockedClient } from '../testing/mockedClient';
import { graphqlMocks } from '../testing/graphqlMocks';
import { mockedUserJWT } from '../testing/mock-data/jwt';
import { lightTheme } from '@/ui/layout/styles/themes';
import { App } from '~/App';
import { FullHeightStorybookLayout } from '~/testing/FullHeightStorybookLayout';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedUserJWT } from '~/testing/mock-data/jwt';
import { mockedClient } from '~/testing/mockedClient';
const meta: Meta<typeof App> = {
title: 'App/App',

View File

@ -1,14 +1,15 @@
import {
ApolloClient,
InMemoryCache,
Observable,
createHttpLink,
from,
InMemoryCache,
Observable,
} from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { RestLink } from 'apollo-link-rest';
import { onError } from '@apollo/client/link/error';
import { refreshAccessToken } from './services/auth/AuthService';
import { RestLink } from 'apollo-link-rest';
import { refreshAccessToken } from './modules/auth/services/AuthService';
const apiLink = createHttpLink({
uri: `${process.env.REACT_APP_API_URL}`,

View File

@ -1,14 +1,17 @@
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import { ApolloProvider } from '@apollo/client';
import '@emotion/react';
import { ThemeType } from './layout/styles/themes';
import { apiClient } from './apollo';
import { RecoilRoot } from 'recoil';
import '@emotion/react';
import { ThemeType } from './modules/ui/layout/styles/themes';
import { apiClient } from './apollo';
import { App } from './App';
import './index.css';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);

View File

@ -1,8 +1,13 @@
import { useNavigate } from 'react-router-dom';
import { useEffect } from 'react';
import { hasAccessToken } from '../../services/auth/AuthService';
import { useNavigate } from 'react-router-dom';
function RequireAuth({ children }: { children: JSX.Element }): JSX.Element {
import { hasAccessToken } from '../services/AuthService';
export function RequireAuth({
children,
}: {
children: JSX.Element;
}): JSX.Element {
const navigate = useNavigate();
useEffect(() => {
@ -13,5 +18,3 @@ function RequireAuth({ children }: { children: JSX.Element }): JSX.Element {
return children;
}
export default RequireAuth;

View File

@ -1,9 +1,10 @@
import { waitFor } from '@testing-library/react';
import {
getUserIdFromToken,
hasAccessToken,
hasRefreshToken,
refreshAccessToken,
getUserIdFromToken,
} from '../AuthService';
const mockFetch = async (

View File

@ -1,4 +1,5 @@
import styled from '@emotion/styled';
import { CommentChip, CommentChipProps } from './CommentChip';
const StyledCellWrapper = styled.div`

View File

@ -1,5 +1,6 @@
import styled from '@emotion/styled';
import { IconComment } from '../icons';
import { IconComment } from '@/ui/icons';
export type CommentChipProps = {
count: number;

View File

@ -1,10 +1,11 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import { HiArrowSmRight } from 'react-icons/hi';
import TextareaAutosize from 'react-textarea-autosize';
import { IconButton } from '../buttons/IconButton';
import { useHotkeys } from 'react-hotkeys-hook';
import { HotkeysEvent } from 'react-hotkeys-hook/dist/types';
import { HiArrowSmRight } from 'react-icons/hi';
import TextareaAutosize from 'react-textarea-autosize';
import styled from '@emotion/styled';
import { IconButton } from '@/ui/components/buttons/IconButton';
type OwnProps = {
onSend?: (text: string) => void;

View File

@ -1,9 +1,12 @@
import { useRecoilState } from 'recoil';
import { RightDrawerBody } from '../../layout/right-drawer/RightDrawerBody';
import { RightDrawerPage } from '../../layout/right-drawer/RightDrawerPage';
import { RightDrawerTopBar } from '../../layout/right-drawer/RightDrawerTopBar';
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
import { commentableEntityArrayState } from '../../states/commentableEntityArrayState';
import { CommentTextInput } from './CommentTextInput';
import { commentableEntityArrayState } from '../../modules/comments/states/commentableEntityArrayState';
export function RightDrawerComments() {
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);

View File

@ -1,8 +1,10 @@
import type { Meta, StoryObj } from '@storybook/react';
import { getRenderWrapperForComponent } from '../../../testing/renderWrappers';
import { CellCommentChip } from '../CellCommentChip';
import styled from '@emotion/styled';
import { CellBaseContainer } from '../../editable-cell/CellBaseContainer';
import type { Meta, StoryObj } from '@storybook/react';
import { CellBaseContainer } from '@/ui/components/editable-cell/CellBaseContainer';
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
import { CellCommentChip } from '../CellCommentChip';
import { CommentChip } from '../CommentChip';
const meta: Meta<typeof CellCommentChip> = {

View File

@ -1,7 +1,9 @@
import type { Meta, StoryObj } from '@storybook/react';
import { graphqlMocks } from '../../../testing/graphqlMocks';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
import { CommentTextInput } from '../CommentTextInput';
import { getRenderWrapperForComponent } from '../../../testing/renderWrappers';
const meta: Meta<typeof CommentTextInput> = {
title: 'Components/CommentTextInput',

View File

@ -1,7 +1,8 @@
import { useRecoilState } from 'recoil';
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
import { CommentableEntity } from '../types/CommentableEntity';
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
import { CommentableEntity } from '../types/CommentableEntity';
export function useOpenCommentRightDrawer() {
const openRightDrawer = useOpenRightDrawer();

View File

@ -1,4 +1,5 @@
import { atom } from 'recoil';
import { CommentableEntity } from '../types/CommentableEntity';
export const commentableEntityArrayState = atom<CommentableEntity[]>({

View File

@ -1,4 +1,4 @@
import { CommentableType } from '../../../generated/graphql';
import { CommentableType } from '~/generated/graphql';
export type CommentableEntity = {
type: keyof typeof CommentableType;

View File

@ -1,9 +1,11 @@
import { Company } from '../../interfaces/entities/company.interface';
import { useOpenCommentRightDrawer } from '../../modules/comments/hooks/useOpenCommentRightDrawer';
import { updateCompany } from '../../services/api/companies';
import { getLogoUrlFromDomainName } from '../../services/utils';
import CompanyChip from '../chips/CompanyChip';
import EditableChip from '../editable-cell/EditableChip';
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
import EditableChip from '@/ui/components/editable-cell/EditableChip';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import { Company } from '../interfaces/company.interface';
import { updateCompany } from '../services';
import CompanyChip from './CompanyChip';
type OwnProps = {
company: Company;

View File

@ -1,9 +1,9 @@
import {
mapToGqlCompany,
mapToCompany,
Company,
GraphqlMutationCompany,
GraphqlQueryCompany,
mapToCompany,
mapToGqlCompany,
} from '../company.interface';
describe('Company mappers', () => {

View File

@ -1,6 +1,12 @@
import { Pipe } from 'stream';
import { GraphqlQueryUser, User, mapToUser } from './user.interface';
import { GraphqlQueryPipe } from './pipe.interface';
import {
GraphqlQueryPipeline,
Pipeline,
} from '../../pipelines/interfaces/pipeline.interface';
import {
GraphqlQueryUser,
mapToUser,
User,
} from '../../users/interfaces/user.interface';
export type Company = {
__typename: 'companies';
@ -12,7 +18,7 @@ export type Company = {
createdAt?: Date;
pipes?: Pipe[];
pipes?: Pipeline[];
accountOwner?: User | null;
};
@ -26,7 +32,7 @@ export type GraphqlQueryCompany = {
createdAt?: string;
accountOwner?: GraphqlQueryUser | null;
pipes?: GraphqlQueryPipe[] | null;
pipes?: GraphqlQueryPipeline[] | null;
__typename: string;
};

View File

@ -1,4 +1,5 @@
import { reduceSortsToOrderBy } from '../../../../components/table/table-header/helpers';
import { reduceSortsToOrderBy } from '@/filters-and-sorts/helpers';
import { CompaniesSelectedSortType } from '../select';
describe('reduceSortsToOrderBy', () => {

View File

@ -1,11 +1,13 @@
import { QueryResult, gql, useQuery } from '@apollo/client';
import { gql, QueryResult, useQuery } from '@apollo/client';
import { SelectedSortType } from '@/filters-and-sorts/interfaces/sorts/interface';
import {
SortOrder as Order_By,
CompanyOrderByWithRelationInput as Companies_Order_By,
CompanyWhereInput as Companies_Bool_Exp,
} from '../../../generated/graphql';
import { GraphqlQueryCompany } from '../../../interfaces/entities/company.interface';
import { SelectedSortType } from '../../../interfaces/sorts/interface';
SortOrder as Order_By,
} from '~/generated/graphql';
import { GraphqlQueryCompany } from '../interfaces/company.interface';
export type CompaniesSelectedSortType = SelectedSortType<Companies_Order_By>;

View File

@ -1,9 +1,8 @@
import { FetchResult, gql } from '@apollo/client';
import {
Company,
mapToGqlCompany,
} from '../../../interfaces/entities/company.interface';
import { apiClient } from '../../../apollo';
import { apiClient } from '~/apollo';
import { Company, mapToGqlCompany } from '../interfaces/company.interface';
export const UPDATE_COMPANY = gql`
mutation UpdateCompany(

View File

@ -1,11 +1,13 @@
import { SortOrder as Order_By } from '../../../generated/graphql';
import { BoolExpType } from '../../../interfaces/entities/generic.interface';
import { SortOrder as Order_By } from '~/generated/graphql';
import { BoolExpType } from '../utils/interfaces/generic.interface';
import {
FilterableFieldsType,
FilterWhereType,
SelectedFilterType,
} from '../../../interfaces/filters/interface';
import { SelectedSortType } from '../../../interfaces/sorts/interface';
} from './interfaces/filters/interface';
import { SelectedSortType } from './interfaces/sorts/interface';
export const reduceFiltersToWhere = <
ValueType extends FilterableFieldsType,

View File

@ -1,10 +1,11 @@
import { ReactNode } from 'react';
import { SearchConfigType } from '../search/interface';
import { SearchConfigType } from '@/search/interfaces/interface';
import {
AnyEntity,
BoolExpType,
UnknownType,
} from '../entities/generic.interface';
} from '@/utils/interfaces/generic.interface';
export type FilterableFieldsType = AnyEntity;
export type FilterWhereRelationType = AnyEntity;

View File

@ -1,5 +1,6 @@
import { ReactNode } from 'react';
import { SortOrder as Order_By } from '../../generated/graphql';
import { SortOrder as Order_By } from '~/generated/graphql';
export type SortType<OrderByTemplate> =
| {

View File

@ -1,9 +1,11 @@
import { useState } from 'react';
import PersonChip from '../chips/PersonChip';
import { EditableDoubleText } from '../editable-cell/EditableDoubleText';
import { CellCommentChip } from '../comments/CellCommentChip';
import styled from '@emotion/styled';
import { CellCommentChip } from '@/comments/components/comments/CellCommentChip';
import { EditableDoubleText } from '@/ui/components/editable-cell/EditableDoubleText';
import { PersonChip } from './PersonChip';
type OwnProps = {
firstname: string;
lastname: string;

View File

@ -1,25 +1,26 @@
import { useState } from 'react';
import { v4 } from 'uuid';
import CompanyChip, {
CompanyChipPropsType,
} from '@/companies/components/CompanyChip';
import {
Company,
mapToCompany,
} from '@/companies/interfaces/company.interface';
import { SearchConfigType } from '@/search/interfaces/interface';
import { SEARCH_COMPANY_QUERY } from '@/search/services/search';
import { EditableRelation } from '@/ui/components/editable-cell/EditableRelation';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import {
QueryMode,
useInsertCompanyMutation,
useUpdatePeopleMutation,
} from '../../generated/graphql';
import {
Person,
mapToGqlPerson,
} from '../../interfaces/entities/person.interface';
} from '~/generated/graphql';
import { mapToGqlPerson, Person } from '../interfaces/person.interface';
import {
Company,
mapToCompany,
} from '../../interfaces/entities/company.interface';
import CompanyChip, { CompanyChipPropsType } from '../chips/CompanyChip';
import EditableRelation from '../editable-cell/EditableRelation';
import { SEARCH_COMPANY_QUERY } from '../../services/api/search/search';
import { SearchConfigType } from '../../interfaces/search/interface';
import { useState } from 'react';
import { PeopleCompanyCreateCell } from './PeopleCompanyCreateCell';
import { v4 } from 'uuid';
import { getLogoUrlFromDomainName } from '../../services/utils';
export type OwnProps = {
people: Person;

View File

@ -1,9 +1,10 @@
import { useRef, useState } from 'react';
import { DoubleTextInput } from '../inputs/DoubleTextInput';
import { useListenClickOutsideArrayOfRef } from '../../modules/ui/common/hooks/useListenClickOutsideArrayOfRef';
import { useHotkeys } from 'react-hotkeys-hook';
import { CellBaseContainer } from '../editable-cell/CellBaseContainer';
import { CellEditModeContainer } from '../editable-cell/CellEditModeContainer';
import { CellBaseContainer } from '@/ui/components/editable-cell/CellBaseContainer';
import { CellEditModeContainer } from '@/ui/components/editable-cell/CellEditModeContainer';
import { DoubleTextInput } from '@/ui/components/inputs/DoubleTextInput';
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
type OwnProps = {
initialCompanyName: string;

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import styled from '@emotion/styled';
import PersonPlaceholder from './person-placeholder.png';
export type PersonChipPropsType = {
@ -31,7 +32,7 @@ const StyledContainer = styled.span`
}
`;
function PersonChip({ name, picture }: PersonChipPropsType) {
export function PersonChip({ name, picture }: PersonChipPropsType) {
return (
<StyledContainer data-testid="person-chip">
<img
@ -43,5 +44,3 @@ function PersonChip({ name, picture }: PersonChipPropsType) {
</StyledContainer>
);
}
export default PersonChip;

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,9 +1,9 @@
import {
GraphqlMutationPerson,
GraphqlQueryPerson,
mapToGqlPerson,
mapToPerson,
Person,
GraphqlMutationPerson,
GraphqlQueryPerson,
} from '../person.interface';
describe('Person mappers', () => {

View File

@ -2,8 +2,8 @@ import {
Company,
GraphqlQueryCompany,
mapToCompany,
} from './company.interface';
import { Pipe } from './pipe.interface';
} from '@/companies/interfaces/company.interface';
import { Pipeline } from '@/pipelines/interfaces/pipeline.interface';
export type Person = {
__typename: 'people';
@ -18,7 +18,7 @@ export type Person = {
createdAt?: Date;
company?: Company | null;
pipes?: Pipe[] | null;
pipes?: Pipeline[] | null;
};
export type GraphqlQueryPerson = {

View File

@ -1,4 +1,5 @@
import { reduceSortsToOrderBy } from '../../../../components/table/table-header/helpers';
import { reduceSortsToOrderBy } from '@/filters-and-sorts/helpers';
import { PeopleSelectedSortType } from '../select';
describe('reduceSortsToOrderBy', () => {

View File

@ -1,12 +1,12 @@
import {
GraphqlMutationPerson,
GraphqlQueryPerson,
} from '../../../../interfaces/entities/person.interface';
} from '../../interfaces/person.interface';
import { updatePerson } from '../update';
jest.mock('../../../../apollo', () => {
jest.mock('~/apollo', () => {
const personInterface = jest.requireActual(
'../../../../interfaces/entities/person.interface',
'@/people/interfaces/person.interface',
);
return {
apiClient: {

View File

@ -1,11 +1,13 @@
import { QueryResult, gql, useQuery } from '@apollo/client';
import { GraphqlQueryPerson } from '../../../interfaces/entities/person.interface';
import { gql, QueryResult, useQuery } from '@apollo/client';
import { SelectedSortType } from '@/filters-and-sorts/interfaces/sorts/interface';
import {
PersonWhereInput as People_Bool_Exp,
PersonOrderByWithRelationInput as People_Order_By,
PersonWhereInput as People_Bool_Exp,
SortOrder,
} from '../../../generated/graphql';
import { SelectedSortType } from '../../../interfaces/sorts/interface';
} from '~/generated/graphql';
import { GraphqlQueryPerson } from '../interfaces/person.interface';
export type PeopleSelectedSortType = SelectedSortType<People_Order_By>;

View File

@ -1,9 +1,7 @@
import { FetchResult, gql } from '@apollo/client';
import {
Person,
mapToGqlPerson,
} from '../../../interfaces/entities/person.interface';
import { apiClient } from '../../../apollo';
import { mapToGqlPerson, Person } from '../interfaces/person.interface';
export const UPDATE_PERSON = gql`
mutation UpdatePeople(

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import styled from '@emotion/styled';
import { Pipe } from '../../interfaces/entities/pipe.interface';
import { Pipeline } from '../interfaces/pipeline.interface';
type OwnProps = {
opportunity: Pipe;
opportunity: Pipeline;
};
const StyledContainer = styled.span`
@ -20,7 +21,7 @@ const StyledContainer = styled.span`
}
`;
function PipeChip({ opportunity }: OwnProps) {
function PipelineChip({ opportunity }: OwnProps) {
return (
<StyledContainer data-testid="company-chip" key={opportunity.id}>
{opportunity.icon && <span>{opportunity.icon}</span>}
@ -29,4 +30,4 @@ function PipeChip({ opportunity }: OwnProps) {
);
}
export default PipeChip;
export default PipelineChip;

View File

@ -1,10 +1,10 @@
export interface Pipe {
export interface Pipeline {
id: string;
name?: string;
icon?: string | null;
}
export interface GraphqlQueryPipe {
export interface GraphqlQueryPipeline {
id: string;
name?: string;
icon?: string | null;

View File

@ -1,11 +1,12 @@
import { DocumentNode } from 'graphql';
import { ReactNode } from 'react';
import { DocumentNode } from 'graphql';
import {
AnyEntity,
BoolExpType,
GqlType,
UnknownType,
} from '../entities/generic.interface';
} from '@/utils/interfaces/generic.interface';
export type SearchConfigType<
SearchType extends AnyEntity | UnknownType = UnknownType,

View File

@ -1,11 +1,10 @@
import { gql, useQuery } from '@apollo/client';
import { useMemo, useState } from 'react';
import { SearchConfigType } from '../../../interfaces/search/interface';
import {
AnyEntity,
UnknownType,
} from '../../../interfaces/entities/generic.interface';
import { debounce } from '../../../modules/utils/debounce';
import { gql, useQuery } from '@apollo/client';
import { debounce } from '@/utils/debounce';
import { AnyEntity, UnknownType } from '@/utils/interfaces/generic.interface';
import { SearchConfigType } from '../interfaces/interface';
export const SEARCH_PEOPLE_QUERY = gql`
query SearchPeopleQuery($where: PersonWhereInput, $limit: Int) {

View File

@ -1,8 +1,10 @@
import { ReactElement } from 'react';
import { useRecoilState } from 'recoil';
import { isSomeInputInEditModeState } from '../../tables/states/isSomeInputInEditModeState';
import { CellBaseContainer } from './CellBaseContainer';
import { CellNormalModeContainer } from './CellNormalModeContainer';
import { useRecoilState } from 'recoil';
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
import { EditableCellEditMode } from './EditableCellEditMode';
type OwnProps = {

View File

@ -1,10 +1,13 @@
import { ReactElement, useMemo, useRef } from 'react';
import { CellEditModeContainer } from './CellEditModeContainer';
import { useRecoilState } from 'recoil';
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
import { useListenClickOutsideArrayOfRef } from '../../modules/ui/common/hooks/useListenClickOutsideArrayOfRef';
import { useHotkeys } from 'react-hotkeys-hook';
import { debounce } from '../../modules/utils/debounce';
import { useRecoilState } from 'recoil';
import { debounce } from '@/utils/debounce';
import { useListenClickOutsideArrayOfRef } from '../../hooks/useListenClickOutsideArrayOfRef';
import { isSomeInputInEditModeState } from '../../tables/states/isSomeInputInEditModeState';
import { CellEditModeContainer } from './CellEditModeContainer';
type OwnProps = {
editModeContent: ReactElement;

View File

@ -1,8 +1,10 @@
import { ReactElement } from 'react';
import { CellBaseContainer } from './CellBaseContainer';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
import { isSomeInputInEditModeState } from '../../tables/states/isSomeInputInEditModeState';
import { CellBaseContainer } from './CellBaseContainer';
import { EditableCellMenuEditMode } from './EditableCellMenuEditMode';
const EditableCellMenuNormalModeContainer = styled.div`

View File

@ -1,9 +1,12 @@
import { ReactElement, useMemo, useRef } from 'react';
import { useRecoilState } from 'recoil';
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
import { useListenClickOutsideArrayOfRef } from '../../modules/ui/common/hooks/useListenClickOutsideArrayOfRef';
import { useHotkeys } from 'react-hotkeys-hook';
import { debounce } from '../../modules/utils/debounce';
import { useRecoilState } from 'recoil';
import { debounce } from '@/utils/debounce';
import { useListenClickOutsideArrayOfRef } from '../../hooks/useListenClickOutsideArrayOfRef';
import { isSomeInputInEditModeState } from '../../tables/states/isSomeInputInEditModeState';
import { EditableCellMenuEditModeContainer } from './EditableCellMenuEditModeContainer';
type OwnProps = {

View File

@ -1,4 +1,5 @@
import styled from '@emotion/styled';
import { overlayBackground } from '../../layout/styles/themes';
type OwnProps = {

View File

@ -1,8 +1,11 @@
import styled from '@emotion/styled';
import { ChangeEvent, ComponentType, useRef, useState } from 'react';
import { EditableCell } from './EditableCell';
import styled from '@emotion/styled';
import { CellCommentChip } from '@/comments/components/comments/CellCommentChip';
import { textInputStyle } from '../../layout/styles/themes';
import { CellCommentChip } from '../comments/CellCommentChip';
import { EditableCell } from './EditableCell';
export type EditableChipProps = {
placeholder?: string;

View File

@ -1,8 +1,11 @@
import styled from '@emotion/styled';
import { forwardRef, useState } from 'react';
import { EditableCell } from './EditableCell';
import styled from '@emotion/styled';
import { humanReadableDate } from '@/utils/utils';
import DatePicker from '../form/DatePicker';
import { humanReadableDate } from '../../services/utils';
import { EditableCell } from './EditableCell';
export type EditableDateProps = {
value: Date;
@ -29,7 +32,7 @@ const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
top: 10px;
background: ${(props) => props.theme.secondaryBackground};
`;
function EditableDate({
export function EditableDate({
value,
changeHandler,
editModeHorizontalAlign,
@ -82,5 +85,3 @@ function EditableDate({
></EditableCell>
);
}
export default EditableDate;

View File

@ -1,8 +1,10 @@
import styled from '@emotion/styled';
import { ChangeEvent, ReactElement, useRef, useState } from 'react';
import { EditableCell } from './EditableCell';
import styled from '@emotion/styled';
import { textInputStyle } from '../../layout/styles/themes';
import { EditableCell } from './EditableCell';
type OwnProps = {
firstValue: string;
secondValue: string;

View File

@ -1,9 +1,11 @@
import styled from '@emotion/styled';
import { ChangeEvent, MouseEvent, useRef, useState } from 'react';
import { EditableCell } from './EditableCell';
import styled from '@emotion/styled';
import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';
import Link from '../link/Link';
import { EditableCell } from './EditableCell';
type OwnProps = {
placeholder?: string;
value: string;
@ -26,7 +28,7 @@ const StyledEditInplaceInput = styled.input<StyledEditModeProps>`
}
`;
function EditablePhone({ value, placeholder, changeHandler }: OwnProps) {
export function EditablePhone({ value, placeholder, changeHandler }: OwnProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value);
const [isEditMode, setIsEditMode] = useState(false);
@ -69,5 +71,3 @@ function EditablePhone({ value, placeholder, changeHandler }: OwnProps) {
/>
);
}
export default EditablePhone;

View File

@ -1,18 +1,21 @@
import { ChangeEvent, ComponentType, useEffect, useState } from 'react';
import styled from '@emotion/styled';
import { useSearch } from '../../services/api/search/search';
import { SearchConfigType } from '../../interfaces/search/interface';
import { AnyEntity } from '../../interfaces/entities/generic.interface';
import { EditableRelationCreateButton } from './EditableRelationCreateButton';
import { isNonEmptyString } from '../../modules/utils/type-guards/isNonEmptyString';
import { isDefined } from '../../modules/utils/type-guards/isDefined';
import { FaPlus } from 'react-icons/fa';
import { HoverableMenuItem } from './HoverableMenuItem';
import { EditableCellMenu } from './EditableCellMenu';
import { CellNormalModeContainer } from './CellNormalModeContainer';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { isSomeInputInEditModeState } from '../../modules/ui/tables/states/isSomeInputInEditModeState';
import { SearchConfigType } from '@/search/interfaces/interface';
import { useSearch } from '@/search/services/search';
import { AnyEntity } from '@/utils/interfaces/generic.interface';
import { isDefined } from '@/utils/type-guards/isDefined';
import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString';
import { textInputStyle } from '../../layout/styles/themes';
import { isSomeInputInEditModeState } from '../../tables/states/isSomeInputInEditModeState';
import { CellNormalModeContainer } from './CellNormalModeContainer';
import { EditableCellMenu } from './EditableCellMenu';
import { EditableRelationCreateButton } from './EditableRelationCreateButton';
import { HoverableMenuItem } from './HoverableMenuItem';
const StyledEditModeContainer = styled.div`
width: 200px;
@ -95,7 +98,7 @@ export type EditableRelationProps<
};
// TODO: split this component
function EditableRelation<
export function EditableRelation<
RelationType extends AnyEntity,
ChipComponentPropsType,
>({
@ -216,5 +219,3 @@ function EditableRelation<
</>
);
}
export default EditableRelation;

View File

@ -1,8 +1,10 @@
import styled from '@emotion/styled';
import { ChangeEvent, useRef, useState } from 'react';
import { EditableCell } from './EditableCell';
import styled from '@emotion/styled';
import { textInputStyle } from '../../layout/styles/themes';
import { EditableCell } from './EditableCell';
type OwnProps = {
placeholder?: string;
content: string;
@ -24,7 +26,7 @@ const StyledNoEditText = styled.div`
width: 100%;
`;
function EditableText({
export function EditableText({
content,
placeholder,
changeHandler,
@ -57,5 +59,3 @@ function EditableText({
></EditableCell>
);
}
export default EditableText;

View File

@ -1,9 +1,10 @@
import styled from '@emotion/styled';
import React, { ReactElement, forwardRef, useState } from 'react';
import React, { forwardRef, ReactElement, useState } from 'react';
import ReactDatePicker, { CalendarContainerProps } from 'react-datepicker';
import styled from '@emotion/styled';
import { overlayBackground } from '../../layout/styles/themes';
import 'react-datepicker/dist/react-datepicker.css';
import { overlayBackground } from '../../layout/styles/themes';
export type DatePickerProps = {
isOpen?: boolean;

View File

@ -1,5 +1,6 @@
import styled from '@emotion/styled';
import { ChangeEvent, useRef } from 'react';
import styled from '@emotion/styled';
import { textInputStyle } from '../../layout/styles/themes';
type OwnProps = {

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import * as React from 'react';
import { Link as ReactLink } from 'react-router-dom';
import styled from '@emotion/styled';
type OwnProps = {
href: string;

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import styled from '@emotion/styled';
import { Checkbox } from '../form/Checkbox';
type OwnProps = {

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import { ReactNode } from 'react';
import styled from '@emotion/styled';
type OwnProps = {
viewName: string;
@ -20,7 +20,7 @@ const StyledIcon = styled.div`
margin-right: ${(props) => props.theme.spacing(1)};
`;
function TableHeader({ viewName, viewIcon }: OwnProps) {
export function ColumnHead({ viewName, viewIcon }: OwnProps) {
return (
<StyledTitle>
<StyledIcon>{viewIcon}</StyledIcon>
@ -28,5 +28,3 @@ function TableHeader({ viewName, viewIcon }: OwnProps) {
</StyledTitle>
);
}
export default TableHeader;

View File

@ -1,21 +1,26 @@
import * as React from 'react';
import styled from '@emotion/styled';
import {
ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
import TableHeader from './table-header/TableHeader';
import { useRecoilState } from 'recoil';
import {
FilterConfigType,
SelectedFilterType,
} from '../../interfaces/filters/interface';
import { SortType, SelectedSortType } from '../../interfaces/sorts/interface';
import { useRecoilState } from 'recoil';
import { currentRowSelectionState } from '../../modules/ui/tables/states/rowSelectionState';
import { useResetTableRowSelection } from '../../modules/ui/tables/hooks/useResetTableRowSelection';
} from '@/filters-and-sorts/interfaces/filters/interface';
import {
SelectedSortType,
SortType,
} from '@/filters-and-sorts/interfaces/sorts/interface';
import { useResetTableRowSelection } from '../../tables/hooks/useResetTableRowSelection';
import { currentRowSelectionState } from '../../tables/states/rowSelectionState';
import { TableHeader } from './table-header/TableHeader';
type OwnProps<
TData extends { id: string; __typename: 'companies' | 'people' },

View File

@ -1,7 +1,8 @@
import styled from '@emotion/styled';
import React from 'react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { selectedRowIdsState } from '../../../modules/ui/tables/states/selectedRowIdsState';
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
type OwnProps = {
children: React.ReactNode | React.ReactNode[];

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import { ReactNode } from 'react';
import styled from '@emotion/styled';
type OwnProps = {
icon: ReactNode;

View File

@ -1,6 +1,8 @@
import { FaRegComment } from 'react-icons/fa';
import { useOpenRightDrawer } from '@/ui/layout/right-drawer/hooks/useOpenRightDrawer';
import { EntityTableActionBarButton } from './EntityTableActionBarButton';
import { useOpenRightDrawer } from '../../../modules/ui/layout/right-drawer/hooks/useOpenRightDrawer';
export function TableActionBarButtonToggleComments() {
// TODO: here it would be nice to access the table context

View File

@ -1,11 +1,12 @@
import { ReactNode, useRef } from 'react';
import { FaAngleDown } from 'react-icons/fa';
import styled from '@emotion/styled';
import { useRef, ReactNode } from 'react';
import { useOutsideAlerter } from '../../../hooks/useOutsideAlerter';
import {
overlayBackground,
textInputStyle,
} from '../../../layout/styles/themes';
import { FaAngleDown } from 'react-icons/fa';
type OwnProps = {
label: string;

View File

@ -1,18 +1,18 @@
import { ChangeEvent, useCallback, useState } from 'react';
import DropdownButton from './DropdownButton';
import styled from '@emotion/styled';
import {
FilterableFieldsType,
FilterConfigType,
FilterOperandType,
FilterableFieldsType,
SelectedFilterType,
} from '../../../interfaces/filters/interface';
import {
SearchResultsType,
useSearch,
} from '../../../services/api/search/search';
} from '@/filters-and-sorts/interfaces/filters/interface';
import { SearchResultsType, useSearch } from '@/search/services/search';
import { humanReadableDate } from '@/utils/utils';
import DatePicker from '../../form/DatePicker';
import styled from '@emotion/styled';
import { humanReadableDate } from '../../../services/utils';
import DropdownButton from './DropdownButton';
type OwnProps<TData extends FilterableFieldsType> = {
isFilterSelected: boolean;

View File

@ -1,11 +1,13 @@
import styled from '@emotion/styled';
import SortOrFilterChip from './SortOrFilterChip';
import { FaArrowDown, FaArrowUp } from 'react-icons/fa';
import styled from '@emotion/styled';
import {
FilterableFieldsType,
SelectedFilterType,
} from '../../../interfaces/filters/interface';
import { SelectedSortType } from '../../../interfaces/sorts/interface';
} from '@/filters-and-sorts/interfaces/filters/interface';
import { SelectedSortType } from '@/filters-and-sorts/interfaces/sorts/interface';
import SortOrFilterChip from './SortOrFilterChip';
type OwnProps<SortField, TData extends FilterableFieldsType> = {
sorts: Array<SelectedSortType<SortField>>;

View File

@ -1,9 +1,11 @@
import { useCallback, useState } from 'react';
import DropdownButton from './DropdownButton';
import {
SelectedSortType,
SortType,
} from '../../../interfaces/sorts/interface';
} from '@/filters-and-sorts/interfaces/sorts/interface';
import DropdownButton from './DropdownButton';
type OwnProps<SortField> = {
isSortSelected: boolean;

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { TbX } from 'react-icons/tb';
import { ReactNode } from 'react';
import { TbX } from 'react-icons/tb';
import styled from '@emotion/styled';
type OwnProps = {
id: string;

View File

@ -1,18 +1,19 @@
import { ReactNode, useCallback, useState } from 'react';
import styled from '@emotion/styled';
import { ReactNode, useCallback, useState } from 'react';
import { SortDropdownButton } from './SortDropdownButton';
import { FilterDropdownButton } from './FilterDropdownButton';
import SortAndFilterBar from './SortAndFilterBar';
import {
FilterableFieldsType,
FilterConfigType,
SelectedFilterType,
} from '../../../interfaces/filters/interface';
} from '@/filters-and-sorts/interfaces/filters/interface';
import {
SortType,
SelectedSortType,
} from '../../../interfaces/sorts/interface';
SortType,
} from '@/filters-and-sorts/interfaces/sorts/interface';
import { FilterDropdownButton } from './FilterDropdownButton';
import SortAndFilterBar from './SortAndFilterBar';
import { SortDropdownButton } from './SortDropdownButton';
type OwnProps<SortField, TData extends FilterableFieldsType> = {
viewName: string;
@ -59,7 +60,7 @@ const StyledFilters = styled.div`
margin-right: ${(props) => props.theme.spacing(2)};
`;
function TableHeader<SortField, TData extends FilterableFieldsType>({
export function TableHeader<SortField, TData extends FilterableFieldsType>({
viewName,
viewIcon,
availableSorts,
@ -150,8 +151,6 @@ function TableHeader<SortField, TData extends FilterableFieldsType>({
);
}
export default TableHeader;
function updateSortOrFilterByKey<SortOrFilter extends { key: string }>(
sorts: Readonly<SortOrFilter[]>,
newSort: SortOrFilter,

View File

@ -1,7 +1,8 @@
import { useRef } from 'react';
import { render, fireEvent } from '@testing-library/react';
import { useOutsideAlerter } from '../useOutsideAlerter';
import { act } from 'react-dom/test-utils';
import { fireEvent, render } from '@testing-library/react';
import { useOutsideAlerter } from '../useOutsideAlerter';
const onOutsideClick = jest.fn();
function TestComponent() {

View File

@ -1,5 +1,6 @@
import React, { useEffect } from 'react';
import { isDefined } from '../../../utils/type-guards/isDefined';
import { isDefined } from '@/utils/type-guards/isDefined';
export function useListenClickOutsideArrayOfRef<T extends HTMLElement>(
arrayOfRef: Array<React.RefObject<T>>,

View File

@ -1,7 +1,7 @@
import { ReactComponent as IconAddressBookRaw } from '../svgs/address-book.svg';
import { TablerIconsProps } from '@tabler/icons-react';
import { ReactComponent as IconAddressBookRaw } from '../svgs/address-book.svg';
export function IconAddressBook(props: TablerIconsProps): JSX.Element {
const size = props.size ?? 24;
const stroke = props.stroke ?? 2;

View File

@ -1,3 +1,3 @@
export { IconAward } from '@tabler/icons-react';
export { IconAddressBook } from './components/IconAddressBook';
export { IconComment } from './components/IconComment';
export { IconAward } from '@tabler/icons-react';

View File

Before

Width:  |  Height:  |  Size: 539 B

After

Width:  |  Height:  |  Size: 539 B

View File

@ -1,7 +1,9 @@
import { Navbar } from './navbar/Navbar';
import styled from '@emotion/styled';
import { ThemeProvider } from '@emotion/react';
import { User } from '../interfaces/entities/user.interface';
import styled from '@emotion/styled';
import { User } from '@/users/interfaces/user.interface';
import { Navbar } from './navbar/Navbar';
import { lightTheme } from './styles/themes';
const StyledLayout = styled.div`
@ -26,7 +28,7 @@ type OwnProps = {
user?: User;
};
function AppLayout({ children, user }: OwnProps) {
export function AppLayout({ children, user }: OwnProps) {
return (
<ThemeProvider theme={lightTheme}>
<StyledLayout>
@ -36,5 +38,3 @@ function AppLayout({ children, user }: OwnProps) {
</ThemeProvider>
);
}
export default AppLayout;

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import React from 'react';
import styled from '@emotion/styled';
const StyledPanel = styled.div`
display: flex;

View File

@ -1,11 +1,12 @@
import styled from '@emotion/styled';
import TopBar from '../top-bar/TopBar';
import { ReactNode } from 'react';
import { RightDrawer } from '../right-drawer/RightDrawer';
import { Panel } from '../Panel';
import { isRightDrawerOpenState } from '../../modules/ui/layout/right-drawer/states/isRightDrawerOpenState';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { Panel } from '../Panel';
import { RightDrawer } from '../right-drawer/components/RightDrawer';
import { isRightDrawerOpenState } from '../right-drawer/states/isRightDrawerOpenState';
import { TopBar } from '../top-bar/TopBar';
type OwnProps = {
children: JSX.Element;
title: string;
@ -45,7 +46,7 @@ const LeftContainer = styled.div<LeftContainerProps>`
position: relative;
`;
function FullWidthContainer({
export function WithTopBarContainer({
children,
title,
icon,
@ -65,5 +66,3 @@ function FullWidthContainer({
</StyledContainer>
);
}
export default FullWidthContainer;

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { useNavigate } from 'react-router-dom';
import { ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import styled from '@emotion/styled';
type OwnProps = {
label: string;

View File

@ -1,11 +1,13 @@
import styled from '@emotion/styled';
import { TbBuilding, TbUser } from 'react-icons/tb';
import { useMatch, useResolvedPath } from 'react-router-dom';
import { User } from '../../interfaces/entities/user.interface';
import { Workspace } from '../../interfaces/entities/workspace.interface';
import styled from '@emotion/styled';
import { User } from '@/users/interfaces/user.interface';
import { Workspace } from '@/workspaces/interfaces/workspace.interface';
import NavItem from './NavItem';
import NavTitle from './NavTitle';
import WorkspaceContainer from './WorkspaceContainer';
import { TbBuilding, TbUser } from 'react-icons/tb';
const NavbarContainer = styled.div`
display: flex;

View File

@ -1,5 +1,6 @@
import styled from '@emotion/styled';
import { Workspace } from '../../interfaces/entities/workspace.interface';
import { Workspace } from '@/workspaces/interfaces/workspace.interface';
type OwnProps = {
workspace: Workspace;

View File

@ -1,10 +1,13 @@
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { isRightDrawerOpenState } from '../../modules/ui/layout/right-drawer/states/isRightDrawerOpenState';
import { isDefined } from '@/utils/type-guards/isDefined';
import { Panel } from '../../Panel';
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
import { rightDrawerPageState } from '../states/rightDrawerPageState';
import { RightDrawerRouter } from './RightDrawerRouter';
import { rightDrawerPageState } from '../../modules/ui/layout/right-drawer/states/rightDrawerPageState';
import { isDefined } from '../../modules/utils/type-guards/isDefined';
import { Panel } from '../Panel';
const StyledRightDrawer = styled.div`
display: flex;

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