From 23758a28b95303dd98276987770e612b90ada1f2 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:00:59 +0200 Subject: [PATCH 001/116] helper string format through regex reviewed --- .../authentication/ForgotPassword.tsx | 4 +- .../src/components/authentication/SignUp.tsx | 6 +- .../creation/ProjectDataInitialization.tsx | 5 +- .../projects/models/ProjectModelSharing.tsx | 4 +- .../app/src/components/team/MemberCreator.tsx | 4 +- colab-webapp/src/main/node/app/src/helper.ts | 88 +++++++++++++------ 6 files changed, 73 insertions(+), 38 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx b/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx index a0f5bf20852..038fd778d85 100644 --- a/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx +++ b/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx @@ -9,7 +9,7 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import * as API from '../../API/api'; -import { buildLinkWithQueryParam, emailFormat } from '../../helper'; +import { assertEmailFormat, buildLinkWithQueryParam } from '../../helper'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch, useLoadingState } from '../../store/hooks'; import { lightLinkStyle, space_lg } from '../../styling/style'; @@ -40,7 +40,7 @@ export default function ResetPasswordForm({ redirectTo }: ResetPasswordFormProps label: i18n.authentication.field.emailAddress, type: 'text', isMandatory: true, - isErroneous: value => value.email.match(emailFormat) == null, + isErroneous: value => !assertEmailFormat(value.email), errorMessage: i18n.authentication.error.emailAddressNotValid, }, ]; diff --git a/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx b/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx index bf639e7040d..d6fe89f8242 100644 --- a/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx +++ b/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx @@ -10,7 +10,7 @@ import { WithJsonDiscriminator } from 'colab-rest-client'; import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import * as API from '../../API/api'; -import { buildLinkWithQueryParam, emailFormat } from '../../helper'; +import { assertEmailFormat, assertUserNameFormat, buildLinkWithQueryParam } from '../../helper'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch, useLoadingState } from '../../store/hooks'; import { lightLinkStyle, space_lg } from '../../styling/style'; @@ -62,7 +62,7 @@ export default function SignUpForm({ redirectTo }: SignUpFormProps): JSX.Element type: 'text', isMandatory: true, autoComplete: 'off', - isErroneous: value => value.email.match(emailFormat) == null, + isErroneous: value => !assertEmailFormat(value.email), errorMessage: i18n.authentication.error.emailAddressNotValid, }, { @@ -71,7 +71,7 @@ export default function SignUpForm({ redirectTo }: SignUpFormProps): JSX.Element type: 'text', isMandatory: true, autoComplete: 'off', - isErroneous: value => value.username.match(/^[a-zA-Z0-9._-]+$/) == null, + isErroneous: value => !assertUserNameFormat(value.username), errorMessage: i18n.authentication.error.usernameNotValid, }, { diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx index 507b912e0a7..29543664266 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx @@ -8,7 +8,7 @@ import { css, cx } from '@emotion/css'; import { Illustration } from 'colab-rest-client'; import * as React from 'react'; -import { emailFormat } from '../../../helper'; +import { assertEmailFormat } from '../../../helper'; import useTranslations from '../../../i18n/I18nContext'; import { labelStyle, @@ -161,8 +161,7 @@ export default function ProjectDataInitialization({ type: 'text', isMandatory: false, readOnly: readOnly, - isErroneous: value => - value.email.length > 0 && value.email.match(emailFormat) == null, + isErroneous: value => value.email.length > 0 && !assertEmailFormat(value.email), errorMessage: i18n.authentication.error.emailAddressNotValid, }, ]} diff --git a/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSharing.tsx b/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSharing.tsx index eb9a9cc8907..ebf88a612b7 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSharing.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSharing.tsx @@ -7,7 +7,7 @@ import * as React from 'react'; import * as API from '../../../API/api'; -import { emailFormat } from '../../../helper'; +import { assertEmailFormat } from '../../../helper'; import useTranslations from '../../../i18n/I18nContext'; import { useAppDispatch, useLoadingState } from '../../../store/hooks'; import { addNotification } from '../../../store/slice/notificationSlice'; @@ -39,7 +39,7 @@ export default function ProjectModelSharing({ label: i18n.authentication.field.emailAddress, type: 'text', isMandatory: true, - isErroneous: value => value.email.match(emailFormat) == null, + isErroneous: value => !assertEmailFormat(value.email), errorMessage: i18n.authentication.error.emailAddressNotValid, }, ]; diff --git a/colab-webapp/src/main/node/app/src/components/team/MemberCreator.tsx b/colab-webapp/src/main/node/app/src/components/team/MemberCreator.tsx index 0b3e5eb969d..4ebdf1c644f 100644 --- a/colab-webapp/src/main/node/app/src/components/team/MemberCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/team/MemberCreator.tsx @@ -8,7 +8,7 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; import * as API from '../../API/api'; -import { emailFormat } from '../../helper'; +import { assertEmailFormat } from '../../helper'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch, useLoadingState } from '../../store/hooks'; import { useCurrentProjectId } from '../../store/selectors/projectSelector'; @@ -42,7 +42,7 @@ export default function TeamMemberCreator(): JSX.Element { }, [members, emailAddress]); const isValidEmailAddress: boolean = React.useMemo(() => { - return emailAddress.length > 0 && emailAddress.match(emailFormat) != null; + return emailAddress.length > 0 && assertEmailFormat(emailAddress); }, [emailAddress]); const isValidNewMember: boolean = isValidEmailAddress && isNewMember; diff --git a/colab-webapp/src/main/node/app/src/helper.ts b/colab-webapp/src/main/node/app/src/helper.ts index 0747ecc4775..76e4b22ce86 100644 --- a/colab-webapp/src/main/node/app/src/helper.ts +++ b/colab-webapp/src/main/node/app/src/helper.ts @@ -9,7 +9,53 @@ import { TeamMember, User, WithId } from 'colab-rest-client'; import { escapeRegExp } from 'lodash'; import logger from './logger'; -export const emailFormat = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; +// ************************************************************************************************* +// String format check through regular expressions + +/** + * Check that the email format is valid + */ +export function assertEmailFormat(data: string) { + return data.match(emailFormat) != null; +} + +const emailFormat = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; + +/** + * Check that the username format is valid + */ +export function assertUserNameFormat(data: string) { + return data.match(userNameFormat) != null; +} + +const userNameFormat = /^[a-zA-Z0-9._-]+$/; + +/** + * Filter data of the list to only those matching the regular expressions + */ +export function regexFilter( + list: T[], + search: string, + matchFn: (regex: RegExp, item: T) => boolean, +): T[] { + if (search.length <= 0) { + return list; + } + + const regexes = search.split(/\s+/).map(regex => new RegExp(escapeRegExp(regex), 'i')); + + return list.filter(item => { + return regexes.reduce((acc, regex) => { + if (acc == false) { + return false; + } + return matchFn(regex, item); + }, true); + }); +} + +// ************************************************************************************************* +// sorting export function sortSmartly( a: string | null | undefined, @@ -31,6 +77,21 @@ export function sortSmartly( return a.localeCompare(b, lang, { numeric: true }); } +// ************************************************************************************************* +// developpment tools + +/** + * Logs an error. + * And, as it is typed as never, it throws a compilation error if a case is missing. + */ +// Advice : add this comment before when using it // If next line is erroneous, it means a type of xxx is not handled +export function checkUnreachable(x: never): void { + logger.error(x); +} + +// ************************************************************************************************* +// + export const getDisplayName = ( user: User | undefined | null, teamMember?: TeamMember, @@ -93,28 +154,3 @@ export const removeAllItems = (array: unknown[], items: unknown[]): void => { } }); }; - -export function checkUnreachable(x: never): void { - logger.error(x); -} - -export function regexFilter( - list: T[], - search: string, - matchFn: (regex: RegExp, item: T) => boolean, -): T[] { - if (search.length <= 0) { - return list; - } - - const regexes = search.split(/\s+/).map(token => new RegExp(escapeRegExp(token), 'i')); - - return list.filter(item => { - return regexes.reduce((acc, regex) => { - if (acc == false) { - return false; - } - return matchFn(regex, item); - }, true); - }); -} From 602f55742a954dadde15a4be7b41b461d6664c17 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:09:37 +0200 Subject: [PATCH 002/116] helper sorting review --- .../node/app/src/components/resources/ResourcesList.tsx | 6 ++---- colab-webapp/src/main/node/app/src/helper.ts | 3 +++ .../main/node/app/src/store/selectors/cardTypeSelector.ts | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx b/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx index 567838627f2..6021dcdb158 100644 --- a/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx +++ b/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx @@ -9,6 +9,7 @@ import { css, cx } from '@emotion/css'; import { entityIs } from 'colab-rest-client'; import * as React from 'react'; import * as API from '../../API/api'; +import { sortSmartly } from '../../helper'; import useTranslations, { useLanguage } from '../../i18n/I18nContext'; import { useAppDispatch } from '../../store/hooks'; import { useProjectRootCard } from '../../store/selectors/cardSelector'; @@ -62,12 +63,9 @@ export const TocDisplayCtx = React.createContext({ * List of ResourceAndRef grouped by category */ -// for the moment, the resources are ordered by id (= creation date) function sortResources(lang: string) { return (a: ResourceAndRef, b: ResourceAndRef): number => { - return (a.targetResource.title || '').localeCompare(b.targetResource.title || '', lang, { - numeric: true, - }); + return sortSmartly(a.targetResource.title, b.targetResource.title, lang); // return (a.targetResource.id || 0) - (b.targetResource.id || 0); }; } diff --git a/colab-webapp/src/main/node/app/src/helper.ts b/colab-webapp/src/main/node/app/src/helper.ts index 76e4b22ce86..3da6373eb2f 100644 --- a/colab-webapp/src/main/node/app/src/helper.ts +++ b/colab-webapp/src/main/node/app/src/helper.ts @@ -57,6 +57,9 @@ export function regexFilter( // ************************************************************************************************* // sorting +/** + * Sort strings : null first, then according to language + */ export function sortSmartly( a: string | null | undefined, b: string | null | undefined, diff --git a/colab-webapp/src/main/node/app/src/store/selectors/cardTypeSelector.ts b/colab-webapp/src/main/node/app/src/store/selectors/cardTypeSelector.ts index 8f337cfb940..c2927ab304c 100644 --- a/colab-webapp/src/main/node/app/src/store/selectors/cardTypeSelector.ts +++ b/colab-webapp/src/main/node/app/src/store/selectors/cardTypeSelector.ts @@ -9,6 +9,7 @@ import { CardType as CardTypeOnly, CardTypeRef, entityIs } from 'colab-rest-clie import { uniq } from 'lodash'; import * as React from 'react'; import * as API from '../../API/api'; +import { sortSmartly } from '../../helper'; import { useLanguage } from '../../i18n/I18nContext'; import { CardTypeAllInOne, CardTypeAndStatus } from '../../types/cardTypeDefinition'; import { customColabStateEquals, useAppDispatch, useAppSelector } from '../hooks'; @@ -251,7 +252,7 @@ function useProjectCardTypes(): CardTypeAllInOne[] { } return result.sort((a, b) => { - return (a.title ?? '').localeCompare(b.title ?? '', lang); + return sortSmartly(a.title, b.title, lang); }); }, customColabStateEquals); } From 753d983d540d971bbac1f4e1f20be36d97d34464 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:19:39 +0200 Subject: [PATCH 003/116] helper split with storeHelper --- colab-webapp/src/main/node/app/src/helper.ts | 23 +------------ .../app/src/store/slice/assignmentSlice.ts | 2 +- .../node/app/src/store/slice/cardTypeSlice.ts | 2 +- .../node/app/src/store/slice/documentSlice.ts | 2 +- .../node/app/src/store/slice/projectSlice.ts | 2 +- .../node/app/src/store/slice/resourceSlice.ts | 2 +- .../app/src/store/slice/teamMemberSlice.ts | 2 +- .../node/app/src/store/slice/teamRoleSlice.ts | 2 +- .../node/app/src/store/slice/teamSlice.ts | 2 +- .../node/app/src/store/slice/userSlice.ts | 2 +- .../main/node/app/src/store/storeHelper.ts | 32 +++++++++++++++++++ 11 files changed, 42 insertions(+), 31 deletions(-) create mode 100644 colab-webapp/src/main/node/app/src/store/storeHelper.ts diff --git a/colab-webapp/src/main/node/app/src/helper.ts b/colab-webapp/src/main/node/app/src/helper.ts index 3da6373eb2f..1cbb8e66b6c 100644 --- a/colab-webapp/src/main/node/app/src/helper.ts +++ b/colab-webapp/src/main/node/app/src/helper.ts @@ -5,7 +5,7 @@ * Licensed under the MIT License */ -import { TeamMember, User, WithId } from 'colab-rest-client'; +import { TeamMember, User } from 'colab-rest-client'; import { escapeRegExp } from 'lodash'; import logger from './logger'; @@ -108,27 +108,6 @@ export const getDisplayName = ( ); }; -export const mapById = (entities: T[]): { [id: number]: T } => { - const map: { [id: number]: T } = {}; - entities.forEach(entity => { - if (entity.id != null) { - map[entity.id] = entity; - } - }); - return map; -}; - -export const updateById = (entities: T[], entity: T): void => { - const index = entities.findIndex(item => entity.id === item.id); - if (index >= 0) { - // entity exists in array:replace it - entities.splice(index, 1, entity); - } else { - // entity not found, add it - entities.push(entity); - } -}; - export const buildLinkWithQueryParam = ( baseUrl: string, queryParameters?: { [key: string]: string | null | undefined }, diff --git a/colab-webapp/src/main/node/app/src/store/slice/assignmentSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/assignmentSlice.ts index 7451b540c65..dbdbbfa3d7b 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/assignmentSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/assignmentSlice.ts @@ -7,9 +7,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { Assignment, IndexEntry } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus } from '../store'; +import { mapById } from '../storeHelper'; export interface AssignmentState { /** all the assignments we got so far, by card id and id */ diff --git a/colab-webapp/src/main/node/app/src/store/slice/cardTypeSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/cardTypeSlice.ts index 0e915b5121d..e5b3e12c70d 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/cardTypeSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/cardTypeSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { AbstractCardType } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus } from '../store'; +import { mapById } from '../storeHelper'; /** what we have in the store */ export interface CardTypeState { diff --git a/colab-webapp/src/main/node/app/src/store/slice/documentSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/documentSlice.ts index 8f235dfe15f..bb811743294 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/documentSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/documentSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { Document } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus } from '../store'; +import { mapById } from '../storeHelper'; /** what we have in the store */ export interface DocumentState { diff --git a/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts index 8c3c69ca982..cd1929b3261 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { CopyParam, Project } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus, EditionStatus, FetchingStatus } from '../store'; +import { mapById } from '../storeHelper'; /** what we have in the store */ export interface ProjectState { diff --git a/colab-webapp/src/main/node/app/src/store/slice/resourceSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/resourceSlice.ts index a8e3b0f6774..b223c52fe27 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/resourceSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/resourceSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { AbstractResource, entityIs } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus, LoadingStatus } from '../store'; +import { mapById } from '../storeHelper'; export interface ResourceState { resources: Record; diff --git a/colab-webapp/src/main/node/app/src/store/slice/teamMemberSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/teamMemberSlice.ts index 995e594f59b..063db4f3333 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/teamMemberSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/teamMemberSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { TeamMember } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus, FetchingStatus } from '../store'; +import { mapById } from '../storeHelper'; /** what we have in the store */ export interface TeamMemberState { diff --git a/colab-webapp/src/main/node/app/src/store/slice/teamRoleSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/teamRoleSlice.ts index 891f3ddd66f..7ed46157fd9 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/teamRoleSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/teamRoleSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { TeamRole } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus, FetchingStatus } from '../store'; +import { mapById } from '../storeHelper'; /** what we have in the store */ export interface TeamRoleState { diff --git a/colab-webapp/src/main/node/app/src/store/slice/teamSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/teamSlice.ts index aa9d9b121df..f0c3bb12837 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/teamSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/teamSlice.ts @@ -8,9 +8,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { InstanceMaker, TeamMember, TeamRole } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus } from '../store'; +import { mapById } from '../storeHelper'; export interface TeamState1 { status: AvailabilityStatus; diff --git a/colab-webapp/src/main/node/app/src/store/slice/userSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/userSlice.ts index 6403a5655af..aff451d1aa4 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/userSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/userSlice.ts @@ -7,9 +7,9 @@ import { createSlice } from '@reduxjs/toolkit'; import { Account, HttpSession, User } from 'colab-rest-client'; import * as API from '../../API/api'; -import { mapById } from '../../helper'; import { processMessage } from '../../ws/wsThunkActions'; import { AvailabilityStatus, LoadingStatus } from '../store'; +import { mapById } from '../storeHelper'; export interface UserState { // null user means loading diff --git a/colab-webapp/src/main/node/app/src/store/storeHelper.ts b/colab-webapp/src/main/node/app/src/store/storeHelper.ts new file mode 100644 index 00000000000..24f7ee6eac0 --- /dev/null +++ b/colab-webapp/src/main/node/app/src/store/storeHelper.ts @@ -0,0 +1,32 @@ +/* + * The coLAB project + * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO + * + * Licensed under the MIT License + */ + +import { WithId } from 'colab-rest-client'; + +/** + * Return a map of entities where key is their id and value is the entity + */ +export const mapById = (entities: T[]): { [id: number]: T } => { + const map: { [id: number]: T } = {}; + entities.forEach(entity => { + if (entity.id != null) { + map[entity.id] = entity; + } + }); + return map; +}; + +// export const updateById = (entities: T[], entity: T): void => { +// const index = entities.findIndex(item => entity.id === item.id); +// if (index >= 0) { +// // entity exists in array:replace it +// entities.splice(index, 1, entity); +// } else { +// // entity not found, add it +// entities.push(entity); +// } +// }; From ad4a2027e2eae5747146922cb00f8747b1b72f8a Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:24:10 +0200 Subject: [PATCH 004/116] helper review --- .../cardtypes/CardTypeThumbnail.tsx | 4 ++-- .../src/components/common/element/Tips.tsx | 4 ++-- .../components/documents/preview/Preview.tsx | 4 ++-- colab-webapp/src/main/node/app/src/helper.ts | 21 +++++++++---------- .../src/main/node/app/src/ws/websocket.ts | 4 ++-- .../main/node/app/src/ws/wsThunkActions.ts | 4 ++-- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx index dcf12f48bb5..311fe21bf23 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx @@ -9,7 +9,7 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import * as API from '../../API/api'; -import { checkUnreachable } from '../../helper'; +import { assertUnreachable } from '../../helper'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch, useLoadingState } from '../../store/hooks'; import { useAllProjectCardTypes } from '../../store/selectors/cardSelector'; @@ -252,7 +252,7 @@ export default function CardTypeThumbnail({ return <>; } default: - checkUnreachable(showModal); + assertUnreachable(showModal); } })()} diff --git a/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx b/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx index 7423971be21..f15e8f1a2fa 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx @@ -7,7 +7,7 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; -import { checkUnreachable } from '../../../helper'; +import { assertUnreachable } from '../../../helper'; import useTranslations from '../../../i18n/I18nContext'; import { MaterialIconsType } from '../../../styling/IconType'; import { lightIconButtonStyle, p_xs, space_sm } from '../../../styling/style'; @@ -74,7 +74,7 @@ function getIconProp(tipsType: TipsProps['tipsType']): MaterialIconsType { case undefined: return 'help'; default: - checkUnreachable(tipsType); + assertUnreachable(tipsType); return 'bug_report'; } } diff --git a/colab-webapp/src/main/node/app/src/components/documents/preview/Preview.tsx b/colab-webapp/src/main/node/app/src/components/documents/preview/Preview.tsx index 3ee3920794f..34307ff9769 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/preview/Preview.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/preview/Preview.tsx @@ -7,7 +7,7 @@ import { Document, entityIs } from 'colab-rest-client'; import * as React from 'react'; -import { checkUnreachable } from '../../../helper'; +import { assertUnreachable } from '../../../helper'; import OpenGraphLink from '../../common/element/OpenGraphLink'; import DocumentFileEditor from '../DocumentFileEditor'; import TextDataBlockPreview from './TextDataBlockPreview'; @@ -41,7 +41,7 @@ export default function Preview({ doc }: PreviewProps): JSX.Element { /> ); } else { - checkUnreachable(doc); + assertUnreachable(doc); return <>; } } diff --git a/colab-webapp/src/main/node/app/src/helper.ts b/colab-webapp/src/main/node/app/src/helper.ts index 1cbb8e66b6c..0ce62b8d8a8 100644 --- a/colab-webapp/src/main/node/app/src/helper.ts +++ b/colab-webapp/src/main/node/app/src/helper.ts @@ -84,21 +84,20 @@ export function sortSmartly( // developpment tools /** - * Logs an error. - * And, as it is typed as never, it throws a compilation error if a case is missing. + * Logs an error and, as it is typed as never, it throws a compilation error if a case is missing. */ // Advice : add this comment before when using it // If next line is erroneous, it means a type of xxx is not handled -export function checkUnreachable(x: never): void { +export function assertUnreachable(x: never): void { logger.error(x); } // ************************************************************************************************* // -export const getDisplayName = ( +export function getDisplayName( user: User | undefined | null, teamMember?: TeamMember, -): string | null => { +): string | null { return ( (user != null ? user.commonname || `${user.firstname || ''} ${user.lastname || ''}`.trim() || user.username @@ -106,12 +105,12 @@ export const getDisplayName = ( teamMember?.displayName || null ); -}; +} -export const buildLinkWithQueryParam = ( +export function buildLinkWithQueryParam( baseUrl: string, queryParameters?: { [key: string]: string | null | undefined }, -): string => { +): string { if (queryParameters == null) { return baseUrl; } else { @@ -126,13 +125,13 @@ export const buildLinkWithQueryParam = ( .join('&') ); } -}; +} -export const removeAllItems = (array: unknown[], items: unknown[]): void => { +export function removeAllItems(array: unknown[], items: unknown[]): void { items.forEach(item => { const index = array.indexOf(item); if (index >= 0) { array.splice(index, 1); } }); -}; +} diff --git a/colab-webapp/src/main/node/app/src/ws/websocket.ts b/colab-webapp/src/main/node/app/src/ws/websocket.ts index e45275d0574..d9208a2db03 100644 --- a/colab-webapp/src/main/node/app/src/ws/websocket.ts +++ b/colab-webapp/src/main/node/app/src/ws/websocket.ts @@ -14,7 +14,7 @@ import { WsUpdateMessage, } from 'colab-rest-client'; import { getApplicationPath, initSocketId } from '../API/api'; -import { checkUnreachable } from '../helper'; +import { assertUnreachable } from '../helper'; import { getLogger } from '../logger'; import * as AdminActions from '../store/slice/adminSlice'; import { addNotification } from '../store/slice/notificationSlice'; @@ -108,7 +108,7 @@ function createConnection(onCloseCb: () => void) { logger.trace('Receive Pong'); } else { //If next line is erroneous, it means a type of WsMessage is not handled - checkUnreachable(message); + assertUnreachable(message); } } else { storeDispatch( diff --git a/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts b/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts index 00250436c61..b94a8dfc549 100644 --- a/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts +++ b/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts @@ -30,7 +30,7 @@ import { UserPresence, WsUpdateMessage, } from 'colab-rest-client'; -import { checkUnreachable } from '../helper'; +import { assertUnreachable } from '../helper'; import { getLogger } from '../logger'; import { ColabNotification } from '../store/slice/notificationSlice'; @@ -186,7 +186,7 @@ export const processMessage = createAsyncThunk( bag.presences.upserted.push(item); } else { //If next line is erroneous, it means a type of entity is not handled - checkUnreachable(item); + assertUnreachable(item); } } }); From 10cd19c943cf39b47c0ab1c4cb42d7493e1ea782 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:30:32 +0200 Subject: [PATCH 005/116] strictly reorder tips --- .../src/main/node/app/src/components/App.tsx | 32 +++++++++---------- .../src/components/common/element/Tips.tsx | 25 ++++++++------- colab-webapp/src/main/node/app/src/i18n/en.ts | 10 +++--- colab-webapp/src/main/node/app/src/i18n/fr.ts | 10 +++--- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index a23da04fcee..6676277b836 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -53,7 +53,7 @@ injectGlobal` h1 { font-size: ${heading.lg}; } - + h2 { font-size: ${heading.md}; } @@ -95,37 +95,37 @@ function App(): JSX.Element { const [tocMode, setTocMode] = useLocalStorage('colab-resource-toc-mode', 'CATEGORY'); const [tipsConfig, setTipsConfig] = useLocalStorage('colab-tips-config', { - TODO: false, - NEWS: true, TIPS: true, + NEWS: true, + FEATURE_PREVIEW: false, WIP: false, + TODO: false, DEBUG: false, - FEATURE_PREVIEW: false, }); - const setTodoCb = React.useCallback( + const setTipsCb = React.useCallback( (v: boolean) => setTipsConfig(state => ({ ...state, - TODO: v, + TIPS: v, })), [setTipsConfig], ); - const setTipsCb = React.useCallback( + const setNewsCb = React.useCallback( (v: boolean) => setTipsConfig(state => ({ ...state, - TIPS: v, + NEWS: v, })), [setTipsConfig], ); - const setNewsCb = React.useCallback( + const setFeaturePreviewCb = React.useCallback( (v: boolean) => setTipsConfig(state => ({ ...state, - NEWS: v, + FEATURE_PREVIEW: v, })), [setTipsConfig], ); @@ -139,11 +139,11 @@ function App(): JSX.Element { [setTipsConfig], ); - const setFeaturePreviewCb = React.useCallback( + const setTodoCb = React.useCallback( (v: boolean) => setTipsConfig(state => ({ ...state, - FEATURE_PREVIEW: v, + TODO: v, })), [setTipsConfig], ); @@ -188,6 +188,10 @@ function App(): JSX.Element { value: tipsConfig.NEWS, set: setNewsCb, }, + FEATURE_PREVIEW: { + value: tipsConfig.FEATURE_PREVIEW, + set: setFeaturePreviewCb, + }, WIP: { value: tipsConfig.WIP, set: setWipCb, @@ -196,10 +200,6 @@ function App(): JSX.Element { value: tipsConfig.TODO, set: setTodoCb, }, - FEATURE_PREVIEW: { - value: tipsConfig.FEATURE_PREVIEW, - set: setFeaturePreviewCb, - }, DEBUG: { value: tipsConfig.DEBUG, set: setDebugCb, diff --git a/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx b/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx index f15e8f1a2fa..1d2e2566811 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/Tips.tsx @@ -15,24 +15,25 @@ import Icon from '../layout/Icon'; import Checkbox from './Checkbox'; import { overlayStyle } from './Tooltip'; -export type TipsType = 'TODO' | 'NEWS' | 'TIPS' | 'WIP' | 'DEBUG' | 'FEATURE_PREVIEW'; +export type TipsType = 'TIPS' | 'NEWS' | 'FEATURE_PREVIEW' | 'WIP' | 'TODO' | 'DEBUG'; export type TipsConfig = Record; + export type TipsContextType = Record< TipsType, { value: boolean; set: (newValue: boolean) => void } >; export const TipsCtx = React.createContext({ - TODO: { + TIPS: { value: false, set: () => {}, }, - TIPS: { + NEWS: { value: false, set: () => {}, }, - NEWS: { + FEATURE_PREVIEW: { value: false, set: () => {}, }, @@ -40,7 +41,7 @@ export const TipsCtx = React.createContext({ value: false, set: () => {}, }, - FEATURE_PREVIEW: { + TODO: { value: false, set: () => {}, }, @@ -60,19 +61,19 @@ export interface TipsProps { function getIconProp(tipsType: TipsProps['tipsType']): MaterialIconsType { switch (tipsType) { - case 'TODO': - return 'construction'; + case 'TIPS': + case undefined: + return 'help'; case 'NEWS': return 'newspaper'; + case 'FEATURE_PREVIEW': + return 'new_releases'; case 'WIP': return 'engineering'; + case 'TODO': + return 'construction'; case 'DEBUG': return 'build'; - case 'FEATURE_PREVIEW': - return 'new_releases'; - case 'TIPS': - case undefined: - return 'help'; default: assertUnreachable(tipsType); return 'bug_report'; diff --git a/colab-webapp/src/main/node/app/src/i18n/en.ts b/colab-webapp/src/main/node/app/src/i18n/en.ts index 3b23d29b135..538c21352df 100644 --- a/colab-webapp/src/main/node/app/src/i18n/en.ts +++ b/colab-webapp/src/main/node/app/src/i18n/en.ts @@ -641,18 +641,14 @@ export const en = { // Tips tips: { label: { - todo: 'Display Todo', tips: 'Display Tips', news: 'Display News', feature_preview: 'Display upcoming new features', wip: 'Display work in progress elements', + todo: 'Display Todo', debug: 'Display debug info', }, example: { - todo: { - title: 'Todo example', - content: 'We know what to do, but we have not done it yet', - }, tips: { title: 'Tips example', content: 'Some useful info to help users', @@ -669,6 +665,10 @@ export const en = { title: 'WIP Example', content: 'Some features not completely finished yet', }, + todo: { + title: 'Todo example', + content: 'We know what to do, but we have not done it yet', + }, debug: { title: 'Debug Example', content: 'Some internal data useful to debug', diff --git a/colab-webapp/src/main/node/app/src/i18n/fr.ts b/colab-webapp/src/main/node/app/src/i18n/fr.ts index 5a8067bf619..d87f235c892 100644 --- a/colab-webapp/src/main/node/app/src/i18n/fr.ts +++ b/colab-webapp/src/main/node/app/src/i18n/fr.ts @@ -655,18 +655,14 @@ export const fr: ColabTranslations = { // Tips tips: { label: { - todo: 'Afficher les éléments à faire', tips: 'Afficher les conseils', news: 'Afficher les actualités', feature_preview: 'Afficher les nouvelles fonctionnalités à venir', wip: 'Afficher les éléments de travail en cours', + todo: 'Afficher les éléments à faire', debug: "Afficher l'information de déboguage", }, example: { - todo: { - title: "Exemple d'élément à faire", - content: "Nous savons ce qu'il faut faire, mais nous ne l'avons pas encore fait.", - }, tips: { title: 'Exemple de conseil', content: 'Quelques informations utiles pour aider les utilisateurs', @@ -683,6 +679,10 @@ export const fr: ColabTranslations = { title: 'Exemple de travail en cours', content: 'Certaines fonctionnalités ne sont pas encore complètement terminées', }, + todo: { + title: "Exemple d'élément à faire", + content: "Nous savons ce qu'il faut faire, mais nous ne l'avons pas encore fait.", + }, debug: { title: 'Exemple de débogue', content: 'Quelques données internes utiles pour le débogage', From ff4e68e915a8f614f030ace9db7636376c91a11f Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:41:39 +0200 Subject: [PATCH 006/116] comments and spaces --- colab-webapp/src/main/node/app/src/components/App.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index 6676277b836..af429f4e6f0 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -35,6 +35,7 @@ injectGlobal` margin: 0; padding: 0; } + * { font-family: 'Public Sans', 'serif'; } @@ -82,6 +83,7 @@ function TokenWrapper() { function App(): JSX.Element { const defaultLanguage = + // try to know it from navigator (navigator.languages .map(l => { // remove variant part and turn uppercase @@ -89,9 +91,12 @@ function App(): JSX.Element { }) .find(lang => { return languages.includes(lang as Language); - }) as Language) || 'EN'; + }) as Language) || + // else english + 'EN'; const [lang, setLang] = useLocalStorage('colab-language', defaultLanguage); + const [tocMode, setTocMode] = useLocalStorage('colab-resource-toc-mode', 'CATEGORY'); const [tipsConfig, setTipsConfig] = useLocalStorage('colab-tips-config', { From ff494466ecb05af815abca19f356fdd2bb751979 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:43:53 +0200 Subject: [PATCH 007/116] split to TokenRouting --- .../src/main/node/app/src/components/App.tsx | 12 ++---------- .../app/src/components/token/TokenRouting.tsx | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index af429f4e6f0..aab809684d9 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -10,7 +10,7 @@ import * as React from 'react'; import { Suspense } from 'react'; import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; -import { HashRouter, Route, Routes, useParams } from 'react-router-dom'; +import { HashRouter, Route, Routes } from 'react-router-dom'; import { I18nCtx, Language, languages } from '../i18n/I18nContext'; import { useLocalStorage } from '../preferences'; import { store } from '../store/store'; @@ -23,7 +23,7 @@ import ErrorBoundary from './common/toplevel/ErrorBoundary'; import Notifier from './common/toplevel/Notifier'; import MainApp from './MainApp'; import { TocDisplayCtx, TocMode } from './resources/ResourcesList'; -import Token from './token/Token'; +import { TokenWrapper } from './token/TokenRouting'; injectGlobal` html { @@ -72,14 +72,6 @@ injectGlobal` border: 1px solid transparent; } `; -/** - * To read parameters from hash - */ -function TokenWrapper() { - const { id, token } = useParams<'id' | 'token'>(); - - return ; -} function App(): JSX.Element { const defaultLanguage = diff --git a/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx b/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx new file mode 100644 index 00000000000..556d91913d2 --- /dev/null +++ b/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx @@ -0,0 +1,19 @@ +/* + * The coLAB project + * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO + * + * Licensed under the MIT License + */ + +import * as React from 'react'; +import { useParams } from 'react-router-dom'; +import Token from './Token'; + +/** + * To read parameters from hash + */ +export function TokenWrapper() { + const { id, token } = useParams<'id' | 'token'>(); + + return ; +} From f4825ea1f58598eeed368e1cd0339a5b2951f0e1 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:50:33 +0200 Subject: [PATCH 008/116] stricty use import * as React --- .../src/main/node/app/src/components/AboutColab.tsx | 2 +- colab-webapp/src/main/node/app/src/components/App.tsx | 5 ++--- .../src/main/node/app/src/components/MainNav.tsx | 2 +- .../components/common/collection/FilterableList.tsx | 2 +- .../app/src/components/common/collection/Filters.tsx | 3 +-- .../src/components/common/collection/SearchInput.tsx | 9 ++++----- .../components/common/collection/SearchSortList.tsx | 8 ++++---- .../node/app/src/components/common/element/Avatar.tsx | 2 +- .../node/app/src/components/common/element/Badge.tsx | 2 +- .../components/common/element/IllustrationDisplay.tsx | 2 +- .../app/src/components/common/layout/DropDownMenu.tsx | 5 ++--- .../src/components/common/toplevel/ErrorBoundary.tsx | 11 +++++------ .../src/main/node/app/src/components/hooks/mouse.ts | 2 +- .../node/app/src/components/projects/ProjectThumb.tsx | 2 +- .../projects/activityFlow/ActivityFlowCardThumb.tsx | 2 +- .../projects/hierarchy/HierarchyCardCreator.tsx | 2 +- .../projects/hierarchy/HierarchyCardThumb.tsx | 2 +- .../projects/hierarchy/HierarchySubContainer.tsx | 2 +- .../node/app/src/store/selectors/documentSelector.ts | 2 +- .../node/app/src/store/selectors/resourceSelector.ts | 2 +- 20 files changed, 32 insertions(+), 37 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/AboutColab.tsx b/colab-webapp/src/main/node/app/src/components/AboutColab.tsx index b61d8a8c16f..bc329bdf13b 100644 --- a/colab-webapp/src/main/node/app/src/components/AboutColab.tsx +++ b/colab-webapp/src/main/node/app/src/components/AboutColab.tsx @@ -6,7 +6,7 @@ */ import { css } from '@emotion/css'; -import React from 'react'; +import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import useTranslations from '../i18n/I18nContext'; import { useVersionDetails } from '../store/selectors/configSelector'; diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index aab809684d9..95c35d33099 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -7,7 +7,6 @@ import { css, cx, injectGlobal } from '@emotion/css'; import * as React from 'react'; -import { Suspense } from 'react'; import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; import { HashRouter, Route, Routes } from 'react-router-dom'; @@ -171,7 +170,7 @@ function App(): JSX.Element { > - }> + }> @@ -226,7 +225,7 @@ function App(): JSX.Element { - + diff --git a/colab-webapp/src/main/node/app/src/components/MainNav.tsx b/colab-webapp/src/main/node/app/src/components/MainNav.tsx index 5b8a1527004..ec35ec9ce35 100644 --- a/colab-webapp/src/main/node/app/src/components/MainNav.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainNav.tsx @@ -6,7 +6,7 @@ */ import { css, cx } from '@emotion/css'; -import React from 'react'; +import * as React from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import * as API from '../API/api'; import useTranslations from '../i18n/I18nContext'; diff --git a/colab-webapp/src/main/node/app/src/components/common/collection/FilterableList.tsx b/colab-webapp/src/main/node/app/src/components/common/collection/FilterableList.tsx index 250849c6b07..e45227df55f 100644 --- a/colab-webapp/src/main/node/app/src/components/common/collection/FilterableList.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/collection/FilterableList.tsx @@ -6,7 +6,7 @@ */ import { css, cx } from '@emotion/css'; -import React from 'react'; +import * as React from 'react'; import useTranslations from '../../../i18n/I18nContext'; import { lightIconButtonStyle, diff --git a/colab-webapp/src/main/node/app/src/components/common/collection/Filters.tsx b/colab-webapp/src/main/node/app/src/components/common/collection/Filters.tsx index 868402eed8e..3564d7dd500 100644 --- a/colab-webapp/src/main/node/app/src/components/common/collection/Filters.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/collection/Filters.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { ReactNode } from 'react'; export interface IFilter { property: keyof T; @@ -43,7 +42,7 @@ export function Filters(props: IFiltersProps) { !Array.isArray(object) && object !== null && Object.keys(object).map(key => { - const getRadioButton = (isTruthyPicked: boolean): ReactNode => { + const getRadioButton = (isTruthyPicked: boolean): React.ReactNode => { const id = isTruthyPicked ? `radio-defined-${key}` : `radio-not-defined-${key}`; const label = isTruthyPicked ? labelTruthy : labelFalsy; diff --git a/colab-webapp/src/main/node/app/src/components/common/collection/SearchInput.tsx b/colab-webapp/src/main/node/app/src/components/common/collection/SearchInput.tsx index 9c7823f83c9..085c7855083 100644 --- a/colab-webapp/src/main/node/app/src/components/common/collection/SearchInput.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/collection/SearchInput.tsx @@ -1,12 +1,11 @@ import * as React from 'react'; -import { useEffect, useState } from 'react'; import Flex from '../layout/Flex'; import Icon from '../layout/Icon'; function useDebounce(value: string | undefined, delay: number) { - const [debouncedValue, setDebouncedValue] = useState(value); + const [debouncedValue, setDebouncedValue] = React.useState(value); - useEffect(() => { + React.useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); @@ -23,11 +22,11 @@ export interface ISearchProps { } export default function SearchInput(props: ISearchProps) { - const [searchQuery, setSearchQuery] = useState(); + const [searchQuery, setSearchQuery] = React.useState(); const { onChangeSearchQuery } = props; const debouncedSearchQuery = useDebounce(searchQuery, 250); - useEffect(() => { + React.useEffect(() => { if (debouncedSearchQuery !== undefined) { onChangeSearchQuery(debouncedSearchQuery); } diff --git a/colab-webapp/src/main/node/app/src/components/common/collection/SearchSortList.tsx b/colab-webapp/src/main/node/app/src/components/common/collection/SearchSortList.tsx index d380e7bb12b..c40ca4c0dc9 100644 --- a/colab-webapp/src/main/node/app/src/components/common/collection/SearchSortList.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/collection/SearchSortList.tsx @@ -6,7 +6,7 @@ */ import { css } from '@emotion/css'; -import React, { useState } from 'react'; +import * as React from 'react'; import { lightTextStyle, space_sm } from '../../../styling/style'; import Flex from '../layout/Flex'; import { Filters, genericFilter, IFilter } from './Filters'; @@ -60,12 +60,12 @@ interface SearchSortListProps { itemComp: (item: IWidget) => React.ReactNode; } export default function SearchSortList({ widgets, itemComp }: SearchSortListProps): JSX.Element { - const [query, setQuery] = useState(''); - const [activeSorter, setActiveSorter] = useState>({ + const [query, setQuery] = React.useState(''); + const [activeSorter, setActiveSorter] = React.useState>({ property: 'title', isDescending: true, }); - const [activeFilters, setActiveFilters] = useState>>([]); + const [activeFilters, setActiveFilters] = React.useState>>([]); const resultWidgets = widgets .filter((widget: IWidget) => genericSearch(widget, ['title', 'description'], query)) diff --git a/colab-webapp/src/main/node/app/src/components/common/element/Avatar.tsx b/colab-webapp/src/main/node/app/src/components/common/element/Avatar.tsx index 5ce68a16752..0f913e52ad6 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/Avatar.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/Avatar.tsx @@ -7,7 +7,7 @@ import { css, cx } from '@emotion/css'; import { User } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import { br_full, space_lg, space_xs } from '../../../styling/style'; import Flex from '../layout/Flex'; diff --git a/colab-webapp/src/main/node/app/src/components/common/element/Badge.tsx b/colab-webapp/src/main/node/app/src/components/common/element/Badge.tsx index 7ffd9446c32..aa9f277f0c8 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/Badge.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/Badge.tsx @@ -6,7 +6,7 @@ */ import { css, cx } from '@emotion/css'; -import React from 'react'; +import * as React from 'react'; import { MaterialIconsType } from '../../../styling/IconType'; import { br_md, diff --git a/colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx b/colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx index 79516a3fad8..b6724d155fe 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx @@ -7,7 +7,7 @@ import { css, cx } from '@emotion/css'; import { Illustration } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import { MaterialIconsType } from '../../../styling/IconType'; import { space_sm } from '../../../styling/style'; import { defaultProjectIllustration } from '../../projects/ProjectCommon'; diff --git a/colab-webapp/src/main/node/app/src/components/common/layout/DropDownMenu.tsx b/colab-webapp/src/main/node/app/src/components/common/layout/DropDownMenu.tsx index 44763fa7641..bb37b616f44 100644 --- a/colab-webapp/src/main/node/app/src/components/common/layout/DropDownMenu.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/layout/DropDownMenu.tsx @@ -7,7 +7,6 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; -import { useEffect, useRef } from 'react'; import { MaterialIconsType } from '../../../styling/IconType'; import { disabledStyle, foregroundStyle, p_0, p_sm, space_sm } from '../../../styling/style'; import Flex from './Flex'; @@ -344,7 +343,7 @@ export default function DropDownMenu({ }: DropDownMenuProps): JSX.Element { const [open, setOpen] = React.useState(false); - const dropRef = useRef(null); + const dropRef = React.useRef(null); const handleClickOutside = (event: Event) => { if (dropRef.current && !dropRef.current.contains(event.target as Node)) { @@ -352,7 +351,7 @@ export default function DropDownMenu({ } }; - useEffect(() => { + React.useEffect(() => { document.addEventListener('click', handleClickOutside, true); return () => { document.removeEventListener('click', handleClickOutside, true); diff --git a/colab-webapp/src/main/node/app/src/components/common/toplevel/ErrorBoundary.tsx b/colab-webapp/src/main/node/app/src/components/common/toplevel/ErrorBoundary.tsx index c44dff64e1a..839af5f3969 100644 --- a/colab-webapp/src/main/node/app/src/components/common/toplevel/ErrorBoundary.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/toplevel/ErrorBoundary.tsx @@ -5,19 +5,18 @@ * Licensed under the MIT License */ import * as React from 'react'; -import { Component, ErrorInfo, ReactNode } from 'react'; import logger from '../../../logger'; interface Props { - fallback?: ReactNode; - children: ReactNode; + fallback?: React.ReactNode; + children: React.ReactNode; } interface State { hasError: boolean; } -class ErrorBoundary extends Component { +class ErrorBoundary extends React.Component { public state: State = { hasError: false, }; @@ -27,11 +26,11 @@ class ErrorBoundary extends Component { return { hasError: true }; } - public componentDidCatch(error: Error, errorInfo: ErrorInfo): void { + public componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { logger.error('Uncaught error:', error, errorInfo); } - public render(): ReactNode { + public render(): React.ReactNode { if (this.state.hasError) { if (this.props.fallback) { return this.props.fallback; diff --git a/colab-webapp/src/main/node/app/src/components/hooks/mouse.ts b/colab-webapp/src/main/node/app/src/components/hooks/mouse.ts index e8211217290..0e153a5e4f4 100644 --- a/colab-webapp/src/main/node/app/src/components/hooks/mouse.ts +++ b/colab-webapp/src/main/node/app/src/components/hooks/mouse.ts @@ -5,7 +5,7 @@ * Licensed under the MIT License */ -import React from 'react'; +import * as React from 'react'; /** * This function is a virtual click/doubleclick handler. diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx index 9a27283c399..ed18623aaae 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx @@ -1,6 +1,6 @@ import { css, cx } from '@emotion/css'; import { Project } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx index 76dff548e49..e99a2f8f856 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx @@ -8,7 +8,7 @@ import { css, cx } from '@emotion/css'; import { BrowserJsPlumbInstance } from '@jsplumb/browser-ui'; import { Card, CardContent } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import useTranslations from '../../../i18n/I18nContext'; import logger from '../../../logger'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardCreator.tsx b/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardCreator.tsx index dc461b883d6..3d8954c084e 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardCreator.tsx @@ -9,7 +9,7 @@ import { css, cx } from '@emotion/css'; import { BrowserJsPlumbInstance } from '@jsplumb/browser-ui'; import { Connection } from '@jsplumb/core'; import { CardContent } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import logger from '../../../logger'; import { lightIconButtonStyle, space_lg } from '../../../styling/style'; import CardCreator from '../../cards/CardCreator'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardThumb.tsx index 58fe02578af..b6ab71e3a8b 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchyCardThumb.tsx @@ -7,7 +7,7 @@ import { css, cx } from '@emotion/css'; import { Card, CardContent } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import { shallowEqual } from 'react-redux'; import * as API from '../../../API/api'; import useTranslations from '../../../i18n/I18nContext'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchySubContainer.tsx b/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchySubContainer.tsx index db0fdfd6e2f..f819693de4d 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchySubContainer.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/hierarchy/HierarchySubContainer.tsx @@ -8,7 +8,7 @@ import { css } from '@emotion/css'; import { BrowserJsPlumbInstance } from '@jsplumb/browser-ui'; import { Card, CardContent } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import InlineLoading from '../../common/element/InlineLoading'; import { HierarchyCTX } from './Hierarchy'; import HierarchyBranch from './HierarchyBranch'; diff --git a/colab-webapp/src/main/node/app/src/store/selectors/documentSelector.ts b/colab-webapp/src/main/node/app/src/store/selectors/documentSelector.ts index 40f16ddd39c..442d41cecf9 100644 --- a/colab-webapp/src/main/node/app/src/store/selectors/documentSelector.ts +++ b/colab-webapp/src/main/node/app/src/store/selectors/documentSelector.ts @@ -6,7 +6,7 @@ */ import { Document, entityIs } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import * as API from '../../API/api'; import { DocumentOwnership } from '../../components/documents/documentCommonType'; import { useAppDispatch, useAppSelector } from '../hooks'; diff --git a/colab-webapp/src/main/node/app/src/store/selectors/resourceSelector.ts b/colab-webapp/src/main/node/app/src/store/selectors/resourceSelector.ts index 89e82709ac6..094989e829c 100644 --- a/colab-webapp/src/main/node/app/src/store/selectors/resourceSelector.ts +++ b/colab-webapp/src/main/node/app/src/store/selectors/resourceSelector.ts @@ -7,7 +7,7 @@ import { entityIs, Resource, ResourceRef } from 'colab-rest-client'; import { difference, uniq } from 'lodash'; -import React from 'react'; +import * as React from 'react'; import * as API from '../../API/api'; import { isActive1, From d12dab41b3f65465cb4521557e4a65acf1a823c4 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:56:42 +0200 Subject: [PATCH 009/116] remove useless index.html --- colab-webapp/src/main/node/app/index.html | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 colab-webapp/src/main/node/app/index.html diff --git a/colab-webapp/src/main/node/app/index.html b/colab-webapp/src/main/node/app/index.html deleted file mode 100644 index c5d960dcfa7..00000000000 --- a/colab-webapp/src/main/node/app/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - co.LAB - - - - - -
- - - From 865b8b50dc8b76e5b6d905d54966a1bb9ad183af Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Mon, 10 Apr 2023 21:59:07 +0200 Subject: [PATCH 010/116] spaces changes --- colab-webapp/src/main/node/app/public/index.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/colab-webapp/src/main/node/app/public/index.html b/colab-webapp/src/main/node/app/public/index.html index 2211b640585..cb5dbddca96 100644 --- a/colab-webapp/src/main/node/app/public/index.html +++ b/colab-webapp/src/main/node/app/public/index.html @@ -28,11 +28,15 @@ font-family: 'Public Sans', serif; } - p, div, html, body, span { + p, + div, + html, + body, + span { margin: 0; padding: 0; } - + @supports (font-variation-settings: normal) { html { font-family: 'Public Sans', serif; From df222ac21d2b75978c54433d32ea6d5e67ddfa26 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Tue, 11 Apr 2023 15:49:58 +0200 Subject: [PATCH 011/116] about Routing --- .../main/node/app/src/components/AboutColab.tsx | 14 +++----------- .../src/main/node/app/src/components/App.tsx | 2 ++ .../src/main/node/app/src/components/MainApp.tsx | 3 --- .../src/main/node/app/src/components/MainNav.tsx | 2 +- .../authentication/PublicEntranceContainer.tsx | 2 +- 5 files changed, 7 insertions(+), 16 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/AboutColab.tsx b/colab-webapp/src/main/node/app/src/components/AboutColab.tsx index bc329bdf13b..2ab9f433f76 100644 --- a/colab-webapp/src/main/node/app/src/components/AboutColab.tsx +++ b/colab-webapp/src/main/node/app/src/components/AboutColab.tsx @@ -7,30 +7,22 @@ import { css } from '@emotion/css'; import * as React from 'react'; -import { useNavigate } from 'react-router-dom'; import useTranslations from '../i18n/I18nContext'; import { useVersionDetails } from '../store/selectors/configSelector'; import Logo from '../styling/Logo'; import { space_lg } from '../styling/style'; -import IconButton from './common/element/IconButton'; import Flex from './common/layout/Flex'; +/** + * Some informations about the co.LAB platform and the co.LAB project + */ export default function AboutColab(): JSX.Element { const i18n = useTranslations(); - const navigate = useNavigate(); const version = useVersionDetails(); return ( - { - navigate(-1); - }} - className={css({ alignSelf: 'flex-start' })} - /> + } /> } /> } /> } /> } /> - } /> {reconnecting} @@ -184,7 +182,6 @@ export default function MainApp(): JSX.Element { } /> - } /> {reconnecting} diff --git a/colab-webapp/src/main/node/app/src/components/MainNav.tsx b/colab-webapp/src/main/node/app/src/components/MainNav.tsx index ec35ec9ce35..0e5131132dd 100644 --- a/colab-webapp/src/main/node/app/src/components/MainNav.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainNav.tsx @@ -158,7 +158,7 @@ export function UserDropDown({ onlyLogout }: { onlyLogout?: boolean }): JSX.Elem {i18n.common.about} ), - action: () => navigate('/about-colab'), + action: () => window.open(`#/about`, '_blank'), }, ] : []), diff --git a/colab-webapp/src/main/node/app/src/components/authentication/PublicEntranceContainer.tsx b/colab-webapp/src/main/node/app/src/components/authentication/PublicEntranceContainer.tsx index 0d810c9ba96..9504eb0347a 100644 --- a/colab-webapp/src/main/node/app/src/components/authentication/PublicEntranceContainer.tsx +++ b/colab-webapp/src/main/node/app/src/components/authentication/PublicEntranceContainer.tsx @@ -31,7 +31,7 @@ export default function PublicEntranceContainer({ > window.open(`#/about-colab`, '_blank')} + onClick={() => window.open(`#/about`, '_blank')} className={css({ '&:hover': { cursor: 'pointer' } })} > Date: Tue, 11 Apr 2023 15:58:23 +0200 Subject: [PATCH 012/116] comment + reordering --- .../src/main/node/app/src/preferences.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/preferences.ts b/colab-webapp/src/main/node/app/src/preferences.ts index 2e6aa623b36..ae1143edb56 100644 --- a/colab-webapp/src/main/node/app/src/preferences.ts +++ b/colab-webapp/src/main/node/app/src/preferences.ts @@ -5,15 +5,17 @@ * Licensed under the MIT License */ -//import {isEqual} from 'lodash'; +// import {isEqual} from 'lodash'; import * as React from 'react'; -const localStorageKey = 'colab_common'; +// ************************************************************************************************* +// local storage -function getKey(key: string) { - return `${localStorageKey}.${key}`; -} +const localStorageKey = 'colab_common'; +/** + * Keep the user preferences in local storage. + */ export function useLocalStorage( key: string, defaultValue: T, @@ -37,7 +39,7 @@ export function useLocalStorage( // setValue(v); // } // }, [getValue, value]); - // + // React.useEffect(() => { // const cb = onChange; // window.addEventListener('storage', cb); @@ -45,6 +47,12 @@ export function useLocalStorage( // window.removeEventListener('storage', cb); // }; // }, [onChange]) - // + return [value, setValue]; } + +function getKey(key: string) { + return `${localStorageKey}.${key}`; +} + +// ************************************************************************************************* From 3d839c3f306651f830d7a2702f5a56bd3fca15f0 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Tue, 11 Apr 2023 16:03:49 +0200 Subject: [PATCH 013/116] documentation --- colab-webapp/src/main/node/app/src/components/App.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index f8c507a4ceb..08ea972bfdf 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -73,6 +73,9 @@ injectGlobal` } `; +/** + * The React root of everything + */ function App(): JSX.Element { const defaultLanguage = // try to know it from navigator From 9cd691b752bb62ee64ff48e1e4e3c3dcdd0538b0 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Tue, 11 Apr 2023 17:00:46 +0200 Subject: [PATCH 014/116] token routing --- .../src/main/node/app/src/components/App.tsx | 5 +- .../src/components/authentication/SignIn.tsx | 13 ++- .../node/app/src/components/token/Token.tsx | 90 ++++++++++++------- .../app/src/components/token/TokenRouting.tsx | 6 +- colab-webapp/src/main/node/app/src/i18n/en.ts | 14 ++- colab-webapp/src/main/node/app/src/i18n/fr.ts | 14 ++- 6 files changed, 97 insertions(+), 45 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index 08ea972bfdf..d2952b37bf1 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -23,7 +23,7 @@ import ErrorBoundary from './common/toplevel/ErrorBoundary'; import Notifier from './common/toplevel/Notifier'; import MainApp from './MainApp'; import { TocDisplayCtx, TocMode } from './resources/ResourcesList'; -import { TokenWrapper } from './token/TokenRouting'; +import { TokenRouting } from './token/TokenRouting'; injectGlobal` html { @@ -210,8 +210,7 @@ function App(): JSX.Element { } /> - } /> - } /> + } /> - {message && {message}} + {messages && + messages.map(message => { + return ( + + {message} + + ); + })}
('LOADING'); + const [state, setState] = React.useState('LOADING'); const [redirectTo, setRedirectTo] = React.useState(''); const [error, setError] = React.useState(null); + const [infoMessages, setInfoMessages] = React.useState(); + function getTokenErrorHandler(error: WithJsonDiscriminator | Error) { if (error) { if ( @@ -63,9 +67,7 @@ export default function Token(props: TokenProps): JSX.Element { } React.useEffect(() => { - if (props.tokenId && props.token) { - const tokenId = props.tokenId; - const tokenHash = props.token; + if (tokenId && plainToken) { // hack: nest API calls within this hook to avoid setting full token slice if (user.status === 'NOT_INITIALIZED') { // authenticate state not initialized -> reload @@ -85,13 +87,29 @@ export default function Token(props: TokenProps): JSX.Element { if (user.currentUser === null && token.authenticationRequired) { logger.debug('Token requires authentication, current user is not'); setState('AUTH_REQUIRED'); + if (entityIs(token, 'InvitationToken')) { + setInfoMessages([ + i18n.authentication.info.projectInvitationCoLab.part1, + i18n.authentication.info.projectInvitationCoLab.part2, + i18n.authentication.info.projectInvitationCoLab.part3, + i18n.authentication.info.projectInvitationCoLab.part4, + ]); + } + if (entityIs(token, 'ModelSharingToken')) { + setInfoMessages([ + i18n.authentication.info.otherInvitationCoLab.part1, + i18n.authentication.info.otherInvitationCoLab.part2, + i18n.authentication.info.otherInvitationCoLab.part3, + i18n.authentication.info.otherInvitationCoLab.part4, + ]); + } } else { logger.debug('Ready to process the token'); setError(null); const processedToken = await getRestClient().TokenRestEndpoint.consumeToken( +tokenId, - tokenHash, + plainToken, defaultErrorHandler, ); setRedirectTo(processedToken.redirectTo || ''); @@ -118,7 +136,7 @@ export default function Token(props: TokenProps): JSX.Element { } // it seems that there is a problem with getTokenErrorHandler // eslint-disable-next-line react-hooks/exhaustive-deps - }, [dispatch, user, props.tokenId, props.token]); + }, [dispatch, user, tokenId, plainToken]); const errorMessage = React.useMemo(() => { if (error) { @@ -130,18 +148,25 @@ export default function Token(props: TokenProps): JSX.Element { if (state === 'LOADING') { return ; - } else if (state === 'DONE') { + } + + if (state === 'DONE') { return ; - } else if (state === 'AUTH_REQUIRED') { + } + + if (state === 'AUTH_REQUIRED') { const backToTokenUrl = location.pathname; + return ( ); - } else if (state === 'NO_TOKEN') { + } + + if (state === 'NO_TOKEN') { return ( @@ -153,21 +178,22 @@ export default function Token(props: TokenProps): JSX.Element { ); - } else { - return ( - - -

{i18n.common.error.sorryError}

- {errorMessage != null ? ( -

{errorMessage}

- ) : ( -

{i18n.authentication.error.pleaseRefresh}

- )} - -
-
- ); } + + // state === 'ERROR' + return ( + + +

{i18n.common.error.sorryError}

+ {errorMessage != null ? ( +

{errorMessage}

+ ) : ( +

{i18n.authentication.error.pleaseRefresh}

+ )} + +
+
+ ); } diff --git a/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx b/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx index 556d91913d2..24ca43dcc70 100644 --- a/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx +++ b/colab-webapp/src/main/node/app/src/components/token/TokenRouting.tsx @@ -10,10 +10,10 @@ import { useParams } from 'react-router-dom'; import Token from './Token'; /** - * To read parameters from hash + * To read parameters from URL */ -export function TokenWrapper() { +export function TokenRouting() { const { id, token } = useParams<'id' | 'token'>(); - return ; + return ; } diff --git a/colab-webapp/src/main/node/app/src/i18n/en.ts b/colab-webapp/src/main/node/app/src/i18n/en.ts index 538c21352df..37c4773002b 100644 --- a/colab-webapp/src/main/node/app/src/i18n/en.ts +++ b/colab-webapp/src/main/node/app/src/i18n/en.ts @@ -304,8 +304,18 @@ export const en = { pendingInvitation: 'Pending invitation', reconnecting: 'Reconnecting...', checkYourMailbox: 'Check your mailbox!', - invitationCoLab: - "Hi! You have been invited to collaborate on a project in co.LAB. Sign in or create your very own account. Happy colabbin'!", + projectInvitationCoLab: { + part1: 'Hi !', + part2: 'You have been invited to collaborate on a project in co.LAB.', + part3: 'Sign in or create your very own account.', + part4: "Happy colabbin' !", + }, + otherInvitationCoLab: { + part1: 'Hi !', + part2: 'You have been invited to collaborate in co.LAB.', + part3: 'Sign in or create your very own account.', + part4: "Happy colabbin' !", + }, }, error: { emailAddressNotValid: 'E-mail address is not valid', diff --git a/colab-webapp/src/main/node/app/src/i18n/fr.ts b/colab-webapp/src/main/node/app/src/i18n/fr.ts index d87f235c892..adb94bf05b9 100644 --- a/colab-webapp/src/main/node/app/src/i18n/fr.ts +++ b/colab-webapp/src/main/node/app/src/i18n/fr.ts @@ -308,8 +308,18 @@ export const fr: ColabTranslations = { pendingInvitation: 'Invitation en attente', reconnecting: 'Reconnexion...', checkYourMailbox: 'Vérifiez votre boîte mail.', - invitationCoLab: - 'Bonjour ! Vous avez été invité-e à collaborer à un projet co.LAB. Connectez-vous ou créez un compte. Bon co.LAB!', + projectInvitationCoLab: { + part1: 'Bonjour !', + part2: 'Vous avez été invité- e à collaborer à un projet co.LAB.', + part3: 'Connectez - vous ou créez un compte.', + part4: 'Bon co.LAB !', + }, + otherInvitationCoLab: { + part1: 'Bonjour !', + part2: 'Vous avez été invité- e à collaborer sur co.LAB.', + part3: 'Connectez - vous ou créez un compte.', + part4: 'Bon co.LAB !', + }, }, error: { emailAddressNotValid: "L'adresse e-mail n'est pas valide", From bffa35a4ab4bde3e7ebed7cfd5f167cf48f291c5 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Tue, 11 Apr 2023 21:50:29 +0200 Subject: [PATCH 015/116] rename token params --- colab-webapp/src/main/node/app/src/components/App.tsx | 2 +- .../src/main/node/app/src/components/token/TokenRouting.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index d2952b37bf1..091231f06eb 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -210,7 +210,7 @@ function App(): JSX.Element { } /> - } /> + } /> (); + const { tokenId, plainToken } = useParams<'tokenId' | 'plainToken'>(); - return ; + return ; } From cfbda7b53432353e2188fb41e89263e5a03621f7 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Wed, 12 Apr 2023 19:24:22 +0200 Subject: [PATCH 016/116] model sharing routing + notification --- .../api/model/token/ModelSharingToken.java | 2 +- .../main/node/app/src/components/MainApp.tsx | 3 +- .../projects/models/NewModelShared.tsx | 32 ++++++++++++------- colab-webapp/src/main/node/app/src/i18n/en.ts | 1 + colab-webapp/src/main/node/app/src/i18n/fr.ts | 2 ++ 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ModelSharingToken.java b/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ModelSharingToken.java index ec5cd3f8541..b7a95bf9d95 100644 --- a/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ModelSharingToken.java +++ b/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ModelSharingToken.java @@ -132,7 +132,7 @@ public String getRedirectTo() { Project project = getProject(); if (project != null && project.getId() != null) { - return "/newModelShared/" + project.getId(); + return "/new-model-shared/" + project.getId(); } } diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index a3072d55ae7..0af22a7487d 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -164,7 +164,6 @@ export default function MainApp(): JSX.Element { > } /> - } /> } /> } /> } /> @@ -176,6 +175,8 @@ export default function MainApp(): JSX.Element { } /> + {/* this path comes from the server side (ModelSharingToken.java) */} + } /> diff --git a/colab-webapp/src/main/node/app/src/components/projects/models/NewModelShared.tsx b/colab-webapp/src/main/node/app/src/components/projects/models/NewModelShared.tsx index e66f5b0519b..b78f171b713 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/models/NewModelShared.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/models/NewModelShared.tsx @@ -6,18 +6,28 @@ */ import * as React from 'react'; -import PublicEntranceContainer from '../../authentication/PublicEntranceContainer'; -import Flex from '../../common/layout/Flex'; +import { Navigate } from 'react-router-dom'; +import useTranslations from '../../../i18n/I18nContext'; +import { useAppDispatch } from '../../../store/hooks'; +import { addNotification } from '../../../store/slice/notificationSlice'; +/** + * Show a notification that a new model is accessible. + */ export default function NewModelShared(): JSX.Element { - // const i18n = useTranslations(); - // const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const i18n = useTranslations(); + + React.useEffect(() => { + dispatch( + addNotification({ + status: 'OPEN', + type: 'INFO', + message: i18n.modules.project.info.newModelShared, + }), + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - return ( - - -

a new model is shared to you !

-
-
- ); + return ; } diff --git a/colab-webapp/src/main/node/app/src/i18n/en.ts b/colab-webapp/src/main/node/app/src/i18n/en.ts index 56f263ba242..275b94db41d 100644 --- a/colab-webapp/src/main/node/app/src/i18n/en.ts +++ b/colab-webapp/src/main/node/app/src/i18n/en.ts @@ -391,6 +391,7 @@ export const en = { isAModel: 'This is a project model', mailSentToShare: (recipientAddress: string): string => `${recipientAddress} will get an email inviting to use the model`, + newModelShared: 'A new model is shared to you. You can now use it to create a new project.', initialProjectNotFound: 'Initial project not found', }, settings: { diff --git a/colab-webapp/src/main/node/app/src/i18n/fr.ts b/colab-webapp/src/main/node/app/src/i18n/fr.ts index 95444930ce7..b16300e869e 100644 --- a/colab-webapp/src/main/node/app/src/i18n/fr.ts +++ b/colab-webapp/src/main/node/app/src/i18n/fr.ts @@ -397,6 +397,8 @@ export const fr: ColabTranslations = { isAModel: 'Ceci est un modèle de projet', mailSentToShare: (recipientAddress: string): string => `${recipientAddress} va recevoir un email l'invitant à utiliser le modèle`, + newModelShared: + "Un nouveau modèle a été partagé avec vous. Vous pouvez désormais l'utiliser pour créer un nouveau projet.", initialProjectNotFound: "Le projet initial n'a pas pu être trouvé", }, settings: { From a0f383c07de0e2cc3cea4a6176cb05a5230e5261 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Wed, 12 Apr 2023 19:25:15 +0200 Subject: [PATCH 017/116] new project access routing + notification --- .../api/model/token/InvitationToken.java | 2 +- .../main/node/app/src/components/MainApp.tsx | 3 ++ .../components/projects/NewProjectAccess.tsx | 35 +++++++++++++++++++ colab-webapp/src/main/node/app/src/i18n/en.ts | 1 + colab-webapp/src/main/node/app/src/i18n/fr.ts | 1 + 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx diff --git a/colab-api/src/main/java/ch/colabproject/colab/api/model/token/InvitationToken.java b/colab-api/src/main/java/ch/colabproject/colab/api/model/token/InvitationToken.java index aefacf28567..be7598f09bd 100644 --- a/colab-api/src/main/java/ch/colabproject/colab/api/model/token/InvitationToken.java +++ b/colab-api/src/main/java/ch/colabproject/colab/api/model/token/InvitationToken.java @@ -143,7 +143,7 @@ public String getRedirectTo() { // as it will lead to an access denied exception Project project = getProject(); if (project != null && project.getId() != null) { - return "/editor/" + project.getId(); + return "/new-project-access/" + project.getId(); } } return ""; diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index 0af22a7487d..c35244728f5 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -25,6 +25,7 @@ import Overlay from './common/layout/Overlay'; import MainNav from './MainNav'; import Editor from './projects/edition/Editor'; import NewModelShared from './projects/models/NewModelShared'; +import NewProjectAccess from './projects/NewProjectAccess'; import { MyModels, MyProjects } from './projects/ProjectList'; import Settings from './settings/Settings'; @@ -177,6 +178,8 @@ export default function MainApp(): JSX.Element { /> {/* this path comes from the server side (ModelSharingToken.java) */} } /> + {/* this path comes from the server side (InvitationToken.java) */} + } />
diff --git a/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx b/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx new file mode 100644 index 00000000000..da98459823e --- /dev/null +++ b/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx @@ -0,0 +1,35 @@ +/* + * The coLAB project + * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO + * + * Licensed under the MIT License + */ + +import * as React from 'react'; +import { Navigate, useParams } from 'react-router-dom'; +import useTranslations from '../../i18n/I18nContext'; +import { useAppDispatch } from '../../store/hooks'; +import { addNotification } from '../../store/slice/notificationSlice'; + +/** + * Show a notification that a new project is accessible. + */ +export default function NewProjectAccess(): JSX.Element { + const dispatch = useAppDispatch(); + const i18n = useTranslations(); + + const { projectId } = useParams<'projectId'>(); + + React.useEffect(() => { + dispatch( + addNotification({ + status: 'OPEN', + type: 'INFO', + message: i18n.modules.project.info.newProjectAccess, + }), + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ; +} diff --git a/colab-webapp/src/main/node/app/src/i18n/en.ts b/colab-webapp/src/main/node/app/src/i18n/en.ts index 275b94db41d..a9ca8858450 100644 --- a/colab-webapp/src/main/node/app/src/i18n/en.ts +++ b/colab-webapp/src/main/node/app/src/i18n/en.ts @@ -392,6 +392,7 @@ export const en = { mailSentToShare: (recipientAddress: string): string => `${recipientAddress} will get an email inviting to use the model`, newModelShared: 'A new model is shared to you. You can now use it to create a new project.', + newProjectAccess: 'You can now access a new project.', initialProjectNotFound: 'Initial project not found', }, settings: { diff --git a/colab-webapp/src/main/node/app/src/i18n/fr.ts b/colab-webapp/src/main/node/app/src/i18n/fr.ts index b16300e869e..1c5d3d77b67 100644 --- a/colab-webapp/src/main/node/app/src/i18n/fr.ts +++ b/colab-webapp/src/main/node/app/src/i18n/fr.ts @@ -399,6 +399,7 @@ export const fr: ColabTranslations = { `${recipientAddress} va recevoir un email l'invitant à utiliser le modèle`, newModelShared: "Un nouveau modèle a été partagé avec vous. Vous pouvez désormais l'utiliser pour créer un nouveau projet.", + newProjectAccess: 'Vous avez maintenant accès à un nouveau projet.', initialProjectNotFound: "Le projet initial n'a pas pu être trouvé", }, settings: { From bfcbc3ef9d0daf636eb8469460aeb725de5bcb43 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Wed, 12 Apr 2023 19:25:57 +0200 Subject: [PATCH 018/116] reset password routing --- .../colab/api/model/token/ResetLocalAccountPasswordToken.java | 2 +- colab-webapp/src/main/node/app/src/components/MainApp.tsx | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ResetLocalAccountPasswordToken.java b/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ResetLocalAccountPasswordToken.java index cbbd028e567..73bb76b8163 100644 --- a/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ResetLocalAccountPasswordToken.java +++ b/colab-api/src/main/java/ch/colabproject/colab/api/model/token/ResetLocalAccountPasswordToken.java @@ -81,7 +81,7 @@ public void setLocalAccount(LocalAccount localAccount) { @Override public String getRedirectTo() { if (localAccount != null) { - return "/settings/user"; // "/settings/account/" + localAccount.getId(); + return "/go-to-profile"; } else { return ""; } diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index c35244728f5..a637d250885 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -186,6 +186,8 @@ export default function MainApp(): JSX.Element { } /> + {/* this path comes from the server side (ResetLocalAccountPasswordToken.java) */} + } /> {reconnecting} From 301b633e891f6318c8b253c63fa8f73b80425721 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 18:30:51 +0200 Subject: [PATCH 019/116] remove useless ending / --- .../app/src/components/projects/creation/ProjectCreator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx index bfb96d89a6c..18ff518cb22 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx @@ -183,7 +183,7 @@ export default function ProjectCreator({ ).then(payload => { resetCb(); close(); - window.open(`#/editor/${payload.payload}/`, '_blank'); + window.open(`#/editor/${payload.payload}`, '_blank'); stopLoading(); }); } From 1598e6f91d8ea242f35c321b4cb9929cc6a76582 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 18:31:35 +0200 Subject: [PATCH 020/116] id in path explicited + EditorWrapper created --- .../main/node/app/src/components/MainApp.tsx | 75 +++++-------------- .../app/src/components/cards/CardWrapper.tsx | 2 +- .../src/components/projects/ProjectList.tsx | 6 +- .../components/projects/edition/Editor.tsx | 8 +- .../projects/edition/EditorWrapper.tsx | 70 +++++++++++++++++ 5 files changed, 97 insertions(+), 64 deletions(-) create mode 100644 colab-webapp/src/main/node/app/src/components/projects/edition/EditorWrapper.tsx diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index a637d250885..023143357fa 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -4,13 +4,13 @@ * * Licensed under the MIT License */ + import { css } from '@emotion/css'; import * as React from 'react'; import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom'; import * as API from '../API/api'; import useTranslations from '../i18n/I18nContext'; import { useAppDispatch, useAppSelector } from '../store/hooks'; -import { useCurrentProject, useProject } from '../store/selectors/projectSelector'; import { useCurrentUser } from '../store/selectors/userSelector'; import Admin from './admin/Admin'; import ResetPasswordForm from './authentication/ForgotPassword'; @@ -19,67 +19,15 @@ import SignInForm from './authentication/SignIn'; import SignUpForm from './authentication/SignUp'; import InlineLoading from './common/element/InlineLoading'; import Flex from './common/layout/Flex'; -import Icon from './common/layout/Icon'; import Loading from './common/layout/Loading'; import Overlay from './common/layout/Overlay'; import MainNav from './MainNav'; -import Editor from './projects/edition/Editor'; +import EditorWrapper from './projects/edition/EditorWrapper'; import NewModelShared from './projects/models/NewModelShared'; import NewProjectAccess from './projects/NewProjectAccess'; import { MyModels, MyProjects } from './projects/ProjectList'; import Settings from './settings/Settings'; -const EditorWrapper = () => { - const { id: sId } = useParams<'id'>(); - - const id = +sId!; - const i18n = useTranslations(); - const dispatch = useAppDispatch(); - const { project, status } = useProject(+id!); - const { project: editedProject, status: editingStatus } = useCurrentProject(); - - const webSocketId = useAppSelector(state => state.websockets.sessionId); - const socketIdRef = React.useRef(undefined); - - React.useEffect(() => { - if (webSocketId && project != null) { - if (editingStatus === 'NOT_EDITING' || (editedProject != null && editedProject.id !== +id)) { - socketIdRef.current = webSocketId; - dispatch(API.startProjectEdition(project)); - } else if (editingStatus === 'READY') { - if (webSocketId !== socketIdRef.current) { - // ws reconnection occured => reconnect - socketIdRef.current = webSocketId; - dispatch(API.reconnectToProjectChannel(project)); - } - } - } - }, [dispatch, editingStatus, editedProject, project, id, webSocketId]); - - if (status === 'NOT_INITIALIZED' || status === 'LOADING') { - return ; - } else if (project == null || status === 'ERROR') { - return ( -
- - {i18n.modules.project.info.noProject} -
- ); - } else { - if (editingStatus === 'NOT_EDITING' || (editedProject != null && editedProject.id !== +id)) { - return ; - } else { - return ; - } - } -}; - -// A custom hook that builds on useLocation to parse -// the query string for you. -function useQuery() { - return new URLSearchParams(useLocation().search); -} - export default function MainApp(): JSX.Element { const dispatch = useAppDispatch(); const i18n = useTranslations(); @@ -145,7 +93,7 @@ export default function MainApp(): JSX.Element { return ( <> - } /> + } /> } /> } /> } /> - {/* } /> */} + {/* } /> */} (); + + return ; +} + +// A custom hook that builds on useLocation to parse +// the query string for you. +function useQuery() { + return new URLSearchParams(useLocation().search); +} diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardWrapper.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardWrapper.tsx index b137a762fed..fe9747f0047 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardWrapper.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardWrapper.tsx @@ -34,7 +34,7 @@ export default function CardWrapper({ align, }: //backButtonPath, CardWrapperProps): JSX.Element { - const { id, vId } = useParams<'id' | 'vId'>(); + const { cardId: id, vId } = useParams<'cardId' | 'vId'>(); const cardId = +id!; const cardContentId = +vId!; diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx index 33f6c93d4f9..1bdce8b1bc4 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx @@ -149,9 +149,9 @@ function ProjectList({ projects, hideCreationButton }: ProjectListProps) { items={projects.sort((a, b) => compareById(a, b))} className={projectListStyle} thumbnailClassName={projectCardStyle} - onItemClick={item => { - if (item) { - window.open(`#/editor/${item.id}`, '_blank'); + onItemClick={project => { + if (project) { + window.open(`#/editor/${project.id}`, '_blank'); } }} fillThumbnail={item => { diff --git a/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx b/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx index f4d7ef7eaf6..9c614d248c9 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx @@ -144,10 +144,10 @@ export default function Editor(): JSX.Element { } /> } /> - } /> + } /> {/* Zooom on a card */} @@ -157,7 +157,7 @@ export default function Editor(): JSX.Element { /> @@ -177,7 +177,7 @@ export default function Editor(): JSX.Element { } const DefaultVariantDetector = (): JSX.Element => { - const { id } = useParams<'id'>(); + const { cardId: id } = useParams<'cardId'>(); const cardId = +id!; const variant = useDefaultVariant(cardId); diff --git a/colab-webapp/src/main/node/app/src/components/projects/edition/EditorWrapper.tsx b/colab-webapp/src/main/node/app/src/components/projects/edition/EditorWrapper.tsx new file mode 100644 index 00000000000..ca29453da6d --- /dev/null +++ b/colab-webapp/src/main/node/app/src/components/projects/edition/EditorWrapper.tsx @@ -0,0 +1,70 @@ +/* + * The coLAB project + * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO + * + * Licensed under the MIT License + */ +import * as React from 'react'; +import * as API from '../../../API/api'; +import useTranslations from '../../../i18n/I18nContext'; +import { useAppDispatch, useAppSelector } from '../../../store/hooks'; +import { useCurrentProject, useProject } from '../../../store/selectors/projectSelector'; +import AvailabilityStatusIndicator from '../../common/element/AvailabilityStatusIndicator'; +import Icon from '../../common/layout/Icon'; +import Loading from '../../common/layout/Loading'; +import Editor from '../../projects/edition/Editor'; + +interface EditorWrapperProps { + projectId: number | undefined; +} + +export default function EditorWrapper({ projectId }: EditorWrapperProps) { + const i18n = useTranslations(); + const dispatch = useAppDispatch(); + const { project, status } = useProject(projectId!); + const { project: editedProject, status: editingStatus } = useCurrentProject(); + + const webSocketId = useAppSelector(state => state.websockets.sessionId); + const socketIdRef = React.useRef(undefined); + + React.useEffect(() => { + if (webSocketId && project != null) { + if ( + editingStatus === 'NOT_EDITING' || + (editedProject != null && editedProject.id !== projectId) + ) { + socketIdRef.current = webSocketId; + dispatch(API.startProjectEdition(project)); + } else if (editingStatus === 'READY') { + if (webSocketId !== socketIdRef.current) { + // ws reconnection occured => reconnect + socketIdRef.current = webSocketId; + dispatch(API.reconnectToProjectChannel(project)); + } + } + } + }, [dispatch, editingStatus, editedProject, project, projectId, webSocketId]); + + if (projectId == null) { + return ; + } + if (status === 'NOT_INITIALIZED' || status === 'LOADING') { + return ; + } else if (project == null || status === 'ERROR') { + return ( +
+ + {i18n.modules.project.info.noProject} +
+ ); + } else { + if ( + editingStatus === 'NOT_EDITING' || + (editedProject != null && editedProject.id !== projectId) + ) { + return ; + } else { + return ; + } + } +} From 5f67ff23f14e1c91e8ac7672985e1507c27d23e1 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 18:38:29 +0200 Subject: [PATCH 021/116] ReconnectingOverlay --- .../main/node/app/src/components/MainApp.tsx | 27 ++------------ .../src/components/ReconnectingOverlay.tsx | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 colab-webapp/src/main/node/app/src/components/ReconnectingOverlay.tsx diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index 023143357fa..51c568613e3 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -17,7 +17,6 @@ import ResetPasswordForm from './authentication/ForgotPassword'; import ResetPasswordSent from './authentication/ResetPasswordSent'; import SignInForm from './authentication/SignIn'; import SignUpForm from './authentication/SignUp'; -import InlineLoading from './common/element/InlineLoading'; import Flex from './common/layout/Flex'; import Loading from './common/layout/Loading'; import Overlay from './common/layout/Overlay'; @@ -26,6 +25,7 @@ import EditorWrapper from './projects/edition/EditorWrapper'; import NewModelShared from './projects/models/NewModelShared'; import NewProjectAccess from './projects/NewProjectAccess'; import { MyModels, MyProjects } from './projects/ProjectList'; +import ReconnectingOverlay from './ReconnectingOverlay'; import Settings from './settings/Settings'; export default function MainApp(): JSX.Element { @@ -45,26 +45,7 @@ export default function MainApp(): JSX.Element { } }, [currentUserStatus, dispatch]); - const reconnecting = socketId == null && ( - -
- - {i18n.authentication.info.reconnecting} -
-
- ); + const isReconnecting = socketId == null; const query = useQuery(); @@ -85,7 +66,7 @@ export default function MainApp(): JSX.Element { } /> } />
- {reconnecting} + {isReconnecting && } ); } else if (currentUser != null) { @@ -137,7 +118,7 @@ export default function MainApp(): JSX.Element { {/* this path comes from the server side (ResetLocalAccountPasswordToken.java) */} } /> - {reconnecting} + {isReconnecting && } ); } else { diff --git a/colab-webapp/src/main/node/app/src/components/ReconnectingOverlay.tsx b/colab-webapp/src/main/node/app/src/components/ReconnectingOverlay.tsx new file mode 100644 index 00000000000..7fda1cd35d5 --- /dev/null +++ b/colab-webapp/src/main/node/app/src/components/ReconnectingOverlay.tsx @@ -0,0 +1,37 @@ +/* + * The coLAB project + * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO + * + * Licensed under the MIT License + */ + +import { css } from '@emotion/css'; +import * as React from 'react'; +import useTranslations from '../i18n/I18nContext'; +import InlineLoading from './common/element/InlineLoading'; +import Overlay from './common/layout/Overlay'; + +export default function ReconnectingOverlay(): JSX.Element { + const i18n = useTranslations(); + + return ( + +
+ + {i18n.authentication.info.reconnecting} +
+
+ ); +} From 8a4a9aa19463e761cc1dda652301ce16c3c3ee09 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 19:09:23 +0200 Subject: [PATCH 022/116] reordering --- .../src/main/node/app/src/SecurityHelper.ts | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/SecurityHelper.ts b/colab-webapp/src/main/node/app/src/SecurityHelper.ts index c7eb832af1d..adf6e00ea92 100644 --- a/colab-webapp/src/main/node/app/src/SecurityHelper.ts +++ b/colab-webapp/src/main/node/app/src/SecurityHelper.ts @@ -7,21 +7,15 @@ import * as API from 'colab-rest-client'; -function hexToUint8Array(hex: string): Uint8Array { - const bytes = new Uint8Array(hex.length / 2); - - let currentByte = 0; - for (let currentHexChar = 0; currentHexChar < hex.length; currentHexChar += 2) { - bytes[currentByte] = Number.parseInt(hex.substring(currentHexChar, currentHexChar + 2), 16); - currentByte++; +export async function hashPassword( + method: API.AuthMethod['mandatoryMethod'], + salt: string, + password: string, +): Promise { + switch (method) { + case 'PBKDF2WithHmacSHA512_65536_64': + return hashPBKDF2(salt, password, 'SHA-512', 65536, 64 * 8); } - return bytes; -} - -function bytesToHex(bytes: ArrayBuffer): string { - return Array.from(new Uint8Array(bytes)) - .map(byte => byte.toString(16).padStart(2, '0')) - .join(''); } export async function hashPBKDF2( @@ -53,13 +47,19 @@ export async function hashPBKDF2( return bytesToHex(keyBuffer); } -export async function hashPassword( - method: API.AuthMethod['mandatoryMethod'], - salt: string, - password: string, -): Promise { - switch (method) { - case 'PBKDF2WithHmacSHA512_65536_64': - return hashPBKDF2(salt, password, 'SHA-512', 65536, 64 * 8); +function hexToUint8Array(hex: string): Uint8Array { + const bytes = new Uint8Array(hex.length / 2); + + let currentByte = 0; + for (let currentHexChar = 0; currentHexChar < hex.length; currentHexChar += 2) { + bytes[currentByte] = Number.parseInt(hex.substring(currentHexChar, currentHexChar + 2), 16); + currentByte++; } + return bytes; +} + +function bytesToHex(bytes: ArrayBuffer): string { + return Array.from(new Uint8Array(bytes)) + .map(byte => byte.toString(16).padStart(2, '0')) + .join(''); } From e9cc1effce4d17f37f85e3bec9d98edfc77e21cc Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 19:09:35 +0200 Subject: [PATCH 023/116] comment --- colab-webapp/src/main/node/app/src/components/App.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index 091231f06eb..900667380e8 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -177,7 +177,7 @@ function App(): JSX.Element { }> - + + {/* Payara is happy with hash router */} } /> From 013a811d75b3dcccc16595741327637ac727cc8f Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 19:10:31 +0200 Subject: [PATCH 024/116] websocketSelector is created --- .../main/node/app/src/components/MainApp.tsx | 30 ++++++++++++------- .../app/src/components/live/LiveEditor.tsx | 6 ++-- .../app/src/components/live/LiveTextEditor.ts | 5 ++-- .../components/presence/PresenceContext.ts | 5 ++-- .../src/store/selectors/presenceSelector.ts | 7 +++-- .../src/store/selectors/websocketSelector.ts | 21 +++++++++++++ 6 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 colab-webapp/src/main/node/app/src/store/selectors/websocketSelector.ts diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index 51c568613e3..f89630b35a3 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -10,8 +10,9 @@ import * as React from 'react'; import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom'; import * as API from '../API/api'; import useTranslations from '../i18n/I18nContext'; -import { useAppDispatch, useAppSelector } from '../store/hooks'; +import { useAppDispatch } from '../store/hooks'; import { useCurrentUser } from '../store/selectors/userSelector'; +import { useSessionId } from '../store/selectors/websocketSelector'; import Admin from './admin/Admin'; import ResetPasswordForm from './authentication/ForgotPassword'; import ResetPasswordSent from './authentication/ResetPasswordSent'; @@ -34,7 +35,7 @@ export default function MainApp(): JSX.Element { const { currentUser, status: currentUserStatus } = useCurrentUser(); - const socketId = useAppSelector(state => state.websockets.sessionId); + const socketId = useSessionId(); //const { project: projectBeingEdited } = useProjectBeingEdited(); @@ -51,9 +52,13 @@ export default function MainApp(): JSX.Element { if (currentUserStatus === 'NOT_INITIALIZED') { return ; - } else if (currentUserStatus == 'LOADING') { + } + + if (currentUserStatus == 'LOADING') { return ; - } else if (currentUserStatus === 'NOT_AUTHENTICATED') { + } + + if (currentUserStatus === 'NOT_AUTHENTICATED') { return ( <> @@ -69,7 +74,9 @@ export default function MainApp(): JSX.Element { {isReconnecting && } ); - } else if (currentUser != null) { + } + + if (currentUser != null) { // user is authenticated return ( <> @@ -121,13 +128,14 @@ export default function MainApp(): JSX.Element { {isReconnecting && } ); - } else { - return ( - - {i18n.activity.inconsistentState} - - ); } + + // should not happen + return ( + + {i18n.activity.inconsistentState} + + ); } // /** diff --git a/colab-webapp/src/main/node/app/src/components/live/LiveEditor.tsx b/colab-webapp/src/main/node/app/src/components/live/LiveEditor.tsx index 321601becab..d6cfff1d1b7 100644 --- a/colab-webapp/src/main/node/app/src/components/live/LiveEditor.tsx +++ b/colab-webapp/src/main/node/app/src/components/live/LiveEditor.tsx @@ -9,7 +9,8 @@ import { css } from '@emotion/css'; import * as React from 'react'; import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; -import { useAppDispatch, useAppSelector } from '../../store/hooks'; +import { useAppDispatch } from '../../store/hooks'; +import { useSessionId } from '../../store/selectors/websocketSelector'; import { space_sm } from '../../styling/style'; import MarkdownViewer from '../blocks/markdown/MarkdownViewer'; import WysiwygEditor, { TXTFormatToolbarProps } from '../blocks/markdown/WysiwygEditor'; @@ -73,7 +74,8 @@ export default function LiveEditor({ }: LiveEditorProps): JSX.Element { const i18n = useTranslations(); const dispatch = useAppDispatch(); - const liveSession = useAppSelector(state => state.websockets.sessionId); + + const liveSession = useSessionId(); const { currentValue, onChange, status } = useLiveBlock({ atClass: atClass, diff --git a/colab-webapp/src/main/node/app/src/components/live/LiveTextEditor.ts b/colab-webapp/src/main/node/app/src/components/live/LiveTextEditor.ts index 019a9be0956..b34ebb960bc 100644 --- a/colab-webapp/src/main/node/app/src/components/live/LiveTextEditor.ts +++ b/colab-webapp/src/main/node/app/src/components/live/LiveTextEditor.ts @@ -13,6 +13,7 @@ import * as LiveHelper from '../../LiveHelper'; import { getLogger } from '../../logger'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { useChanges } from '../../store/selectors/changeSelector'; +import { useSessionId } from '../../store/selectors/websocketSelector'; //import {ToastClsMarkdownEditor} from '../blocks/markdown/ToastClsMarkdownEditor'; @@ -60,7 +61,7 @@ const subscriptionCounters: Record> = {}; export function useBlock(blockId: number | null | undefined): TextDataBlock | null | undefined { // blockId => number of subscriptions const dispatch = useAppDispatch(); - const webSocketId = useAppSelector(state => state.websockets.sessionId); + const webSocketId = useSessionId(); const socketIdRef = React.useRef(null); // maintain socketId up to date socketIdRef.current = webSocketId || null; @@ -119,7 +120,7 @@ export function useBlock(blockId: number | null | undefined): TextDataBlock | nu } export function useLiveBlock({ atClass, atId, value, revision }: Props): LiveBlockState { - const liveSession = useAppSelector(state => state.websockets.sessionId); + const liveSession = useSessionId(); const changesState = useChanges(atClass, atId); const dispatch = useAppDispatch(); diff --git a/colab-webapp/src/main/node/app/src/components/presence/PresenceContext.ts b/colab-webapp/src/main/node/app/src/components/presence/PresenceContext.ts index 59e7892794d..bf18a1c99ec 100644 --- a/colab-webapp/src/main/node/app/src/components/presence/PresenceContext.ts +++ b/colab-webapp/src/main/node/app/src/components/presence/PresenceContext.ts @@ -11,8 +11,9 @@ import { TouchUserPresence } from 'colab-rest-client'; import { throttle } from 'lodash'; import * as API from '../../API/api'; import { getLogger } from '../../logger'; -import { useAppDispatch, useAppSelector } from '../../store/hooks'; +import { useAppDispatch } from '../../store/hooks'; import { useCurrentProjectId } from '../../store/selectors/projectSelector'; +import { useSessionId } from '../../store/selectors/websocketSelector'; type ShortTouchUserPresence = Omit; @@ -38,7 +39,7 @@ export function usePresenceContext(): PresenceContext { const dispatch = useAppDispatch(); const currentProjectId = useCurrentProjectId(); - const wsSessionId = useAppSelector(state => state.websockets.sessionId); + const wsSessionId = useSessionId(); const presenceRef = React.useRef({}); diff --git a/colab-webapp/src/main/node/app/src/store/selectors/presenceSelector.ts b/colab-webapp/src/main/node/app/src/store/selectors/presenceSelector.ts index 94013f065f5..a43b5bac765 100644 --- a/colab-webapp/src/main/node/app/src/store/selectors/presenceSelector.ts +++ b/colab-webapp/src/main/node/app/src/store/selectors/presenceSelector.ts @@ -13,16 +13,18 @@ import { useAppDispatch, useAppSelector } from '../hooks'; import { InlineAvailabilityStatus } from '../store'; import { useDeepMemo } from './hooks/useDeepMemo'; import { selectCurrentProjectId } from './projectSelector'; +import { useSessionId } from './websocketSelector'; export function usePresence(projectId: number): InlineAvailabilityStatus { const dispatch = useAppDispatch(); + const me = useSessionId(); + const result = useAppSelector(state => { const presenceState = state.presences.projects[projectId]; if (presenceState != null) { // state exists if (presenceState.status === 'READY') { - const me = state.websockets.sessionId; return Object.values(presenceState.presence).filter(p => p.wsSessionId != me); } else { return presenceState.status; @@ -43,11 +45,12 @@ export function usePresence(projectId: number): InlineAvailabilityStatus { if (documentId != null && currentProjectId != null) { const presenceState = state.presences.projects[currentProjectId]; if (presenceState != null) { - const me = state.websockets.sessionId; return Object.values(presenceState.presence).filter( p => p.wsSessionId != me && p.documentId === documentId, ); diff --git a/colab-webapp/src/main/node/app/src/store/selectors/websocketSelector.ts b/colab-webapp/src/main/node/app/src/store/selectors/websocketSelector.ts new file mode 100644 index 00000000000..04d845eb8e2 --- /dev/null +++ b/colab-webapp/src/main/node/app/src/store/selectors/websocketSelector.ts @@ -0,0 +1,21 @@ +/* + * The coLAB project + * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO + * + * Licensed under the MIT License + */ + +import { useAppSelector } from '../hooks'; +import { ColabState } from '../store'; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Select data +//////////////////////////////////////////////////////////////////////////////////////////////////// + +function selectSessionId(state: ColabState) { + return state.websockets.sessionId; +} + +export function useSessionId() { + return useAppSelector(selectSessionId); +} From d31e77224cb89e02140a38f11c29f55f97611734 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Fri, 14 Apr 2023 19:46:33 +0200 Subject: [PATCH 025/116] renaming (+chores) --- .../main/node/app/src/components/MainApp.tsx | 24 ++++++++----------- .../admin/{Admin.tsx => AdminTabs.tsx} | 2 +- ...mentationTab.tsx => DocumentationTabs.tsx} | 4 ++-- .../activityFlow/ActivityFlowCardThumb.tsx | 2 +- ...owChart.tsx => ActivityFlowChartPanel.tsx} | 2 +- .../components/projects/edition/Editor.tsx | 22 ++++++++--------- .../projects/hierarchy/HierarchyBranch.tsx | 2 +- .../hierarchy/HierarchyCardCreator.tsx | 2 +- .../projects/hierarchy/HierarchyCardThumb.tsx | 2 +- .../{Hierarchy.tsx => HierarchyPanel.tsx} | 6 ++--- .../hierarchy/HierarchySubContainer.tsx | 2 +- .../resources/summary/ResourceScope.tsx | 4 ++-- .../{Settings.tsx => SettingsTabs.tsx} | 2 +- 13 files changed, 36 insertions(+), 40 deletions(-) rename colab-webapp/src/main/node/app/src/components/admin/{Admin.tsx => AdminTabs.tsx} (97%) rename colab-webapp/src/main/node/app/src/components/projects/{DocumentationTab.tsx => DocumentationTabs.tsx} (96%) rename colab-webapp/src/main/node/app/src/components/projects/activityFlow/{ActivityFlowChart.tsx => ActivityFlowChartPanel.tsx} (99%) rename colab-webapp/src/main/node/app/src/components/projects/hierarchy/{Hierarchy.tsx => HierarchyPanel.tsx} (99%) rename colab-webapp/src/main/node/app/src/components/settings/{Settings.tsx => SettingsTabs.tsx} (98%) diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index f89630b35a3..9ef1506173e 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -13,7 +13,7 @@ import useTranslations from '../i18n/I18nContext'; import { useAppDispatch } from '../store/hooks'; import { useCurrentUser } from '../store/selectors/userSelector'; import { useSessionId } from '../store/selectors/websocketSelector'; -import Admin from './admin/Admin'; +import AdminTabs from './admin/AdminTabs'; import ResetPasswordForm from './authentication/ForgotPassword'; import ResetPasswordSent from './authentication/ResetPasswordSent'; import SignInForm from './authentication/SignIn'; @@ -27,18 +27,16 @@ import NewModelShared from './projects/models/NewModelShared'; import NewProjectAccess from './projects/NewProjectAccess'; import { MyModels, MyProjects } from './projects/ProjectList'; import ReconnectingOverlay from './ReconnectingOverlay'; -import Settings from './settings/Settings'; +import SettingsTabs from './settings/SettingsTabs'; export default function MainApp(): JSX.Element { const dispatch = useAppDispatch(); const i18n = useTranslations(); - const { currentUser, status: currentUserStatus } = useCurrentUser(); - const socketId = useSessionId(); + const isReconnecting = socketId == null; - //const { project: projectBeingEdited } = useProjectBeingEdited(); - + const { currentUser, status: currentUserStatus } = useCurrentUser(); React.useEffect(() => { if (currentUserStatus == 'NOT_INITIALIZED') { // user is not known. Reload state from API @@ -46,8 +44,6 @@ export default function MainApp(): JSX.Element { } }, [currentUserStatus, dispatch]); - const isReconnecting = socketId == null; - const query = useQuery(); if (currentUserStatus === 'NOT_INITIALIZED') { @@ -81,7 +77,7 @@ export default function MainApp(): JSX.Element { return ( <> - } /> + } /> } /> } /> } /> - } /> - } /> + } /> + } /> {/* } /> */} } /> - {/* this path comes from the server side (ModelSharingToken.java) */} - } /> {/* this path comes from the server side (InvitationToken.java) */} } /> + {/* this path comes from the server side (ModelSharingToken.java) */} + } /> @@ -141,7 +137,7 @@ export default function MainApp(): JSX.Element { // /** // * To read parameters from URL // */ -function ProjectRouting() { +function EditorRouting() { const { projectId } = useParams<'projectId'>(); return ; diff --git a/colab-webapp/src/main/node/app/src/components/admin/Admin.tsx b/colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx similarity index 97% rename from colab-webapp/src/main/node/app/src/components/admin/Admin.tsx rename to colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx index abe18832250..e68b99a7245 100644 --- a/colab-webapp/src/main/node/app/src/components/admin/Admin.tsx +++ b/colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx @@ -21,7 +21,7 @@ import LoggersConfig from './LoggersConfig'; import MainPanel from './MainPanel'; import Who from './Who'; -export default function Admin(): JSX.Element { +export default function AdminTabs(): JSX.Element { const i18n = useTranslations(); const navigate = useNavigate(); diff --git a/colab-webapp/src/main/node/app/src/components/projects/DocumentationTab.tsx b/colab-webapp/src/main/node/app/src/components/projects/DocumentationTabs.tsx similarity index 96% rename from colab-webapp/src/main/node/app/src/components/projects/DocumentationTab.tsx rename to colab-webapp/src/main/node/app/src/components/projects/DocumentationTabs.tsx index daa56b0b796..efbd56622d3 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/DocumentationTab.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/DocumentationTabs.tsx @@ -25,11 +25,11 @@ import { ResourcesMainViewPanel, } from '../resources/ResourcesMainView'; -interface DocumentationTabProps { +interface DocumentationTabsProps { project: Project; } -export default function DocumentationTab({ project }: DocumentationTabProps): JSX.Element { +export default function DocumentationTabs({ project }: DocumentationTabsProps): JSX.Element { const i18n = useTranslations(); const tipsConfig = React.useContext(TipsCtx); diff --git a/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx index e99a2f8f856..1290af80119 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowCardThumb.tsx @@ -19,7 +19,7 @@ import { ProgressBar } from '../../cards/ProgressBar'; import VariantSelector from '../../cards/VariantSelector'; import Flex from '../../common/layout/Flex'; import Icon from '../../common/layout/Icon'; -import { AFPlumbRef } from './ActivityFlowChart'; +import { AFPlumbRef } from './ActivityFlowChartPanel'; const cardStyle = css({ zIndex: 1, diff --git a/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowChart.tsx b/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowChartPanel.tsx similarity index 99% rename from colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowChart.tsx rename to colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowChartPanel.tsx index 652ab91f903..3da38355773 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowChart.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/activityFlow/ActivityFlowChartPanel.tsx @@ -51,7 +51,7 @@ export interface AFPlumbRef { connections: Record; } -export default function ActivityFlowChart(): JSX.Element { +export default function ActivityFlowChartPanel(): JSX.Element { const dispatch = useAppDispatch(); /* const i18n = useTranslations(); */ const currentProjectId = useCurrentProjectId(); diff --git a/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx b/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx index 9c614d248c9..2479876e328 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/edition/Editor.tsx @@ -14,19 +14,19 @@ import useTranslations from '../../../i18n/I18nContext'; import { useAppDispatch, useAppSelector } from '../../../store/hooks'; import { useDefaultVariant, useProjectRootCard } from '../../../store/selectors/cardSelector'; import { selectCurrentProject } from '../../../store/selectors/projectSelector'; -import Admin from '../../admin/Admin'; +import AdminTabs from '../../admin/AdminTabs'; import CardEditor from '../../cards/CardEditor'; import RootView from '../../cards/CardRootView'; import CardWrapper from '../../cards/CardWrapper'; import InlineLoading from '../../common/element/InlineLoading'; import Flex from '../../common/layout/Flex'; import { PresenceContext, usePresenceContext } from '../../presence/PresenceContext'; -import Settings from '../../settings/Settings'; +import SettingsTabs from '../../settings/SettingsTabs'; import ProjectTasksPanel from '../../team/ProjectTasksList'; import TeamTabs from '../../team/TeamTabs'; -import ActivityFlowChart from '../activityFlow/ActivityFlowChart'; -import DocumentationTab from '../DocumentationTab'; -import Hierarchy from '../hierarchy/Hierarchy'; +import ActivityFlowChartPanel from '../activityFlow/ActivityFlowChartPanel'; +import DocumentationTabs from '../DocumentationTabs'; +import HierarchyPanel from '../hierarchy/HierarchyPanel'; import { ProjectNav } from '../ProjectNav'; import { ProjectSettingsTabs } from '../settings/ProjectSettingsTabs'; import ProjectSidePanelWrapper from '../SidePanelWrapper'; @@ -125,7 +125,7 @@ export default function Editor(): JSX.Element { path="docs/*" element={ - + } /> @@ -139,13 +139,13 @@ export default function Editor(): JSX.Element { /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> } /> - {/* Zooom on a card */} +

{i18n.modules.resource.scope.mainViewTitle}

{i18n.modules.resource.scope.mainViewDesc}
- Date: Tue, 18 Jul 2023 17:24:05 +0200 Subject: [PATCH 026/116] remove admin from user drop down (regression) --- .../src/main/node/app/src/components/MainNav.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/MainNav.tsx b/colab-webapp/src/main/node/app/src/components/MainNav.tsx index 61843796eef..7c3eda358de 100644 --- a/colab-webapp/src/main/node/app/src/components/MainNav.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainNav.tsx @@ -143,19 +143,6 @@ export function UserDropDown(): JSX.Element { ), action: () => navigate('./settings'), }, - ...(currentUser.admin - ? [ - { - value: 'admin', - label: ( - <> - {i18n.admin.admin} - - ), - action: () => navigate('./admin'), - }, - ] - : []), { value: 'about', label: ( From 16d2ec031fa98ebd59c1b064db58cea0f9dd31d9 Mon Sep 17 00:00:00 2001 From: Sandra Monnier Date: Tue, 18 Jul 2023 17:26:19 +0200 Subject: [PATCH 027/116] main nav fix regression --- .../src/main/node/app/src/components/MainNav.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/MainNav.tsx b/colab-webapp/src/main/node/app/src/components/MainNav.tsx index 7c3eda358de..61f03ae648d 100644 --- a/colab-webapp/src/main/node/app/src/components/MainNav.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainNav.tsx @@ -143,15 +143,6 @@ export function UserDropDown(): JSX.Element { ), action: () => navigate('./settings'), }, - { - value: 'about', - label: ( - <> - {i18n.common.about} - - ), - action: () => window.open(`#/about`, '_blank'), - }, { value: 'language', label: ( @@ -181,7 +172,7 @@ export function UserDropDown(): JSX.Element { {i18n.common.about} ), - action: () => navigate('/about-colab'), + action: () => window.open(`#/about`, '_blank'), }, { value: 'logout', From 67bc537a3db05c70022be15b3612ecfa511e8f97 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Mon, 27 Nov 2023 22:14:09 +0100 Subject: [PATCH 028/116] strictly use import * as React --- .../main/node/app/src/components/cards/StatusDropDown.tsx | 2 +- .../src/components/documents/texteditor/nodes/FileNode.tsx | 2 +- .../texteditor/plugins/ToolbarPlugin/FormatDropDown.tsx | 2 +- .../main/node/app/src/components/team/MassMemberCreator.tsx | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/cards/StatusDropDown.tsx b/colab-webapp/src/main/node/app/src/components/cards/StatusDropDown.tsx index 263181b87a0..4338badbaff 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/StatusDropDown.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/StatusDropDown.tsx @@ -7,7 +7,7 @@ import { css, cx } from '@emotion/css'; import { CardContent } from 'colab-rest-client'; -import React from 'react'; +import * as React from 'react'; import { iconButtonStyle, p_xs } from '../../styling/style'; import DropDownMenu from '../common/layout/DropDownMenu'; import CardContentStatusDisplay from './CardContentStatusDisplay'; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/nodes/FileNode.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/nodes/FileNode.tsx index bd3b7a248e3..0c3a15baf6f 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/nodes/FileNode.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/nodes/FileNode.tsx @@ -17,7 +17,7 @@ import { SerializedLexicalNode, Spread, } from 'lexical'; -import React from 'react'; +import * as React from 'react'; import * as API from '../../../../API/api'; const FileComponent = React.lazy(() => import('./FileComponent')); diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/FormatDropDown.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/FormatDropDown.tsx index 604cb14f705..ceb7dedf8f8 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/FormatDropDown.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/FormatDropDown.tsx @@ -16,7 +16,7 @@ import { DEPRECATED_$isGridSelection, LexicalEditor, } from 'lexical'; -import React from 'react'; +import * as React from 'react'; import useTranslations from '../../../../../i18n/I18nContext'; import { MaterialIconsType } from '../../../../../styling/IconType'; import { ghostIconButtonStyle, iconButtonStyle, space_xs } from '../../../../../styling/style'; diff --git a/colab-webapp/src/main/node/app/src/components/team/MassMemberCreator.tsx b/colab-webapp/src/main/node/app/src/components/team/MassMemberCreator.tsx index 0b2707255ca..df6bf1d94e9 100644 --- a/colab-webapp/src/main/node/app/src/components/team/MassMemberCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/team/MassMemberCreator.tsx @@ -6,7 +6,7 @@ */ import { css, cx } from '@emotion/css'; -import React, { useCallback } from 'react'; +import * as React from 'react'; import * as API from '../../API/api'; import { assertEmailFormat } from '../../helper'; import useTranslations from '../../i18n/I18nContext'; @@ -33,11 +33,11 @@ export default function MassMemberCreator({ mode }: MassMemberCreatorProps): JSX const [inputValue, setInputValue] = React.useState(''); const [invalidEmails, setInvalidEmails] = React.useState([]); - const isValidEmail = useCallback((email: string) => { + const isValidEmail = React.useCallback((email: string) => { return email.length > 0 && assertEmailFormat(email); }, []); - const validateEmails = useCallback( + const validateEmails = React.useCallback( (emails: string[]): boolean => { let error = false; From 8d680bc04cfb85fa4e30f29081d5f21bcef9305c Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Mon, 27 Nov 2023 22:48:24 +0100 Subject: [PATCH 029/116] add param types --- .../src/main/node/app/src/components/common/element/Form.tsx | 2 +- .../main/node/app/src/components/settings/LocalAccount.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/common/element/Form.tsx b/colab-webapp/src/main/node/app/src/components/common/element/Form.tsx index 5955357cf7e..6ea4dda50df 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/Form.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/Form.tsx @@ -236,7 +236,7 @@ export default function Form({ { + onChangeScore={(value: number, feedback: PasswordFeedback) => { if (field.strengthProp != null) { setFormValue(field.strengthProp, { score: value, feedback: feedback }); } diff --git a/colab-webapp/src/main/node/app/src/components/settings/LocalAccount.tsx b/colab-webapp/src/main/node/app/src/components/settings/LocalAccount.tsx index 8656109f279..10fb098e41b 100644 --- a/colab-webapp/src/main/node/app/src/components/settings/LocalAccount.tsx +++ b/colab-webapp/src/main/node/app/src/components/settings/LocalAccount.tsx @@ -7,7 +7,7 @@ import { css } from '@emotion/css'; import * as React from 'react'; -import PasswordStrengthBar from 'react-password-strength-bar'; +import PasswordStrengthBar, { PasswordFeedback } from 'react-password-strength-bar'; import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; @@ -66,7 +66,7 @@ export default function LocalAccount(props: LocalAccountProps): JSX.Element { {score != null ? : null} { + onChangeScore={(score: number, feedback: PasswordFeedback) => { setScore({ score: score as unknown as PasswordScore['score'], feedback: feedback, From 352bd6b970db2614d3e7bd2dcd281d5abf61a147 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Mon, 27 Nov 2023 22:56:28 +0100 Subject: [PATCH 030/116] remove unused suppressXXXError config --- .../src/main/resources/templates/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/client-generator-plugin/src/main/resources/templates/tsconfig.json b/client-generator-plugin/src/main/resources/templates/tsconfig.json index 6477e420a70..378397e1d87 100644 --- a/client-generator-plugin/src/main/resources/templates/tsconfig.json +++ b/client-generator-plugin/src/main/resources/templates/tsconfig.json @@ -8,7 +8,6 @@ "strict": true, "moduleResolution": "node", "allowSyntheticDefaultImports": true, - "suppressImplicitAnyIndexErrors": true, "declaration": true }, "files": [ From f5be0c0f354c84773550d52c746ed34c6d7f4088 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Mon, 27 Nov 2023 23:19:04 +0100 Subject: [PATCH 031/116] organize imports --- .../src/components/blocks/markdown/WysiwygEditor.tsx | 12 ++++++------ .../app/src/components/cardtypes/CardTypeCreator.tsx | 2 +- .../cardtypes/summary/TargetCardTypeSummary.tsx | 2 +- .../node/app/src/components/debugger/debugger.tsx | 2 +- .../components/documents/DocumentCreatorButton.tsx | 2 +- .../components/documents/DocumentEditorToolbox.tsx | 2 +- .../app/src/components/documents/DocumentList.tsx | 2 +- .../documents/texteditor/plugins/CardLinkPlugin.tsx | 2 +- .../documents/texteditor/plugins/FilesPlugin.tsx | 2 +- .../FloatingLinkEditorPlugin.tsx | 2 +- .../FloatingTextFormatPlugin.tsx | 2 +- .../documents/texteditor/plugins/ImagesPlugin.tsx | 2 +- .../plugins/ListPlugin/CustomCheckListPlugin.tsx | 2 +- .../plugins/TablePlugin/TableActionMenuPlugin.tsx | 2 +- .../texteditor/plugins/ToolbarPlugin/Converter.tsx | 2 +- .../projects/creation/ProjectDataInitialization.tsx | 2 +- .../src/components/projects/listView/CardView.tsx | 2 +- .../resources/summary/TargetResourceSummary.tsx | 2 +- .../src/main/node/app/src/components/team/Rights.tsx | 2 +- .../main/node/app/src/components/team/TeamTabs.tsx | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/blocks/markdown/WysiwygEditor.tsx b/colab-webapp/src/main/node/app/src/components/blocks/markdown/WysiwygEditor.tsx index f225b7c82a1..af9e56e415b 100644 --- a/colab-webapp/src/main/node/app/src/components/blocks/markdown/WysiwygEditor.tsx +++ b/colab-webapp/src/main/node/app/src/components/blocks/markdown/WysiwygEditor.tsx @@ -21,14 +21,14 @@ import { DocEditorCtx } from '../../documents/DocumentEditorToolbox'; import { createCaret, getUserColor } from '../../presence/Presence'; import { PresenceContext } from '../../presence/PresenceContext'; import { + MajorTag, + MinorTag, areAllLeafsWrappedByTag, boundedClosest, findChildByTag, findNextLeaf, indentListItem, - MajorTag, majorTags, - MinorTag, moveToLeaf, sortNodes, switchTo, @@ -36,21 +36,21 @@ import { unindentListItem, } from './DomHelper'; import { + LinkOverlay, colabFlavouredMarkdown, colabFlavouredMarkdownEditable, computeOverlayPosition, - LinkOverlay, } from './MarkdownViewer'; import domToMarkdown, { - escapeText, MarkdownRange, MarkdownWithSelection, + escapeText, } from './parser/domToMarkdown'; import markdownToDom, { - convertRange, - getFirstMajorTag, MajorTagParsed, NodesAndOffsets, + convertRange, + getFirstMajorTag, } from './parser/markdownToDom'; const logger = getLogger('WysiwygEditor'); diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeCreator.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeCreator.tsx index be8d5a35799..3da243b23a0 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeCreator.tsx @@ -17,7 +17,7 @@ import { import { useCurrentProjectId } from '../../store/selectors/projectSelector'; import { buttonStyle, space_lg } from '../../styling/style'; import Button from '../common/element/Button'; -import Form, { createSelectField, Field } from '../common/element/Form'; +import Form, { Field, createSelectField } from '../common/element/Form'; import Icon from '../common/layout/Icon'; import OpenModalOnClick from '../common/layout/OpenModalOnClick'; diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/summary/TargetCardTypeSummary.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/summary/TargetCardTypeSummary.tsx index 87c9604d046..9f55dc2dd83 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/summary/TargetCardTypeSummary.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/summary/TargetCardTypeSummary.tsx @@ -10,10 +10,10 @@ import { entityIs } from 'colab-rest-client'; import * as React from 'react'; import useTranslations from '../../../i18n/I18nContext'; import { useProject } from '../../../store/selectors/projectSelector'; +import { MaterialIconsType } from '../../../styling/IconType'; import { space_sm } from '../../../styling/style'; import { CardTypeAllInOne as CardType } from '../../../types/cardTypeDefinition'; import Icon from '../../common/layout/Icon'; -import { MaterialIconsType } from '../../../styling/IconType'; export const referenceIcon = 'star'; diff --git a/colab-webapp/src/main/node/app/src/components/debugger/debugger.tsx b/colab-webapp/src/main/node/app/src/components/debugger/debugger.tsx index 0be0ce78bb5..76dc0b3132b 100644 --- a/colab-webapp/src/main/node/app/src/components/debugger/debugger.tsx +++ b/colab-webapp/src/main/node/app/src/components/debugger/debugger.tsx @@ -14,10 +14,10 @@ import SearchSortList, { IWidget } from '../common/collection/SearchSortList'; import AvailabilityStatusIndicator from '../common/element/AvailabilityStatusIndicator'; import Icon from '../common/layout/Icon'; import Tabs, { Tab } from '../common/layout/Tabs'; -import DebugForm from './debugForm'; import DebugInput from './DebugInput'; import DebugLoading from './DebugLoading'; import PlayWithGridOrganizer from './PlayWithGridOrganizer'; +import DebugForm from './debugForm'; export default function Debugger(): JSX.Element { const cards = useAllProjectCards(); diff --git a/colab-webapp/src/main/node/app/src/components/documents/DocumentCreatorButton.tsx b/colab-webapp/src/main/node/app/src/components/documents/DocumentCreatorButton.tsx index 5dd3495eb8f..978b52c7ac6 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/DocumentCreatorButton.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/DocumentCreatorButton.tsx @@ -13,8 +13,8 @@ import { useAppDispatch } from '../../store/hooks'; import { MaterialIconsType } from '../../styling/IconType'; import IconButton from '../common/element/IconButton'; import DropDownMenu from '../common/layout/DropDownMenu'; -import { DocumentKind, DocumentOwnership } from './documentCommonType'; import { DocEditorCtx } from './DocumentEditorToolbox'; +import { DocumentKind, DocumentOwnership } from './documentCommonType'; function iconByType(docKind: DocumentKind): MaterialIconsType { if (docKind === 'DocumentFile') { diff --git a/colab-webapp/src/main/node/app/src/components/documents/DocumentEditorToolbox.tsx b/colab-webapp/src/main/node/app/src/components/documents/DocumentEditorToolbox.tsx index 72ae29b3597..f2461e43896 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/DocumentEditorToolbox.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/DocumentEditorToolbox.tsx @@ -20,8 +20,8 @@ import ConfirmDeleteOpenCloseModal from '../common/layout/ConfirmDeleteModal'; import DropDownMenu from '../common/layout/DropDownMenu'; import Flex from '../common/layout/Flex'; import Icon from '../common/layout/Icon'; -import { DocumentOwnership } from './documentCommonType'; import DocumentCreatorButton from './DocumentCreatorButton'; +import { DocumentOwnership } from './documentCommonType'; const toolboxContainerStyle = css({ height: 'auto', diff --git a/colab-webapp/src/main/node/app/src/components/documents/DocumentList.tsx b/colab-webapp/src/main/node/app/src/components/documents/DocumentList.tsx index 2d9b220f9d8..de7164ee932 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/DocumentList.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/DocumentList.tsx @@ -11,8 +11,8 @@ import useTranslations from '../../i18n/I18nContext'; import { useAndLoadDocuments } from '../../store/selectors/documentSelector'; import { lightTextStyle, space_lg, space_sm, text_sm } from '../../styling/style'; import AvailabilityStatusIndicator from '../common/element/AvailabilityStatusIndicator'; -import { DocumentOwnership } from './documentCommonType'; import DocumentEditor from './DocumentEditor'; +import { DocumentOwnership } from './documentCommonType'; export interface DocumentListProps { docOwnership: DocumentOwnership; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/CardLinkPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/CardLinkPlugin.tsx index 31edc7b15b5..f137099f668 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/CardLinkPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/CardLinkPlugin.tsx @@ -8,7 +8,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $insertNodeToNearestRoot, mergeRegister } from '@lexical/utils'; import { Card } from 'colab-rest-client'; -import { COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand, LexicalEditor } from 'lexical'; +import { COMMAND_PRIORITY_EDITOR, LexicalCommand, LexicalEditor, createCommand } from 'lexical'; import * as React from 'react'; import useTranslations from '../../../../i18n/I18nContext'; import CardSelector from '../../../cards/CardSelector'; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FilesPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FilesPlugin.tsx index eb5dae9f33a..4b48436f94a 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FilesPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FilesPlugin.tsx @@ -10,10 +10,10 @@ import { $insertNodeToNearestRoot, mergeRegister } from '@lexical/utils'; import { $getNodeByKey, COMMAND_PRIORITY_EDITOR, - createCommand, LexicalCommand, LexicalEditor, NodeKey, + createCommand, } from 'lexical'; import * as React from 'react'; import { useEffect, useState } from 'react'; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx index 8e363142b3a..7376f938be7 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx @@ -33,7 +33,7 @@ import Icon from '../../../../common/layout/Icon'; import { getSelectedNode } from '../../utils/getSelectedNode'; import { setFloatingElemPosition } from '../../utils/setFloatingElemPosition'; import { sanitizeUrl } from '../../utils/url'; -import { activeToolbarButtonStyle, TOGGLE_LINK_MENU_COMMAND } from '../ToolbarPlugin/ToolbarPlugin'; +import { TOGGLE_LINK_MENU_COMMAND, activeToolbarButtonStyle } from '../ToolbarPlugin/ToolbarPlugin'; import { floatingToolbarStyle } from './FloatingTextFormatPlugin'; const linkStyle = css({ diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingTextFormatPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingTextFormatPlugin.tsx index 21fa68181cf..c7adc201b5d 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingTextFormatPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingTextFormatPlugin.tsx @@ -26,7 +26,7 @@ import IconButton from '../../../../common/element/IconButton'; import { getDOMRangeRect } from '../../utils/getDOMRangeRect'; import { getSelectedNode } from '../../utils/getSelectedNode'; import { setFloatingElemPosition } from '../../utils/setFloatingElemPosition'; -import { activeToolbarButtonStyle, TOGGLE_LINK_MENU_COMMAND } from '../ToolbarPlugin/ToolbarPlugin'; +import { TOGGLE_LINK_MENU_COMMAND, activeToolbarButtonStyle } from '../ToolbarPlugin/ToolbarPlugin'; export const floatingToolbarStyle = css({ display: 'flex', diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx index dad3210f9e5..ba31748ad6e 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx @@ -17,12 +17,12 @@ import { COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, - createCommand, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, LexicalCommand, LexicalEditor, + createCommand, } from 'lexical'; import * as React from 'react'; import { useEffect } from 'react'; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ListPlugin/CustomCheckListPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ListPlugin/CustomCheckListPlugin.tsx index 112b3fb9d4a..d473151e60d 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ListPlugin/CustomCheckListPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ListPlugin/CustomCheckListPlugin.tsx @@ -22,7 +22,7 @@ import type { ListItemNode } from '@lexical/list'; import type { LexicalEditor } from 'lexical'; -import { $isListItemNode, $isListNode, insertList, INSERT_CHECK_LIST_COMMAND } from '@lexical/list'; +import { $isListItemNode, $isListNode, INSERT_CHECK_LIST_COMMAND, insertList } from '@lexical/list'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $findMatchingParent, isHTMLElement, mergeRegister } from '@lexical/utils'; import { diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/TablePlugin/TableActionMenuPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/TablePlugin/TableActionMenuPlugin.tsx index eed51b323af..98667a06728 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/TablePlugin/TableActionMenuPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/TablePlugin/TableActionMenuPlugin.tsx @@ -19,10 +19,10 @@ import { $isTableCellNode, $isTableRowNode, $removeTableRowAtIndex, - getTableSelectionFromTableElement, HTMLTableElementWithWithTableSelectionState, TableCellHeaderStates, TableCellNode, + getTableSelectionFromTableElement, } from '@lexical/table'; import { $getRoot, $getSelection, $isRangeSelection, DEPRECATED_$isGridSelection } from 'lexical'; import * as React from 'react'; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/Converter.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/Converter.tsx index 4071fb8154e..29d267feed6 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/Converter.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/Converter.tsx @@ -18,7 +18,7 @@ import { useCurrentUser } from '../../../../../store/selectors/userSelector'; import IconButton from '../../../../common/element/IconButton'; import { useMustBeConverted } from '../../../../hooks/lexicalConversion'; import { DocumentOwnership } from '../../../documentCommonType'; -import { activeToolbarButtonStyle, Divider } from './ToolbarPlugin'; +import { Divider, activeToolbarButtonStyle } from './ToolbarPlugin'; export default function ConverterPlugin(docOwnership: DocumentOwnership) { const dispatch = useAppDispatch(); diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx index 29543664266..2b105e7543b 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx @@ -11,9 +11,9 @@ import * as React from 'react'; import { assertEmailFormat } from '../../../helper'; import useTranslations from '../../../i18n/I18nContext'; import { + OutlineButtonStyle, labelStyle, lightIconButtonStyle, - OutlineButtonStyle, space_lg, space_sm, text_sm, diff --git a/colab-webapp/src/main/node/app/src/components/projects/listView/CardView.tsx b/colab-webapp/src/main/node/app/src/components/projects/listView/CardView.tsx index d514ff25371..6d31533bdab 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/listView/CardView.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/listView/CardView.tsx @@ -16,6 +16,7 @@ import { useAppDispatch } from '../../../store/hooks'; import { useDefaultVariant } from '../../../store/selectors/cardSelector'; import { heading_sm, space_sm } from '../../../styling/style'; import StatusDropDown from '../../cards/StatusDropDown'; +import DeletionStatusIndicator from '../../common/element/DeletionStatusIndicator'; import IconButton from '../../common/element/IconButton'; import InlineLoading from '../../common/element/InlineLoading'; import { DiscreetInput } from '../../common/element/Input'; @@ -24,7 +25,6 @@ import Flex from '../../common/layout/Flex'; import { DocumentOwnership } from '../../documents/documentCommonType'; import TextEditorWrapper from '../../documents/texteditor/TextEditorWrapper'; import ListView from './ListView'; -import DeletionStatusIndicator from '../../common/element/DeletionStatusIndicator'; interface CardViewProps { card: Card; diff --git a/colab-webapp/src/main/node/app/src/components/resources/summary/TargetResourceSummary.tsx b/colab-webapp/src/main/node/app/src/components/resources/summary/TargetResourceSummary.tsx index 9c80fde129c..cabbcfd22ef 100644 --- a/colab-webapp/src/main/node/app/src/components/resources/summary/TargetResourceSummary.tsx +++ b/colab-webapp/src/main/node/app/src/components/resources/summary/TargetResourceSummary.tsx @@ -15,8 +15,8 @@ import { useCurrentProject, useProject } from '../../../store/selectors/projectS import { referenceIcon } from '../../cardtypes/summary/TargetCardTypeSummary'; import Icon from '../../common/layout/Icon'; -import { ResourceAndRef } from '../resourcesCommonType'; import { MaterialIconsType } from '../../../styling/IconType'; +import { ResourceAndRef } from '../resourcesCommonType'; type ShowText = 'tooltip' | 'short' | 'full'; diff --git a/colab-webapp/src/main/node/app/src/components/team/Rights.tsx b/colab-webapp/src/main/node/app/src/components/team/Rights.tsx index 74e267b9e5b..f42ea633572 100644 --- a/colab-webapp/src/main/node/app/src/components/team/Rights.tsx +++ b/colab-webapp/src/main/node/app/src/components/team/Rights.tsx @@ -18,8 +18,8 @@ import { import { useLoadUsersForCurrentProject } from '../../store/selectors/userSelector'; import { addNotification } from '../../store/slice/notificationSlice'; import { - iconButtonStyle, LightIconButtonStyle, + iconButtonStyle, lightTextStyle, space_lg, space_xl, diff --git a/colab-webapp/src/main/node/app/src/components/team/TeamTabs.tsx b/colab-webapp/src/main/node/app/src/components/team/TeamTabs.tsx index c11e0c8a62d..16d2da1af16 100644 --- a/colab-webapp/src/main/node/app/src/components/team/TeamTabs.tsx +++ b/colab-webapp/src/main/node/app/src/components/team/TeamTabs.tsx @@ -13,11 +13,11 @@ import { space_md } from '../../styling/style'; import AvailabilityStatusIndicator from '../common/element/AvailabilityStatusIndicator'; import Flex from '../common/layout/Flex'; import Tabs, { Tab } from '../common/layout/Tabs'; +import MassMemberCreator from './MassMemberCreator'; import TeamMembersPanel from './MembersList'; import ProjectTeamAssignmentsPanel from './ProjectAssignments'; import TeamRightsPanel from './Rights'; import TeamRolesPanel from './Roles'; -import MassMemberCreator from './MassMemberCreator'; export default function TeamTabs(): JSX.Element { const i18n = useTranslations(); From 314c995517cb512d16f7b899f2542f3ebaac4307 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Tue, 28 Nov 2023 09:40:53 +0100 Subject: [PATCH 032/116] change route names - authentication --- colab-webapp/src/main/node/app/src/components/MainApp.tsx | 8 ++++---- .../app/src/components/authentication/ForgotPassword.tsx | 4 ++-- .../node/app/src/components/authentication/SignIn.tsx | 4 ++-- .../node/app/src/components/authentication/SignUp.tsx | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index bef5c5a3c5a..a0304efffeb 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -61,13 +61,13 @@ export default function MainApp(): JSX.Element { return ( <> - } /> - } /> + } /> + } /> } /> - } /> + } /> } /> {isReconnecting && } diff --git a/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx b/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx index 82d4f9e794c..68a300659d9 100644 --- a/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx +++ b/colab-webapp/src/main/node/app/src/components/authentication/ForgotPassword.tsx @@ -52,7 +52,7 @@ export default function ResetPasswordForm({ redirectTo }: ResetPasswordFormProps dispatch(API.requestPasswordReset(email)).then(action => { stopLoading(); if (action.meta.requestStatus === 'fulfilled') { - navigate('../ResetPasswordEmailSent'); + navigate('../password-change-sent'); } }); }, @@ -72,7 +72,7 @@ export default function ResetPasswordForm({ redirectTo }: ResetPasswordFormProps > {i18n.common.cancel} diff --git a/colab-webapp/src/main/node/app/src/components/authentication/SignIn.tsx b/colab-webapp/src/main/node/app/src/components/authentication/SignIn.tsx index b566bbcdd12..fba80603517 100644 --- a/colab-webapp/src/main/node/app/src/components/authentication/SignIn.tsx +++ b/colab-webapp/src/main/node/app/src/components/authentication/SignIn.tsx @@ -138,14 +138,14 @@ export default function SignInForm({ /> {i18n.authentication.action.resetPassword} {(forceShowCreateAccountButton || accountConfig.showCreateAccountButton) && ( {i18n.authentication.action.createAnAccount} diff --git a/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx b/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx index 7b77d641a01..1f950c12978 100644 --- a/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx +++ b/colab-webapp/src/main/node/app/src/components/authentication/SignUp.tsx @@ -176,7 +176,7 @@ export default function SignUpForm({ redirectTo }: SignUpFormProps): JSX.Element isSubmitInProcess={isLoading} > {i18n.common.cancel} From 21eae4e6843e65c0cc27a3ca649595c25251e0c9 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:09:41 +0100 Subject: [PATCH 033/116] change route names --- .../node/app/src/components/admin/AdminTabs.tsx | 14 +++++++------- .../app/src/components/projects/ProjectList.tsx | 2 +- .../app/src/components/projects/ProjectThumb.tsx | 4 ++-- .../app/src/components/settings/SettingsTabs.tsx | 6 +++--- colab-webapp/src/main/node/app/src/i18n/en.ts | 1 - colab-webapp/src/main/node/app/src/i18n/fr.ts | 1 - 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx b/colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx index e68b99a7245..d1486837a69 100644 --- a/colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx +++ b/colab-webapp/src/main/node/app/src/components/admin/AdminTabs.tsx @@ -47,22 +47,22 @@ export default function AdminTabs(): JSX.Element { + + + + + + - - - - - - - + diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx index 06b9bf5b699..c962775682b 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx @@ -144,7 +144,7 @@ function ProjectList({ projects, hideCreationButton }: ProjectListProps) { } /> - } /> + } /> )} diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx index e5bb5176e5d..e457d560d44 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx @@ -136,13 +136,13 @@ export default function ProjectThumb({ project, className }: ProjectThumbProps) ...(project.type !== 'MODEL' ? [ { - value: 'extractModel', + value: 'extract-model', label: ( <> {i18n.modules.project.actions.saveAsModel} ), - action: () => navigate(`extractModel/${project.id}`), + action: () => navigate(`extract-model/${project.id}`), }, ] : []), diff --git a/colab-webapp/src/main/node/app/src/components/settings/SettingsTabs.tsx b/colab-webapp/src/main/node/app/src/components/settings/SettingsTabs.tsx index 8d21a06b08d..82f6a5ed292 100644 --- a/colab-webapp/src/main/node/app/src/components/settings/SettingsTabs.tsx +++ b/colab-webapp/src/main/node/app/src/components/settings/SettingsTabs.tsx @@ -55,7 +55,7 @@ export default function SettingsTabs(): JSX.Element { - + {accounts.map(account => { @@ -72,10 +72,10 @@ export default function SettingsTabs(): JSX.Element { - + - + {/*

my shared models

(imagine a view with the thumbnails)

I can remove one. No more use

diff --git a/colab-webapp/src/main/node/app/src/i18n/en.ts b/colab-webapp/src/main/node/app/src/i18n/en.ts index 4f8d03fa200..4419559c3f7 100644 --- a/colab-webapp/src/main/node/app/src/i18n/en.ts +++ b/colab-webapp/src/main/node/app/src/i18n/en.ts @@ -414,7 +414,6 @@ export const en = { newProject: 'New project', saveAsModel: 'Create a model', saveProjectAsModelPart: 'Create a model from project', - extractModel: 'Extract model', extractAModel: 'Extract a model from a project', extractAModelFromProject: 'Extract a model from project ', createModel: 'Create model', diff --git a/colab-webapp/src/main/node/app/src/i18n/fr.ts b/colab-webapp/src/main/node/app/src/i18n/fr.ts index 89f880f46d3..aa5098ab8c6 100644 --- a/colab-webapp/src/main/node/app/src/i18n/fr.ts +++ b/colab-webapp/src/main/node/app/src/i18n/fr.ts @@ -423,7 +423,6 @@ export const fr: ColabTranslations = { newProject: 'Nouveau projet', saveAsModel: 'Créer un modèle', saveProjectAsModelPart: 'Créer un modèle à partir du projet', - extractModel: 'Extraire un modèle', extractAModel: "Extraire un modèle à partir d'un projet", extractAModelFromProject: 'Extraire un modèle à partir du projet ', createModel: 'Créer le modèle', From 25eb655109fc32685db28c284ceed05b76503919 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:11:36 +0100 Subject: [PATCH 034/116] change route names - card types --- .../node/app/src/components/cardtypes/CardTypeItem.tsx | 2 +- .../app/src/components/cardtypes/CardTypeThumbnail.tsx | 2 +- .../app/src/components/cardtypes/GlobalCardTypeList.tsx | 8 ++++---- .../app/src/components/cardtypes/ProjectCardTypeList.tsx | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx index 5184e947bbc..05f978dc4e3 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx @@ -71,7 +71,7 @@ export default function CardTypeItem({ cardType, usage }: CardTypeItemProps): JS {i18n.common.edit} ), - action: () => navigate(`./edit/${cardType.ownId}`), + action: () => navigate(`./card-type/${cardType.ownId}`), }, ] : []), diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx index 311fe21bf23..f49c60363d6 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx @@ -115,7 +115,7 @@ export default function CardTypeThumbnail({ {i18n.common.edit} ), - action: () => navigate(`./edit/${cardType.ownId}`), + action: () => navigate(`./card-type/${cardType.ownId}`), }, ] : []), diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/GlobalCardTypeList.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/GlobalCardTypeList.tsx index d0ef93ca030..aeeeed59557 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/GlobalCardTypeList.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/GlobalCardTypeList.tsx @@ -39,8 +39,8 @@ export default function GlobalCardTypeList(): JSX.Element { if (lastCreated) { cardTypes.forEach(cardType => { if (cardType.id === lastCreated) { - navigate(`./edit/${cardType.id}`); - navigate(`./edit/${cardType.ownId}`), setLastCreated(null); + navigate(`./card-type/${cardType.id}`); + navigate(`./card-type/${cardType.ownId}`), setLastCreated(null); } }); } @@ -48,9 +48,9 @@ export default function GlobalCardTypeList(): JSX.Element { return ( - } /> + } /> {/* TODO : stabilize the routes ! Now : easy path to make it work*/} - } /> + } /> { if (cardType.id === lastCreated) { - navigate(`./edit/${cardType.id}`); + navigate(`./card-type/${cardType.id}`); setLastCreated(null); } }); @@ -62,9 +62,9 @@ export default function ProjectCardTypeList(): JSX.Element { return ( - } /> + } /> {/* TODO : stabilize the routes ! Now : easy path to make it work*/} - } /> + } /> { if (item) { - navigate(`./edit/${item.ownId}`); + navigate(`./card-type/${item.ownId}`); } }} customThumbnailStyle={cx(cardTypeThumbnailStyle, customThumbStyle)} From ab6cd0c21daf0ffe536d8d9d9cde0e3d17e8d42b Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:20:38 +0100 Subject: [PATCH 035/116] change route names - editor => project --- colab-webapp/src/main/node/app/src/components/MainApp.tsx | 4 ++-- .../src/main/node/app/src/components/cards/CardCreator.tsx | 2 +- .../src/main/node/app/src/components/presence/Presence.tsx | 4 ++-- .../node/app/src/components/projects/NewProjectAccess.tsx | 2 +- .../src/main/node/app/src/components/projects/ProjectList.tsx | 2 +- .../src/main/node/app/src/components/projects/ProjectNav.tsx | 2 +- .../main/node/app/src/components/projects/ProjectThumb.tsx | 4 ++-- .../src/main/node/app/src/components/projects/ProjectsBin.tsx | 2 +- .../src/components/projects/creation/NewProjectCreator.tsx | 2 +- .../app/src/components/projects/creation/ProjectCreator.tsx | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/MainApp.tsx b/colab-webapp/src/main/node/app/src/components/MainApp.tsx index a0304efffeb..7fbf158bb75 100644 --- a/colab-webapp/src/main/node/app/src/components/MainApp.tsx +++ b/colab-webapp/src/main/node/app/src/components/MainApp.tsx @@ -80,7 +80,7 @@ export default function MainApp(): JSX.Element { return ( <> - } /> + } /> } /> } /> } /> - {/* } /> */} + {/* } /> */} { if (currentProjectId) { - navigate(`/editor/${currentProjectId}/docs/cardTypes`); + navigate(`/project/${currentProjectId}/docs/cardTypes`); } }} kind="outline" diff --git a/colab-webapp/src/main/node/app/src/components/presence/Presence.tsx b/colab-webapp/src/main/node/app/src/components/presence/Presence.tsx index 0a1e3cd5cd5..df9fc252f81 100644 --- a/colab-webapp/src/main/node/app/src/components/presence/Presence.tsx +++ b/colab-webapp/src/main/node/app/src/components/presence/Presence.tsx @@ -174,10 +174,10 @@ function PresenceIcon({ presence, member }: PresenceIconProps): JSX.Element { const onClickCb = React.useCallback(() => { if (presence.cardId != null && presence.cardContentId != null) { - navigate(`/editor/${presence.projectId}/card/${presence.cardId}/v/${presence.cardContentId}`); + navigate(`/project/${presence.projectId}/card/${presence.cardId}/v/${presence.cardContentId}`); } else { // back to root - navigate(`/editor/${presence.projectId}`); + navigate(`/project/${presence.projectId}`); } }, [presence, navigate]); diff --git a/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx b/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx index da98459823e..e953fbf2f04 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/NewProjectAccess.tsx @@ -31,5 +31,5 @@ export default function NewProjectAccess(): JSX.Element { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - return ; + return ; } diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx index c962775682b..238ee2c4548 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectList.tsx @@ -131,7 +131,7 @@ function ProjectList({ projects, hideCreationButton }: ProjectListProps) { thumbnailClassName={projectCardStyle} onItemClick={project => { if (project) { - window.open(`#/editor/${project.id}`, '_blank'); + window.open(`#/project/${project.id}`, '_blank'); } }} fillThumbnail={item => { diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx index 95f9c1e6d02..0a338b2c274 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx @@ -62,7 +62,7 @@ export function ProjectNav({ project }: ProjectNavProps): JSX.Element { )} wrap="nowrap" > - + diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx index e457d560d44..9230308067f 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx @@ -55,7 +55,7 @@ export default function ProjectThumb({ project, className }: ProjectThumbProps) onMouseDown={e => { // ultimate hack to open a project in the very same tab: use middle mouse button if (e.button === 1) { - navigate(`/editor/${project.id}`); + navigate(`/project/${project.id}`); } }} direction="column" @@ -110,7 +110,7 @@ export default function ProjectThumb({ project, className }: ProjectThumbProps) {i18n.common.open} ), - action: () => window.open(`#/editor/${project.id}`, '_blank'), + action: () => window.open(`#/project/${project.id}`, '_blank'), }, { value: 'settings', diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectsBin.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectsBin.tsx index 7016927c445..971a49bd430 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectsBin.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectsBin.tsx @@ -123,7 +123,7 @@ function BinDropDownMenu({ project }: { project: Project }): JSX.Element { const i18n = useTranslations(); const showDeletedProject = React.useCallback(() => { - window.open(`#/editor/${project.id!}`, '_blank'); + window.open(`#/project/${project.id!}`, '_blank'); }, [project]); return ( diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx index 7949037e02a..e9fbea57360 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx @@ -116,7 +116,7 @@ export default function ProjectCreator() { setData({ ...defaultData }); close(); setReadOnly(false); - window.open(`#/editor/${payload.payload}`, '_blank'); + window.open(`#/project/${payload.payload}`, '_blank'); stopLoading(); }); } diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx index 76415b88d4c..31d50087cfd 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectCreator.tsx @@ -182,7 +182,7 @@ export default function ProjectCreator({ ).then(payload => { resetCb(); close(); - window.open(`#/editor/${payload.payload}`, '_blank'); + window.open(`#/project/${payload.payload}`, '_blank'); stopLoading(); }); } From 64b22a09be9d739e88e08e6eb9ef1e303181fe05 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:26:52 +0100 Subject: [PATCH 036/116] change route names --- .../src/main/node/app/src/components/cards/CardCreator.tsx | 2 +- .../main/node/app/src/components/projects/DocumentationTabs.tsx | 2 +- .../src/main/node/app/src/components/projects/ProjectList.tsx | 2 +- .../src/main/node/app/src/components/projects/ProjectThumb.tsx | 2 +- .../src/components/projects/settings/ProjectSettingsTabs.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardCreator.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardCreator.tsx index 80976dd0e92..06fa89ef9f8 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardCreator.tsx @@ -110,7 +110,7 @@ export default function CardCreator({ - -
- ); + const i18n = useTranslations(); + + const [loadedFile, setLoadedFile] = useState(null); + + const isDisabled = !activeEditor.isEditable; + + const uploadFile = (files: FileList | null) => { + if (files != null && files.length > 0) { + const file = files[0]; + if (file != null) { + setLoadedFile(file); + logger.info('loadedFile: ', file); + } + } + }; + + return ( + + + + + + + ); } export function InsertFileDialog({ - activeEditor, - onClose, - docOwnership, - }: { - activeEditor: LexicalEditor; - onClose: () => void; - docOwnership: DocumentOwnership; + activeEditor, + onClose, + docOwnership, +}: { + activeEditor: LexicalEditor; + onClose: () => void; + docOwnership: DocumentOwnership; }): React.ReactElement { - const dispatch = useAppDispatch(); - const [isLoading, setIsLoading] = useState(false); - - const onClick = (file: File) => { - setIsLoading(true); - dispatch(API.addFile({docOwnership, file, fileSize: file.size})).then(payload => { - activeEditor.dispatchCommand(INSERT_FILE_COMMAND, { - docId: Number(payload.payload), - fileName: file.name, - }); - setIsLoading(false); - onClose(); - }); - }; - - return ( - <> - - - ); + const dispatch = useAppDispatch(); + const [isLoading, setIsLoading] = useState(false); + + const onClick = (file: File) => { + setIsLoading(true); + dispatch(API.addFile({ docOwnership, file, fileSize: file.size })).then(payload => { + activeEditor.dispatchCommand(INSERT_FILE_COMMAND, { + docId: Number(payload.payload), + fileName: file.name, + }); + setIsLoading(false); + onClose(); + }); + }; + + return ( + <> + + + ); } export default function FilesPlugin(): null { - const dispatch = useAppDispatch(); - - const [editor] = useLexicalComposerContext(); - - // A map to store all file nodes - // I did not find any other way to fetch just deleted file nodes otherwise - const fileNodes = new Map(); - - useEffect(() => { - if (!editor.hasNodes([FileNode])) { - throw new Error('FilesPlugin: FileNode not registered on editor'); + const dispatch = useAppDispatch(); + + const [editor] = useLexicalComposerContext(); + + // A map to store all file nodes + // I did not find any other way to fetch just deleted file nodes otherwise + const fileNodes = new Map(); + + useEffect(() => { + if (!editor.hasNodes([FileNode])) { + throw new Error('FilesPlugin: FileNode not registered on editor'); + } + + return mergeRegister( + editor.registerCommand( + INSERT_FILE_COMMAND, + payload => { + const fileNode = $createFileNode(payload); + $insertNodeToNearestRoot(fileNode); + + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + + // handle aliveness and death of file nodes + // To do it here ascertains that it works with : + // create file node, press delete key, replacing selected data, do, undo + editor.registerMutationListener(FileNode, mutatedNodes => { + for (const [nodeKey, mutation] of mutatedNodes) { + if (mutation === 'created') { + editor.getEditorState().read(() => { + const fileNode = $getNodeByKey(nodeKey); + if ($isFileNode(fileNode)) { + fileNodes.set(nodeKey, fileNode); + dispatch(API.assertFileIsAlive({ docId: fileNode.__docId })); + logger.info(fileNode.__docId + ' created'); + } + }); + } else if (mutation === 'destroyed') { + const fileNode = fileNodes.get(nodeKey); + if (fileNode != null) { + dispatch(API.assertFileIsInBin({ docId: fileNode.__docId })); + } + logger.info(fileNode?.__docId + ' destroyed'); + } } + }), + ); + + // no fileNodes dependency + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [editor]); - return mergeRegister( - editor.registerCommand( - INSERT_FILE_COMMAND, - payload => { - const fileNode = $createFileNode(payload); - $insertNodeToNearestRoot(fileNode); - - return true; - }, - COMMAND_PRIORITY_EDITOR, - ), - - // handle aliveness and death of file nodes - // To do it here ascertains that it works with : - // create file node, press delete key, replacing selected data, do, undo - editor.registerMutationListener(FileNode, mutatedNodes => { - for (const [nodeKey, mutation] of mutatedNodes) { - if (mutation === 'created') { - editor.getEditorState().read(() => { - const fileNode = $getNodeByKey(nodeKey); - if ($isFileNode(fileNode)) { - fileNodes.set(nodeKey, fileNode); - dispatch(API.assertFileIsAlive({docId: fileNode.__docId})); - logger.info(fileNode.__docId + ' created'); - } - }); - } else if (mutation === 'destroyed') { - const fileNode = fileNodes.get(nodeKey); - if (fileNode != null) { - dispatch(API.assertFileIsInBin({docId: fileNode.__docId})); - } - logger.info(fileNode?.__docId + ' destroyed'); - } - } - }), - ); - - // no fileNodes dependency - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [editor]); - - return null; + return null; } diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx index 96eb78aff9a..1ed1e0879a8 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx @@ -5,366 +5,365 @@ * Licensed under the MIT License */ -import {css, cx} from '@emotion/css'; -import {$isLinkNode, TOGGLE_LINK_COMMAND} from '@lexical/link'; -import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import {mergeRegister} from '@lexical/utils'; +import { css, cx } from '@emotion/css'; +import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link'; +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { mergeRegister } from '@lexical/utils'; import { - $getSelection, - $isRangeSelection, BaseSelection, - COMMAND_PRIORITY_CRITICAL, - COMMAND_PRIORITY_HIGH, - COMMAND_PRIORITY_LOW, - KEY_ESCAPE_COMMAND, - LexicalEditor, - SELECTION_CHANGE_COMMAND, + $getSelection, + $isRangeSelection, + BaseSelection, + COMMAND_PRIORITY_CRITICAL, + COMMAND_PRIORITY_HIGH, + COMMAND_PRIORITY_LOW, + KEY_ESCAPE_COMMAND, + LexicalEditor, + SELECTION_CHANGE_COMMAND, } from 'lexical'; import * as React from 'react'; -import {createPortal} from 'react-dom'; +import { createPortal } from 'react-dom'; import useTranslations from '../../../../../i18n/I18nContext'; -import {lightIconButtonStyle, space_md} from '../../../../../styling/style'; +import { lightIconButtonStyle, space_md } from '../../../../../styling/style'; import IconButton from '../../../../common/element/IconButton'; -import {inputStyle} from '../../../../common/element/Input'; +import { inputStyle } from '../../../../common/element/Input'; import Flex from '../../../../common/layout/Flex'; import Icon from '../../../../common/layout/Icon'; -import {getSelectedNode} from '../../utils/getSelectedNode'; -import {setFloatingElemPosition} from '../../utils/setFloatingElemPosition'; -import {sanitizeUrl} from '../../utils/url'; -import {activeToolbarButtonStyle, TOGGLE_LINK_MENU_COMMAND} from '../ToolbarPlugin/ToolbarPlugin'; -import {floatingToolbarStyle} from './FloatingTextFormatPlugin'; +import { getSelectedNode } from '../../utils/getSelectedNode'; +import { setFloatingElemPosition } from '../../utils/setFloatingElemPosition'; +import { sanitizeUrl } from '../../utils/url'; +import { activeToolbarButtonStyle, TOGGLE_LINK_MENU_COMMAND } from '../ToolbarPlugin/ToolbarPlugin'; +import { floatingToolbarStyle } from './FloatingTextFormatPlugin'; const linkStyle = css({ - margin: 'auto', - padding: '4px', + margin: 'auto', + padding: '4px', }); function FloatingLinkEditor({ - editor, - anchorElement, - isLink, - setIsLink, - }: { - editor: LexicalEditor; - anchorElement: HTMLElement; - isLink: boolean; - setIsLink: React.Dispatch; + editor, + anchorElement, + isLink, + setIsLink, +}: { + editor: LexicalEditor; + anchorElement: HTMLElement; + isLink: boolean; + setIsLink: React.Dispatch; }): React.ReactElement { - const editorRef = React.useRef(null); - const inputRef = React.useRef(null); - const [linkUrl, setLinkUrl] = React.useState(''); - const [editedLinkUrl, setEditedLinkUrl] = React.useState(''); - const [isEditMode, setIsEditMode] = React.useState(false); - const [lastSelection, setLastSelection] = React.useState< - BaseSelection | null - >(null); + const editorRef = React.useRef(null); + const inputRef = React.useRef(null); + const [linkUrl, setLinkUrl] = React.useState(''); + const [editedLinkUrl, setEditedLinkUrl] = React.useState(''); + const [isEditMode, setIsEditMode] = React.useState(false); + const [lastSelection, setLastSelection] = React.useState(null); - const i18n = useTranslations(); + const i18n = useTranslations(); - const updateLinkEditor = React.useCallback(() => { - const selection = $getSelection(); - if ($isRangeSelection(selection)) { - const node = getSelectedNode(selection); - const parent = node.getParent(); - if ($isLinkNode(node)) { - setLinkUrl(node.getURL()); - } else if ($isLinkNode(parent)) { - setLinkUrl(parent.getURL()); - } else { - setLinkUrl(''); - } - } - const editorElement = editorRef.current; - const nativeSelection = window.getSelection(); - const activeElement = document.activeElement; - - if (editorElement === null) return; + const updateLinkEditor = React.useCallback(() => { + const selection = $getSelection(); + if ($isRangeSelection(selection)) { + const node = getSelectedNode(selection); + const parent = node.getParent(); + if ($isLinkNode(node)) { + setLinkUrl(node.getURL()); + } else if ($isLinkNode(parent)) { + setLinkUrl(parent.getURL()); + } else { + setLinkUrl(''); + } + } + const editorElement = editorRef.current; + const nativeSelection = window.getSelection(); + const activeElement = document.activeElement; - const rootElement = editor.getRootElement(); + if (editorElement === null) return; - if ( - selection !== null && - nativeSelection !== null && - rootElement !== null && - rootElement.contains(nativeSelection.anchorNode) && - editor.isEditable() - ) { - const domRange = nativeSelection.getRangeAt(0); - let rect; - if (nativeSelection.anchorNode === rootElement) { - let inner = rootElement; - while (inner.firstElementChild != null) { - inner = inner.firstElementChild as HTMLElement; - } - rect = inner.getBoundingClientRect(); - } else { - rect = domRange.getBoundingClientRect(); - } + const rootElement = editor.getRootElement(); - setFloatingElemPosition(rect, editorElement, anchorElement); - setLastSelection(selection); - } else if (!activeElement || activeElement.className !== 'link-input') { - if (rootElement !== null) { - setFloatingElemPosition(null, editorElement, anchorElement); - } - setLastSelection(null); - setIsEditMode(false); - setLinkUrl(''); + if ( + selection !== null && + nativeSelection !== null && + rootElement !== null && + rootElement.contains(nativeSelection.anchorNode) && + editor.isEditable() + ) { + const domRange = nativeSelection.getRangeAt(0); + let rect; + if (nativeSelection.anchorNode === rootElement) { + let inner = rootElement; + while (inner.firstElementChild != null) { + inner = inner.firstElementChild as HTMLElement; } + rect = inner.getBoundingClientRect(); + } else { + rect = domRange.getBoundingClientRect(); + } - return true; - }, [anchorElement, editor]); - - React.useEffect(() => { - const scrollerElem = anchorElement.parentElement; + setFloatingElemPosition(rect, editorElement, anchorElement); + setLastSelection(selection); + } else if (!activeElement || activeElement.className !== 'link-input') { + if (rootElement !== null) { + setFloatingElemPosition(null, editorElement, anchorElement); + } + setLastSelection(null); + setIsEditMode(false); + setLinkUrl(''); + } - const update = () => { - editor.getEditorState().read(() => { - updateLinkEditor(); - }); - }; + return true; + }, [anchorElement, editor]); - window.addEventListener('resize', update); + React.useEffect(() => { + const scrollerElem = anchorElement.parentElement; - if (scrollerElem) { - scrollerElem.addEventListener('scroll', update); - } + const update = () => { + editor.getEditorState().read(() => { + updateLinkEditor(); + }); + }; - return () => { - window.removeEventListener('resize', update); + window.addEventListener('resize', update); - if (scrollerElem) { - scrollerElem.removeEventListener('scroll', update); - } - }; - }, [anchorElement.parentElement, editor, updateLinkEditor]); + if (scrollerElem) { + scrollerElem.addEventListener('scroll', update); + } - React.useEffect(() => { - return mergeRegister( - editor.registerUpdateListener(({editorState}) => { - editorState.read(() => { - updateLinkEditor(); - }); - }), + return () => { + window.removeEventListener('resize', update); - editor.registerCommand( - SELECTION_CHANGE_COMMAND, - () => { - updateLinkEditor(); - return true; - }, - COMMAND_PRIORITY_LOW, - ), - editor.registerCommand( - KEY_ESCAPE_COMMAND, - () => { - if (isLink) { - setIsLink(false); - return true; - } - return false; - }, - COMMAND_PRIORITY_HIGH, - ), - ); - }, [editor, updateLinkEditor, setIsLink, isLink]); + if (scrollerElem) { + scrollerElem.removeEventListener('scroll', update); + } + }; + }, [anchorElement.parentElement, editor, updateLinkEditor]); - React.useEffect(() => { - editor.getEditorState().read(() => { - updateLinkEditor(); + React.useEffect(() => { + return mergeRegister( + editor.registerUpdateListener(({ editorState }) => { + editorState.read(() => { + updateLinkEditor(); }); - }, [editor, updateLinkEditor]); + }), - React.useEffect(() => { - if (isEditMode && inputRef.current) { - inputRef.current.focus(); - } - }, [isEditMode]); + editor.registerCommand( + SELECTION_CHANGE_COMMAND, + () => { + updateLinkEditor(); + return true; + }, + COMMAND_PRIORITY_LOW, + ), + editor.registerCommand( + KEY_ESCAPE_COMMAND, + () => { + if (isLink) { + setIsLink(false); + return true; + } + return false; + }, + COMMAND_PRIORITY_HIGH, + ), + ); + }, [editor, updateLinkEditor, setIsLink, isLink]); - React.useEffect(() => { - return editor.registerCommand( - TOGGLE_LINK_MENU_COMMAND, - payload => { - setEditedLinkUrl('https://'); - setIsEditMode(true); - return editor.dispatchCommand(TOGGLE_LINK_COMMAND, payload); - }, - COMMAND_PRIORITY_CRITICAL, - ); - }, [editor]); + React.useEffect(() => { + editor.getEditorState().read(() => { + updateLinkEditor(); + }); + }, [editor, updateLinkEditor]); - const monitorInputInteraction = (event: React.KeyboardEvent) => { - if (event.key === 'Enter') { - event.preventDefault(); - handleLinkSubmission(); - } else if (event.key === 'Escape') { - event.preventDefault(); - setIsEditMode(false); - } - }; + React.useEffect(() => { + if (isEditMode && inputRef.current) { + inputRef.current.focus(); + } + }, [isEditMode]); - const handleLinkSubmission = () => { - if (lastSelection !== null) { - if (linkUrl !== '') { - editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(editedLinkUrl)); - } - setIsEditMode(false); - } - }; + React.useEffect(() => { + return editor.registerCommand( + TOGGLE_LINK_MENU_COMMAND, + payload => { + setEditedLinkUrl('https://'); + setIsEditMode(true); + return editor.dispatchCommand(TOGGLE_LINK_COMMAND, payload); + }, + COMMAND_PRIORITY_CRITICAL, + ); + }, [editor]); - const handleLinkRemoval = () => { - if (lastSelection !== null) { - editor.dispatchCommand(TOGGLE_LINK_COMMAND, null); - } - }; + const monitorInputInteraction = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + event.preventDefault(); + handleLinkSubmission(); + } else if (event.key === 'Escape') { + event.preventDefault(); + setIsEditMode(false); + } + }; - return ( - <> - {!isLink ? null : ( -
- )} - - ); + const handleLinkSubmission = () => { + if (lastSelection !== null) { + if (linkUrl !== '') { + editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(editedLinkUrl)); + } + setIsEditMode(false); + } + }; + + const handleLinkRemoval = () => { + if (lastSelection !== null) { + editor.dispatchCommand(TOGGLE_LINK_COMMAND, null); + } + }; + + return ( + <> + {!isLink ? null : ( +
+ {isEditMode ? ( + <> + { + setEditedLinkUrl(event.target.value); + }} + onKeyDown={event => { + monitorInputInteraction(event); + }} + /> + event.preventDefault()} + onClick={() => { + setIsEditMode(false); + }} + className={activeToolbarButtonStyle} + /> + event.preventDefault()} + onClick={handleLinkSubmission} + className={activeToolbarButtonStyle} + /> + + ) : ( + <> + + + {linkUrl} + + + + event.preventDefault()} + onClick={() => { + setEditedLinkUrl(linkUrl); + setIsEditMode(true); + }} + className={activeToolbarButtonStyle} + /> + event.preventDefault()} + onClick={handleLinkRemoval} + className={activeToolbarButtonStyle} + /> + + )} +
+ )} + + ); } function useFloatingLinkEditor( - editor: LexicalEditor, - anchorElement: HTMLElement, -): React.ReactElement| null { - const [activeEditor, setActiveEditor] = React.useState(editor); - const [isLink, setIsLink] = React.useState(false); - - const updateToolbar = React.useCallback(() => { - const selection = $getSelection(); - if ($isRangeSelection(selection)) { - const node = getSelectedNode(selection); - const parent = node.getParent(); + editor: LexicalEditor, + anchorElement: HTMLElement, +): React.ReactElement | null { + const [activeEditor, setActiveEditor] = React.useState(editor); + const [isLink, setIsLink] = React.useState(false); - if ($isLinkNode(parent) || $isLinkNode(node)) { - setIsLink(true); - } else { - setIsLink(false); - } - } - }, []); + const updateToolbar = React.useCallback(() => { + const selection = $getSelection(); + if ($isRangeSelection(selection)) { + const node = getSelectedNode(selection); + const parent = node.getParent(); - React.useEffect(() => { - return mergeRegister( - editor.registerUpdateListener(({editorState}) => { - editorState.read(() => { - updateToolbar(); - }); - }), - editor.registerCommand( - SELECTION_CHANGE_COMMAND, - (_payload, newEditor) => { - updateToolbar(); - setActiveEditor(newEditor); - return false; - }, - COMMAND_PRIORITY_CRITICAL, - ), - ); - }, [editor, updateToolbar]); + if ($isLinkNode(parent) || $isLinkNode(node)) { + setIsLink(true); + } else { + setIsLink(false); + } + } + }, []); - return createPortal( - , - anchorElement, + React.useEffect(() => { + return mergeRegister( + editor.registerUpdateListener(({ editorState }) => { + editorState.read(() => { + updateToolbar(); + }); + }), + editor.registerCommand( + SELECTION_CHANGE_COMMAND, + (_payload, newEditor) => { + updateToolbar(); + setActiveEditor(newEditor); + return false; + }, + COMMAND_PRIORITY_CRITICAL, + ), ); + }, [editor, updateToolbar]); + + return createPortal( + , + anchorElement, + ); } export default function FloatingLinkEditorPlugin({ - anchorElement = document.body, - }: { - anchorElement?: HTMLElement; + anchorElement = document.body, +}: { + anchorElement?: HTMLElement; }): React.ReactElement | null { - const [editor] = useLexicalComposerContext(); - return useFloatingLinkEditor(editor, anchorElement); + const [editor] = useLexicalComposerContext(); + return useFloatingLinkEditor(editor, anchorElement); } diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx index ab4131e0a56..b39220b7a32 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ImagesPlugin.tsx @@ -4,314 +4,310 @@ * * Licensed under the MIT License */ -import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import {$wrapNodeInElement, mergeRegister} from '@lexical/utils'; +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { $wrapNodeInElement, mergeRegister } from '@lexical/utils'; import { - $createParagraphNode, - $createRangeSelection, - $getSelection, - $insertNodes, - $isNodeSelection, - $isRootOrShadowRoot, - $setSelection, - COMMAND_PRIORITY_EDITOR, - COMMAND_PRIORITY_HIGH, - COMMAND_PRIORITY_LOW, - createCommand, - DRAGOVER_COMMAND, - DRAGSTART_COMMAND, - DROP_COMMAND, - LexicalCommand, - LexicalEditor, + $createParagraphNode, + $createRangeSelection, + $getSelection, + $insertNodes, + $isNodeSelection, + $isRootOrShadowRoot, + $setSelection, + COMMAND_PRIORITY_EDITOR, + COMMAND_PRIORITY_HIGH, + COMMAND_PRIORITY_LOW, + createCommand, + DRAGOVER_COMMAND, + DRAGSTART_COMMAND, + DROP_COMMAND, + LexicalCommand, + LexicalEditor, } from 'lexical'; import * as React from 'react'; -import {useEffect, useState} from 'react'; +import { useEffect, useState } from 'react'; import Button from '../../../common/element/Button'; // import { DialogActions, DialogButtonsList } from '../../ui/Dialog'; import useTranslations from '../../../../i18n/I18nContext'; -import {$createImageNode, $isImageNode, ImageNode, ImagePayload} from '../nodes/ImageNode'; -import {DialogActions} from '../ui/Dialog'; +import { $createImageNode, $isImageNode, ImageNode, ImagePayload } from '../nodes/ImageNode'; +import { DialogActions } from '../ui/Dialog'; import FileInput from '../ui/FileInput'; import TextInput from '../ui/TextInput'; -import Flex from "../../../common/layout/Flex"; -import {space_sm} from "../../../../styling/style"; +import Flex from '../../../common/layout/Flex'; +import { space_sm } from '../../../../styling/style'; const CAN_USE_DOM: boolean = - typeof window !== 'undefined' && - typeof window.document !== 'undefined' && - typeof window.document.createElement !== 'undefined'; + typeof window !== 'undefined' && + typeof window.document !== 'undefined' && + typeof window.document.createElement !== 'undefined'; export type InsertImagePayload = Readonly; const getDOMSelection = (targetWindow: Window | null): Selection | null => - CAN_USE_DOM ? (targetWindow || window).getSelection() : null; + CAN_USE_DOM ? (targetWindow || window).getSelection() : null; export const INSERT_IMAGE_COMMAND: LexicalCommand = - createCommand('INSERT_IMAGE_COMMAND'); + createCommand('INSERT_IMAGE_COMMAND'); export function InsertImageUploadedDialogBody({ - onClick, - isLoading, - }: { - onClick: (payload: InsertImagePayload) => void; - isLoading: boolean; + onClick, + isLoading, +}: { + onClick: (payload: InsertImagePayload) => void; + isLoading: boolean; }) { - const i18n = useTranslations(); - // const dispatch = useAppDispatch(); + const i18n = useTranslations(); + // const dispatch = useAppDispatch(); - // const [state, setState] = React.useState<'IDLE' | 'LOADING' | 'DONE'>('IDLE'); - const [src, setSrc] = React.useState(''); - const [altText, setAltText] = React.useState(''); + // const [state, setState] = React.useState<'IDLE' | 'LOADING' | 'DONE'>('IDLE'); + const [src, setSrc] = React.useState(''); + const [altText, setAltText] = React.useState(''); - const isDisabled = src === ''; + const isDisabled = src === ''; - const loadImage = (files: FileList | null) => { - const reader = new FileReader(); - reader.onload = function () { - if (typeof reader.result === 'string') { - setSrc(reader.result); - } - return ''; - }; - if (files !== null) { - reader.readAsDataURL(files[0]!); - } + const loadImage = (files: FileList | null) => { + const reader = new FileReader(); + reader.onload = function () { + if (typeof reader.result === 'string') { + setSrc(reader.result); + } + return ''; }; + if (files !== null) { + reader.readAsDataURL(files[0]!); + } + }; - return ( - - - - - - - - ); + return ( + + + + + + + + ); } export function InsertImageDialog({ - activeEditor, - onClose, - }: { - activeEditor: LexicalEditor; - onClose: () => void; + activeEditor, + onClose, +}: { + activeEditor: LexicalEditor; + onClose: () => void; }): JSX.Element { - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(false); - const onClick = (payload: InsertImagePayload) => { - setIsLoading(true); - activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload); - setIsLoading(false); - onClose(); - }; + const onClick = (payload: InsertImagePayload) => { + setIsLoading(true); + activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload); + setIsLoading(false); + onClose(); + }; - return ( - <> - - - ); + return ( + <> + + + ); } export default function ImagesPlugin({ - captionsEnabled, - }: { - captionsEnabled?: boolean; + captionsEnabled, +}: { + captionsEnabled?: boolean; }): JSX.Element | null { - const [editor] = useLexicalComposerContext(); + const [editor] = useLexicalComposerContext(); - useEffect(() => { - if (!editor.hasNodes([ImageNode])) { - throw new Error('ImagesPlugin: ImageNode not registered on editor'); - } + useEffect(() => { + if (!editor.hasNodes([ImageNode])) { + throw new Error('ImagesPlugin: ImageNode not registered on editor'); + } - return mergeRegister( - editor.registerCommand( - INSERT_IMAGE_COMMAND, - payload => { - const imageNode = $createImageNode(payload); - $insertNodes([imageNode]); - if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) { - $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd(); - } + return mergeRegister( + editor.registerCommand( + INSERT_IMAGE_COMMAND, + payload => { + const imageNode = $createImageNode(payload); + $insertNodes([imageNode]); + if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) { + $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd(); + } - return true; - }, - COMMAND_PRIORITY_EDITOR, - ), - editor.registerCommand( - DRAGSTART_COMMAND, - event => { - return onDragStart(event); - }, - COMMAND_PRIORITY_HIGH, - ), - editor.registerCommand( - DRAGOVER_COMMAND, - event => { - return onDragover(event); - }, - COMMAND_PRIORITY_LOW, - ), - editor.registerCommand( - DROP_COMMAND, - event => { - return onDrop(event, editor); - }, - COMMAND_PRIORITY_HIGH, - ), - ); - }, [captionsEnabled, editor]); + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + editor.registerCommand( + DRAGSTART_COMMAND, + event => { + return onDragStart(event); + }, + COMMAND_PRIORITY_HIGH, + ), + editor.registerCommand( + DRAGOVER_COMMAND, + event => { + return onDragover(event); + }, + COMMAND_PRIORITY_LOW, + ), + editor.registerCommand( + DROP_COMMAND, + event => { + return onDrop(event, editor); + }, + COMMAND_PRIORITY_HIGH, + ), + ); + }, [captionsEnabled, editor]); - return null; + return null; } const TRANSPARENT_IMAGE = - 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; + 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; const img = document.createElement('img'); img.src = TRANSPARENT_IMAGE; function onDragStart(event: DragEvent): boolean { - const node = getImageNodeInSelection(); - if (!node) { - return false; - } - const dataTransfer = event.dataTransfer; - if (!dataTransfer) { - return false; - } - dataTransfer.setData('text/plain', '_'); - dataTransfer.setDragImage(img, 0, 0); - dataTransfer.setData( - 'application/x-lexical-drag', - JSON.stringify({ - data: { - altText: node.__altText, - caption: node.__caption, - height: node.__height, - key: node.getKey(), - maxWidth: node.__maxWidth, - showCaption: node.__showCaption, - src: node.__src, - width: node.__width, - }, - type: 'image', - }), - ); + const node = getImageNodeInSelection(); + if (!node) { + return false; + } + const dataTransfer = event.dataTransfer; + if (!dataTransfer) { + return false; + } + dataTransfer.setData('text/plain', '_'); + dataTransfer.setDragImage(img, 0, 0); + dataTransfer.setData( + 'application/x-lexical-drag', + JSON.stringify({ + data: { + altText: node.__altText, + caption: node.__caption, + height: node.__height, + key: node.getKey(), + maxWidth: node.__maxWidth, + showCaption: node.__showCaption, + src: node.__src, + width: node.__width, + }, + type: 'image', + }), + ); - return true; + return true; } function onDragover(event: DragEvent): boolean { - const node = getImageNodeInSelection(); - if (!node) { - return false; - } - if (!canDropImage(event)) { - event.preventDefault(); - } - return true; + const node = getImageNodeInSelection(); + if (!node) { + return false; + } + if (!canDropImage(event)) { + event.preventDefault(); + } + return true; } function onDrop(event: DragEvent, editor: LexicalEditor): boolean { - const node = getImageNodeInSelection(); - if (!node) { - return false; + const node = getImageNodeInSelection(); + if (!node) { + return false; + } + const data = getDragImageData(event); + if (!data) { + return false; + } + event.preventDefault(); + if (canDropImage(event)) { + const range = getDragSelection(event); + node.remove(); + const rangeSelection = $createRangeSelection(); + if (range !== null && range !== undefined) { + rangeSelection.applyDOMRange(range); } - const data = getDragImageData(event); - if (!data) { - return false; - } - event.preventDefault(); - if (canDropImage(event)) { - const range = getDragSelection(event); - node.remove(); - const rangeSelection = $createRangeSelection(); - if (range !== null && range !== undefined) { - rangeSelection.applyDOMRange(range); - } - $setSelection(rangeSelection); - editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); - } - return true; + $setSelection(rangeSelection); + editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); + } + return true; } function getImageNodeInSelection(): ImageNode | null { - const selection = $getSelection(); - if (!$isNodeSelection(selection)) { - return null; - } - const nodes = selection.getNodes(); - const node = nodes[0]; - return $isImageNode(node) ? node : null; + const selection = $getSelection(); + if (!$isNodeSelection(selection)) { + return null; + } + const nodes = selection.getNodes(); + const node = nodes[0]; + return $isImageNode(node) ? node : null; } function getDragImageData(event: DragEvent): null | InsertImagePayload { - const dragData = event.dataTransfer?.getData('application/x-lexical-drag'); - if (!dragData) { - return null; - } - const {type, data} = JSON.parse(dragData); - if (type !== 'image') { - return null; - } + const dragData = event.dataTransfer?.getData('application/x-lexical-drag'); + if (!dragData) { + return null; + } + const { type, data } = JSON.parse(dragData); + if (type !== 'image') { + return null; + } - return data; + return data; } declare global { - interface DragEvent { - rangeOffset?: number; - rangeParent?: Node; - } + interface DragEvent { + rangeOffset?: number; + rangeParent?: Node; + } } function canDropImage(event: DragEvent): boolean { - const target = event.target; - return !!( - target && - target instanceof HTMLElement && - !target.closest('code, span.editor-image') && - target.parentElement && - target.parentElement.closest('div.ContentEditable__root') - ); + const target = event.target; + return !!( + target && + target instanceof HTMLElement && + !target.closest('code, span.editor-image') && + target.parentElement && + target.parentElement.closest('div.ContentEditable__root') + ); } function getDragSelection(event: DragEvent): Range | null | undefined { - let range; - const target = event.target as null | Element | Document; - const targetWindow = - target == null - ? null - : target.nodeType === 9 - ? (target as Document).defaultView - : (target as Element).ownerDocument.defaultView; - const domSelection = getDOMSelection(targetWindow); - if (document.caretRangeFromPoint) { - range = document.caretRangeFromPoint(event.clientX, event.clientY); - } else if (event.rangeParent && domSelection !== null) { - domSelection.collapse(event.rangeParent, event.rangeOffset || 0); - range = domSelection.getRangeAt(0); - } else { - throw Error(`Cannot get the selection when dragging`); - } + let range; + const target = event.target as null | Element | Document; + const targetWindow = + target == null + ? null + : target.nodeType === 9 + ? (target as Document).defaultView + : (target as Element).ownerDocument.defaultView; + const domSelection = getDOMSelection(targetWindow); + if (document.caretRangeFromPoint) { + range = document.caretRangeFromPoint(event.clientX, event.clientY); + } else if (event.rangeParent && domSelection !== null) { + domSelection.collapse(event.rangeParent, event.rangeOffset || 0); + range = domSelection.getRangeAt(0); + } else { + throw Error(`Cannot get the selection when dragging`); + } - return range; + return range; } diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/theme/EditorTheme.css b/colab-webapp/src/main/node/app/src/components/documents/texteditor/theme/EditorTheme.css index 5483ed93e4c..cc43ac59bc6 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/theme/EditorTheme.css +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/theme/EditorTheme.css @@ -1,506 +1,506 @@ .TextEditorTheme__ltr { - text-align: left; - line-height: 1.7; + text-align: left; + line-height: 1.7; } .TextEditorTheme__rtl { - text-align: right; - line-height: 1.7; + text-align: right; + line-height: 1.7; } .TextEditorTheme__paragraph { - margin: 0; - position: relative; + margin: 0; + position: relative; } .TextEditorTheme__quote { - margin: 0; - margin-left: 20px; - margin-bottom: 10px; - font-size: 15px; - color: rgb(101, 103, 107); - border-left-color: rgb(206, 208, 212); - border-left-width: 4px; - border-left-style: solid; - padding-left: 16px; + margin: 0; + margin-left: 20px; + margin-bottom: 10px; + font-size: 15px; + color: rgb(101, 103, 107); + border-left-color: rgb(206, 208, 212); + border-left-width: 4px; + border-left-style: solid; + padding-left: 16px; } .TextEditorTheme__h1 { - font-size: 32px; - color: #43444B; - margin: 0; - text-transform: uppercase; + font-size: 32px; + color: #43444b; + margin: 0; + text-transform: uppercase; } .TextEditorTheme__h2 { - font-size: 26px; - color: #43444B; - margin: 0; - text-transform: uppercase; + font-size: 26px; + color: #43444b; + margin: 0; + text-transform: uppercase; } .TextEditorTheme__h3 { - font-size: 22px; - color: #787C87; - margin: 0; - text-transform: uppercase; + font-size: 22px; + color: #787c87; + margin: 0; + text-transform: uppercase; } .TextEditorTheme__h4 { - font-size: 18px; - color: #787C87; - margin: 0; - text-transform: uppercase; + font-size: 18px; + color: #787c87; + margin: 0; + text-transform: uppercase; } .TextEditorTheme__h5 { - font-size: 16px; - color: #A0A2AB; - margin: 0; - text-transform: uppercase; + font-size: 16px; + color: #a0a2ab; + margin: 0; + text-transform: uppercase; } .TextEditorTheme__textBold { - font-weight: bold; + font-weight: bold; } .TextEditorTheme__textItalic { - font-style: italic; + font-style: italic; } .TextEditorTheme__textUnderline { - text-decoration: underline; + text-decoration: underline; } .TextEditorTheme__textStrikethrough { - text-decoration: line-through; + text-decoration: line-through; } .TextEditorTheme__textUnderlineStrikethrough { - text-decoration: underline line-through; + text-decoration: underline line-through; } .TextEditorTheme__textSubscript { - font-size: 0.8em; - vertical-align: sub !important; + font-size: 0.8em; + vertical-align: sub !important; } .TextEditorTheme__textSuperscript { - font-size: 0.8em; - vertical-align: super; + font-size: 0.8em; + vertical-align: super; } .TextEditorTheme__textCode { - background-color: rgb(240, 242, 245); - padding: 1px 0.25rem; - font-family: Menlo, Consolas, Monaco, monospace; - font-size: 94%; + background-color: rgb(240, 242, 245); + padding: 1px 0.25rem; + font-family: Menlo, Consolas, Monaco, monospace; + font-size: 94%; } .TextEditorTheme__hashtag { - background-color: rgba(88, 144, 255, 0.15); - border-bottom: 1px solid rgba(88, 144, 255, 0.3); + background-color: rgba(88, 144, 255, 0.15); + border-bottom: 1px solid rgba(88, 144, 255, 0.3); } .TextEditorTheme__link { - color: rgb(33, 111, 219); - text-decoration: none; + color: rgb(33, 111, 219); + text-decoration: none; } .TextEditorTheme__link:hover { - text-decoration: underline; - cursor: pointer; + text-decoration: underline; + cursor: pointer; } .TextEditorTheme__code { - background-color: rgb(240, 242, 245); - font-family: Menlo, Consolas, Monaco, monospace; - display: block; - padding: 8px 8px 8px 52px; - line-height: 1.53; - font-size: 13px; - margin: 0; - margin-top: 8px; - margin-bottom: 8px; - tab-size: 2; - /* white-space: pre; */ - overflow-x: auto; - position: relative; + background-color: rgb(240, 242, 245); + font-family: Menlo, Consolas, Monaco, monospace; + display: block; + padding: 8px 8px 8px 52px; + line-height: 1.53; + font-size: 13px; + margin: 0; + margin-top: 8px; + margin-bottom: 8px; + tab-size: 2; + /* white-space: pre; */ + overflow-x: auto; + position: relative; } .TextEditorTheme__code:before { - content: attr(data-gutter); - position: absolute; - background-color: #eee; - left: 0; - top: 0; - border-right: 1px solid #ccc; - padding: 8px; - color: #777; - white-space: pre-wrap; - text-align: right; - min-width: 25px; + content: attr(data-gutter); + position: absolute; + background-color: #eee; + left: 0; + top: 0; + border-right: 1px solid #ccc; + padding: 8px; + color: #777; + white-space: pre-wrap; + text-align: right; + min-width: 25px; } .TextEditorTheme__table { - border-collapse: collapse; - border-spacing: 0; - max-width: 100%; - overflow-y: scroll; - table-layout: fixed; - width: calc(100% - 25px); - margin: 30px 0; + border-collapse: collapse; + border-spacing: 0; + max-width: 100%; + overflow-y: scroll; + table-layout: fixed; + width: calc(100% - 25px); + margin: 30px 0; } .TextEditorTheme__tableSelected { - outline: 2px solid rgb(60, 132, 244); + outline: 2px solid rgb(60, 132, 244); } .TextEditorTheme__tableCell { - border: 1px solid #bbb; - min-width: 75px; - vertical-align: top; - text-align: start; - padding: 6px 8px; - position: relative; - cursor: default; - outline: none; - background-clip: padding-box; + border: 1px solid #bbb; + min-width: 75px; + vertical-align: top; + text-align: start; + padding: 6px 8px; + position: relative; + cursor: default; + outline: none; + background-clip: padding-box; } .TextEditorTheme__tableCellSortedIndicator { - display: block; - opacity: 0.5; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 4px; - background-color: #999; + display: block; + opacity: 0.5; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 4px; + background-color: #999; } .TextEditorTheme__tableCellResizer { - position: absolute; - right: -4px; - height: 100%; - width: 8px; - cursor: ew-resize; - z-index: 10; - top: 0; + position: absolute; + right: -4px; + height: 100%; + width: 8px; + cursor: ew-resize; + z-index: 10; + top: 0; } .TextEditorTheme__tableCellHeader { - background-color: #f2f3f5; - text-align: start; + background-color: #f2f3f5; + text-align: start; } .TextEditorTheme__tableCellSelected { - background-color: #c9dbf0; + background-color: #c9dbf0; } .TextEditorTheme__tableCellPrimarySelected { - border: 2px solid rgb(60, 132, 244); - display: block; - height: calc(100% - 2px); - position: absolute; - width: calc(100% - 2px); - left: -1px; - top: -1px; - z-index: 2; + border: 2px solid rgb(60, 132, 244); + display: block; + height: calc(100% - 2px); + position: absolute; + width: calc(100% - 2px); + left: -1px; + top: -1px; + z-index: 2; } .TextEditorTheme__tableCellEditing { - box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); - border-radius: 3px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); + border-radius: 3px; } .TextEditorTheme__tableAddColumns { - position: absolute; - top: 0; - width: 20px; - background-color: #eee; - height: 100%; - right: 0; - animation: table-controls 0.2s ease; - border: 0; - cursor: pointer; + position: absolute; + top: 0; + width: 20px; + background-color: #eee; + height: 100%; + right: 0; + animation: table-controls 0.2s ease; + border: 0; + cursor: pointer; } .TextEditorTheme__tableAddColumns:after { - background-size: contain; - background-position: center; - background-repeat: no-repeat; - display: block; - content: ' '; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0.4; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + display: block; + content: ' '; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.4; } .TextEditorTheme__tableAddColumns:hover { - background-color: #c9dbf0; + background-color: #c9dbf0; } .TextEditorTheme__tableAddRows { - position: absolute; - bottom: -25px; - width: calc(100% - 25px); - background-color: #eee; - height: 20px; - left: 0; - animation: table-controls 0.2s ease; - border: 0; - cursor: pointer; + position: absolute; + bottom: -25px; + width: calc(100% - 25px); + background-color: #eee; + height: 20px; + left: 0; + animation: table-controls 0.2s ease; + border: 0; + cursor: pointer; } .TextEditorTheme__tableAddRows:after { - background-size: contain; - background-position: center; - background-repeat: no-repeat; - display: block; - content: ' '; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0.4; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + display: block; + content: ' '; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.4; } .TextEditorTheme__tableAddRows:hover { - background-color: #c9dbf0; + background-color: #c9dbf0; } @keyframes table-controls { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } } .TextEditorTheme__tableCellResizeRuler { - display: block; - position: absolute; - width: 1px; - background-color: rgb(60, 132, 244); - height: 100%; - top: 0; + display: block; + position: absolute; + width: 1px; + background-color: rgb(60, 132, 244); + height: 100%; + top: 0; } .TextEditorTheme__tableCellActionButtonContainer { - display: block; - right: 5px; - top: 6px; - position: absolute; - z-index: 4; - width: 20px; - height: 20px; + display: block; + right: 5px; + top: 6px; + position: absolute; + z-index: 4; + width: 20px; + height: 20px; } .TextEditorTheme__tableCellActionButton { - background-color: #eee; - display: block; - border: 0; - border-radius: 20px; - width: 20px; - height: 20px; - color: #222; - cursor: pointer; + background-color: #eee; + display: block; + border: 0; + border-radius: 20px; + width: 20px; + height: 20px; + color: #222; + cursor: pointer; } .TextEditorTheme__tableCellActionButton:hover { - background-color: #ddd; + background-color: #ddd; } .TextEditorTheme__characterLimit { - display: inline; - background-color: #ffbbbb !important; + display: inline; + background-color: #ffbbbb !important; } .TextEditorTheme__ol1 { - padding: 0; - margin: 0; + padding: 0; + margin: 0; } .TextEditorTheme__ol2 { - padding: 0; - margin: 0; - list-style-type: upper-alpha; + padding: 0; + margin: 0; + list-style-type: upper-alpha; } .TextEditorTheme__ol3 { - padding: 0; - margin: 0; - list-style-type: lower-alpha; + padding: 0; + margin: 0; + list-style-type: lower-alpha; } .TextEditorTheme__ol4 { - padding: 0; - margin: 0; - list-style-type: upper-roman; + padding: 0; + margin: 0; + list-style-type: upper-roman; } .TextEditorTheme__ol5 { - padding: 0; - margin: 0; - list-style-type: lower-roman; + padding: 0; + margin: 0; + list-style-type: lower-roman; } .TextEditorTheme__ul { - padding: 0; - margin: 0; + padding: 0; + margin: 0; } .TextEditorTheme__listItem { - margin: 0 32px; + margin: 0 32px; } .TextEditorTheme__listItemChecked, .TextEditorTheme__listItemUnchecked { - position: relative; - margin-left: 12px; - margin-right: 8px; - padding-left: 28px; - padding-right: 24px; - list-style-type: none; - outline: none; + position: relative; + margin-left: 12px; + margin-right: 8px; + padding-left: 28px; + padding-right: 24px; + list-style-type: none; + outline: none; } .TextEditorTheme__listItemChecked { - text-decoration: line-through; + text-decoration: line-through; } .TextEditorTheme__listItemUnchecked:before, .TextEditorTheme__listItemChecked:before { - content: ''; - width: 16px; - height: 16px; - top: 2px; - left: 0; - cursor: pointer; - display: block; - background-size: cover; - position: absolute; + content: ''; + width: 16px; + height: 16px; + top: 2px; + left: 0; + cursor: pointer; + display: block; + background-size: cover; + position: absolute; } .TextEditorTheme__listItemUnchecked[dir='rtl']:before, .TextEditorTheme__listItemChecked[dir='rtl']:before { - left: auto; - right: 0; + left: auto; + right: 0; } .TextEditorTheme__listItemUnchecked:focus:before, .TextEditorTheme__listItemChecked:focus:before { - box-shadow: 0 0 0 2px #a6cdfe; - border-radius: 2px; + box-shadow: 0 0 0 2px #a6cdfe; + border-radius: 2px; } .TextEditorTheme__listItemUnchecked:before { - border: 1px solid #999; - border-radius: 2px; + border: 1px solid #999; + border-radius: 2px; } .TextEditorTheme__listItemChecked:before { - border: 1px solid rgb(61, 135, 245); - border-radius: 2px; - background-color: #3d87f5; - background-repeat: no-repeat; + border: 1px solid rgb(61, 135, 245); + border-radius: 2px; + background-color: #3d87f5; + background-repeat: no-repeat; } .TextEditorTheme__listItemChecked:after { - content: ''; - cursor: pointer; - border-color: #fff; - border-style: solid; - position: absolute; - display: block; - top: 6px; - width: 3px; - left: 7px; - right: 7px; - height: 6px; - transform: rotate(45deg); - border-width: 0 2px 2px 0; + content: ''; + cursor: pointer; + border-color: #fff; + border-style: solid; + position: absolute; + display: block; + top: 6px; + width: 3px; + left: 7px; + right: 7px; + height: 6px; + transform: rotate(45deg); + border-width: 0 2px 2px 0; } .TextEditorTheme__nestedListItem { - list-style-type: none; + list-style-type: none; } .TextEditorTheme__nestedListItem:before, .TextEditorTheme__nestedListItem:after { - display: none; + display: none; } .TextEditorTheme__tokenComment { - color: slategray; + color: slategray; } .TextEditorTheme__tokenPunctuation { - color: #999; + color: #999; } .TextEditorTheme__tokenProperty { - color: #905; + color: #905; } .TextEditorTheme__tokenSelector { - color: #690; + color: #690; } .TextEditorTheme__tokenOperator { - color: #9a6e3a; + color: #9a6e3a; } .TextEditorTheme__tokenAttr { - color: #07a; + color: #07a; } .TextEditorTheme__tokenVariable { - color: #e90; + color: #e90; } .TextEditorTheme__tokenFunction { - color: #dd4a68; + color: #dd4a68; } .TextEditorTheme__mark { - background: rgba(255, 212, 0, 0.14); - border-bottom: 2px solid rgba(255, 212, 0, 0.3); - padding-bottom: 2px; + background: rgba(255, 212, 0, 0.14); + border-bottom: 2px solid rgba(255, 212, 0, 0.3); + padding-bottom: 2px; } .TextEditorTheme__markOverlap { - background: rgba(255, 212, 0, 0.3); - border-bottom: 2px solid rgba(255, 212, 0, 0.7); + background: rgba(255, 212, 0, 0.3); + border-bottom: 2px solid rgba(255, 212, 0, 0.7); } .TextEditorTheme__mark.selected { - background: rgba(255, 212, 0, 0.5); - border-bottom: 2px solid rgba(255, 212, 0, 1); + background: rgba(255, 212, 0, 0.5); + border-bottom: 2px solid rgba(255, 212, 0, 1); } .TextEditorTheme__markOverlap.selected { - background: rgba(255, 212, 0, 0.7); - border-bottom: 2px solid rgba(255, 212, 0, 0.7); + background: rgba(255, 212, 0, 0.7); + border-bottom: 2px solid rgba(255, 212, 0, 0.7); } .TextEditorTheme__embedBlock { - user-select: none; + user-select: none; } .TextEditorTheme__embedBlockFocus { - outline: 2px solid rgb(60, 132, 244); + outline: 2px solid rgb(60, 132, 244); } .editor-image { - cursor: default; - display: inline-block; - position: relative; - user-select: none; + cursor: default; + display: inline-block; + position: relative; + user-select: none; } diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/FileInput.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/FileInput.tsx index 592c2dcf396..8d5cef453e3 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/FileInput.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/FileInput.tsx @@ -7,25 +7,25 @@ import * as React from 'react'; type FileInputProps = Readonly<{ - 'data-test-id'?: string; + 'data-test-id'?: string; - accept?: string; - onChange: (files: FileList | null) => void; + accept?: string; + onChange: (files: FileList | null) => void; }>; export default function FileInput({ - accept, - onChange, - 'data-test-id': dataTestId, - }: FileInputProps): JSX.Element { - return ( - <> - onChange(e.target.files)} - data-test-id={dataTestId} - /> - - ); + accept, + onChange, + 'data-test-id': dataTestId, +}: FileInputProps): JSX.Element { + return ( + <> + onChange(e.target.files)} + data-test-id={dataTestId} + /> + + ); } diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/TextInput.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/TextInput.tsx index 372919701f4..d5f17d74155 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/TextInput.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/ui/TextInput.tsx @@ -5,36 +5,36 @@ * Licensed under the MIT License */ import * as React from 'react'; -import {space_sm} from "../../../../styling/style"; -import Flex from "../../../common/layout/Flex"; +import { space_sm } from '../../../../styling/style'; +import Flex from '../../../common/layout/Flex'; type Props = Readonly<{ - 'data-test-id'?: string; - label: string; - onChange: (val: string) => void; - placeholder?: string; - value: string; + 'data-test-id'?: string; + label: string; + onChange: (val: string) => void; + placeholder?: string; + value: string; }>; export default function TextInput({ - label, - value, - onChange, - placeholder = '', - 'data-test-id': dataTestId, - }: Props): JSX.Element { - return ( - - - { - onChange(e.target.value); - }} - data-test-id={dataTestId} - /> - - ); + label, + value, + onChange, + placeholder = '', + 'data-test-id': dataTestId, +}: Props): JSX.Element { + return ( + + + { + onChange(e.target.value); + }} + data-test-id={dataTestId} + /> + + ); } diff --git a/colab-webapp/src/main/node/app/src/components/team/ProjectAssignmentsTable.tsx b/colab-webapp/src/main/node/app/src/components/team/ProjectAssignmentsTable.tsx index f0c323af54e..c4918ebe96e 100644 --- a/colab-webapp/src/main/node/app/src/components/team/ProjectAssignmentsTable.tsx +++ b/colab-webapp/src/main/node/app/src/components/team/ProjectAssignmentsTable.tsx @@ -150,7 +150,7 @@ function MembersRow({ members }: MembersRowProps): JSX.Element { <> {members.map(member => ( - + ))} From 34e91525e6b6e3c67b0fd1ea04c563f4ddc77243 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:39:45 +0100 Subject: [PATCH 045/116] i18n review --- .../src/main/node/app/src/components/App.tsx | 2 +- .../src/main/node/app/src/i18n/I18nContext.ts | 10 ++++++++++ .../src/main/node/app/src/i18n/LanguageSelector.tsx | 12 +++--------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/App.tsx b/colab-webapp/src/main/node/app/src/components/App.tsx index c4aad1adaa7..c0530a08065 100644 --- a/colab-webapp/src/main/node/app/src/components/App.tsx +++ b/colab-webapp/src/main/node/app/src/components/App.tsx @@ -174,7 +174,7 @@ function App(): JSX.Element { }> - + void; @@ -23,8 +27,12 @@ export const I18nCtx = React.createContext({ setLang: () => {}, }); +//////////////////////////////////////////////////////////////////////////////////////////////////// + export type ColabTranslations = typeof en; +//////////////////////////////////////////////////////////////////////////////////////////////////// + export default function useTranslations(): typeof en { const { lang } = React.useContext(I18nCtx); @@ -39,3 +47,5 @@ export function useLanguage(): Language { const { lang } = React.useContext(I18nCtx); return lang; } + +//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/colab-webapp/src/main/node/app/src/i18n/LanguageSelector.tsx b/colab-webapp/src/main/node/app/src/i18n/LanguageSelector.tsx index 9a39b4d2d28..be1885c0e88 100644 --- a/colab-webapp/src/main/node/app/src/i18n/LanguageSelector.tsx +++ b/colab-webapp/src/main/node/app/src/i18n/LanguageSelector.tsx @@ -17,23 +17,17 @@ export default function LanguageSelector(): JSX.Element { { value: 'EN', label:
English
}, { value: 'FR', label:
Français
}, ]; - const valueComp: { value: Language; label: React.ReactNode } = - lang == 'EN' - ? { value: 'EN', label:
English
} - : { value: 'FR', label:
Français
}; return ( setLang(entry.value)} - idleHoverStyle="BACKGROUND" + direction="left" className={css({ alignItems: 'stretch' })} buttonClassName={entryStyle} - showSelectedLabel - direction="left" /> ); } From 9be8f41f4b629630f2d807d615bc39c24a7c1d18 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:45:45 +0100 Subject: [PATCH 046/116] remove sticky note from front --- colab-webapp/src/main/node/app/src/API/api.ts | 47 +---- .../stickynotes/StickyNoteCreator.tsx | 174 ------------------ .../stickynotes/StickyNoteDisplay.tsx | 153 --------------- .../components/stickynotes/StickyNoteList.tsx | 57 ------ .../stickynotes/StickyNoteWrapper.tsx | 60 ------ colab-webapp/src/main/node/app/src/i18n/en.ts | 6 - colab-webapp/src/main/node/app/src/i18n/fr.ts | 6 - .../store/selectors/stickyNoteLinkSelector.ts | 71 ------- .../src/store/slice/stickynotelinkSlice.ts | 100 ---------- .../src/main/node/app/src/store/store.ts | 4 +- .../main/node/app/src/ws/wsThunkActions.ts | 7 +- 11 files changed, 4 insertions(+), 681 deletions(-) delete mode 100644 colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteCreator.tsx delete mode 100644 colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteDisplay.tsx delete mode 100644 colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteList.tsx delete mode 100644 colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteWrapper.tsx delete mode 100644 colab-webapp/src/main/node/app/src/store/selectors/stickyNoteLinkSelector.ts delete mode 100644 colab-webapp/src/main/node/app/src/store/slice/stickynotelinkSlice.ts diff --git a/colab-webapp/src/main/node/app/src/API/api.ts b/colab-webapp/src/main/node/app/src/API/api.ts index ca733ad3e9e..0cdc0bae47e 100644 --- a/colab-webapp/src/main/node/app/src/API/api.ts +++ b/colab-webapp/src/main/node/app/src/API/api.ts @@ -27,8 +27,8 @@ import { GridPosition, HierarchicalPosition, HttpSession, - InvolvementLevel, InstanceMaker, + InvolvementLevel, Project, ProjectCreationData, ProjectStructure, @@ -36,8 +36,6 @@ import { ResourceCreationData, ResourceRef, SignUpInfo, - StickyNoteLink, - StickyNoteLinkCreationData, TeamMember, TeamRole, TouchUserPresence, @@ -1695,49 +1693,6 @@ export const deletePendingChanges = createAsyncThunk('block/deleteChanges', asyn return await restClient.ChangeRestEndpoint.deletePendingChanges(id); }); -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Sticky Note Links -//////////////////////////////////////////////////////////////////////////////////////////////////// - -//export const getStickyNoteLink = createAsyncThunk('stickyNoteLinks/get', async (id: number) => { -// return await restClient.StickyNoteLinkRestEndpoint.getLink(id); -//}); - -// TODO see if it belongs to stickyNoteLinks or to cards. Make your choice ! -export const getStickyNoteLinkAsDest = createAsyncThunk( - 'stickyNoteLinks/getAsDest', - async (cardId: number) => { - if (cardId > 0) { - return await restClient.CardRestEndpoint.getStickyNoteLinksAsDest(cardId); - } else { - return []; - } - }, -); - -export const createStickyNote = createAsyncThunk( - 'stickyNoteLinks/create', - async (stickyNote: StickyNoteLinkCreationData) => { - return await restClient.StickyNoteLinkRestEndpoint.createLink(stickyNote); - }, -); - -export const updateStickyNote = createAsyncThunk( - 'stickyNoteLinks/update', - async (stickyNote: StickyNoteLink) => { - return await restClient.StickyNoteLinkRestEndpoint.updateLink(stickyNote); - }, -); - -export const deleteStickyNote = createAsyncThunk( - 'stickyNoteLinks/delete', - async (stickyNote: StickyNoteLink) => { - if (stickyNote.id != null) { - return await restClient.StickyNoteLinkRestEndpoint.deleteLink(stickyNote.id); - } - }, -); - //////////////////////////////////////////////////////////////////////////////////////////////////// // Activity-Flow Links //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteCreator.tsx b/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteCreator.tsx deleted file mode 100644 index 782e2931528..00000000000 --- a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteCreator.tsx +++ /dev/null @@ -1,174 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { css, cx } from '@emotion/css'; -import * as React from 'react'; -import * as API from '../../API/api'; -import useTranslations from '../../i18n/I18nContext'; -import { useAppDispatch, useAppSelector } from '../../store/hooks'; -import { useAllProjectCards } from '../../store/selectors/cardSelector'; -import { useCurrentProjectId } from '../../store/selectors/projectSelector'; -import { space_lg, space_sm } from '../../styling/style'; -import Button from '../common/element/Button'; -import Form, { Field } from '../common/element/Form'; -import IconButton from '../common/element/IconButton'; -import Flex from '../common/layout/Flex'; -import Icon from '../common/layout/Icon'; -import OpenModalOnClick from '../common/layout/OpenModalOnClick'; - -interface StickyNoteCreatorProps { - destCardId: number; - className?: string; -} - -interface StickyNoteLinkType { - srcCardId: number | null; - srcCardContentId: number | null; - srcResourceOrRefId: number | null; - srcBlockId: number | null; - destinationCardId: number | null; - teaser: string; - explanation: string; -} - -const defaultStickyNode: StickyNoteLinkType = { - srcCardId: null, - srcCardContentId: null, - srcResourceOrRefId: null, - srcBlockId: null, - destinationCardId: null, - teaser: '', - explanation: '', -}; - -export default function StickyNoteCreator({ - destCardId, - className, -}: StickyNoteCreatorProps): JSX.Element { - const dispatch = useAppDispatch(); - const i18n = useTranslations(); - - const currentProjectId = useCurrentProjectId(); - const cards = useAllProjectCards(); - const cardStatus = useAppSelector(state => state.cards.status); - - // make sure to know all cards - React.useEffect(() => { - if (cardStatus == 'NOT_INITIALIZED' && currentProjectId != null) { - dispatch(API.getAllProjectCards(currentProjectId)); - } - }, [cardStatus, dispatch, currentProjectId]); - - const [state, setState] = React.useState(defaultStickyNode); - - const resetInputs = React.useCallback(() => { - setState(defaultStickyNode); - }, []); - - const cardOptions = cards.flatMap(card => { - if (card.parentId != null) { - return [ - { - label: `${card.title || i18n.modules.card.untitled} (${card.id})`, - value: card.id!, - }, - ]; - } else { - return []; - } - }); - - const fields: Field[] = [ - { - key: 'teaser', - label: 'teaser', - type: 'text', - isMandatory: true, - }, - { - key: 'explanation', - label: 'explanation', - type: 'textarea', - isMandatory: true, - }, - { - key: 'srcCardId', - label: 'Source', - type: 'selectnumber', - isMandatory: true, - options: cardOptions, - }, - ]; - - return ( - - - - } - > - {collapse => ( - <> - { - resetInputs(); - collapse(); - }); - }} - submitLabel={i18n.common.create} - className={css({ alignSelf: 'center' })} - childrenClassName={css({ - flexDirection: 'row-reverse', - alignItems: 'center', - justifyContent: 'end', - })} - > - - resetInputs()} /> - - - )} - - ); -} diff --git a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteDisplay.tsx b/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteDisplay.tsx deleted file mode 100644 index ad41d18c5c6..00000000000 --- a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteDisplay.tsx +++ /dev/null @@ -1,153 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { css, cx } from '@emotion/css'; -import { StickyNoteLink } from 'colab-rest-client'; -import * as React from 'react'; -import { useNavigate } from 'react-router-dom'; -import * as API from '../../API/api'; -import useTranslations from '../../i18n/I18nContext'; -import { useAppDispatch } from '../../store/hooks'; -import { useCard } from '../../store/selectors/cardSelector'; -import { cardStyle, lightIconButtonStyle, space_lg, space_sm } from '../../styling/style'; -import { BlockEditorWrapper } from '../blocks/BlockEditorWrapper'; -import CardThumbWithSelector from '../cards/CardThumbWithSelector'; -import Button from '../common/element/Button'; -import { DiscreetInput } from '../common/element/Input'; -import { ConfirmDeleteModal } from '../common/layout/ConfirmDeleteModal'; -import DropDownMenu from '../common/layout/DropDownMenu'; -import Flex from '../common/layout/Flex'; -import Icon from '../common/layout/Icon'; - -// TODO replace { - if (showSrc && stickyNote.srcCardId && srcCard === undefined) { - dispatch(API.getCard(stickyNote.srcCardId)); - } - }, [showSrc, stickyNote.srcCardId, srcCard, dispatch]); - - React.useEffect(() => { - if (showDest && stickyNote.destinationCardId && destCard === undefined) { - dispatch(API.getCard(stickyNote.destinationCardId)); - } - }, [showDest, stickyNote.destinationCardId, destCard, dispatch]); - - return ( - - - {showModal === 'delete' && ( - - Are you sure you want to delete this sticky note? This will remove - it one the source as well. -

- } - onCancel={() => { - setShowModal(''); - }} - onConfirm={() => { - dispatch(API.deleteStickyNote(stickyNote)); - }} - confirmButtonLabel={'Delete sticky note'} - /> - )} - dispatch(API.updateStickyNote({ ...stickyNote, teaser: newValue }))} - inputDisplayClassName={css({ fontWeight: 'bold' })} - /> - setShowModal(value.value)} - entries={[ - { - value: 'delete', - label: ( - <> - {i18n.common.delete} - - ), - }, - ]} - /> -
- -
- {stickyNote.explanationId && ( -
-

- Explanation: -

- -
- )} - {showSrc && ( -
- {srcCard && typeof srcCard === 'object' && ( -
-

- Source: -

-

{srcCard.title}

-

Card #{srcCard.id}

- -
- )} -
- )} - {showDest && ( -
- {destCard && typeof destCard === 'object' && ( - - )} -
- )} -
-
-
- ); -} diff --git a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteList.tsx b/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteList.tsx deleted file mode 100644 index 6dc858d9e9e..00000000000 --- a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteList.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { css } from '@emotion/css'; -import { StickyNoteLink } from 'colab-rest-client'; -import * as React from 'react'; -import { compareById } from '../../store/selectors/selectorHelper'; -import { lightIconButtonStyle, space_lg } from '../../styling/style'; -import Flex from '../common/layout/Flex'; -import StickyNoteCreator from './StickyNoteCreator'; -import StickyNoteDisplay from './StickyNoteDisplay'; - -// TODO real sort order -function sortStickyNotes(a: StickyNoteLink, b: StickyNoteLink): number { - return compareById(a, b); -} - -export interface StickyNoteListProps { - stickyNotes: StickyNoteLink[]; - destCardId: number; - showSrc?: boolean; - showDest?: boolean; -} - -export default function StickyNoteList({ - stickyNotes, - destCardId, - showSrc = false, - showDest = false, -}: StickyNoteListProps): JSX.Element { - return ( - - - {stickyNotes.sort(sortStickyNotes).map(stickyNote => ( -
- -
- ))} -
- -
- ); -} diff --git a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteWrapper.tsx b/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteWrapper.tsx deleted file mode 100644 index 0c84b237ada..00000000000 --- a/colab-webapp/src/main/node/app/src/components/stickynotes/StickyNoteWrapper.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import * as React from 'react'; -import * as API from '../../API/api'; -import { useAppDispatch } from '../../store/hooks'; -import { useStickyNoteLinksForDest } from '../../store/selectors/stickyNoteLinkSelector'; -import InlineLoading from '../common/element/InlineLoading'; -import StickyNoteList from './StickyNoteList'; - -/** - * In this component, we load the sticky note links if necessary and display the StickyNoteList - */ - -export interface StickyNoteWrapperProps { - destCardId: number | undefined; - showSrc?: boolean; - showDest?: boolean; - // TODO complete with srcCardId, srcCardContentId, srcResourceId, srcBlockId -} - -export default function StickyNoteWrapper({ - destCardId, - showSrc, - showDest, -}: StickyNoteWrapperProps): JSX.Element { - const dispatch = useAppDispatch(); - - const { stickyNotesForDest, status } = useStickyNoteLinksForDest(destCardId); - const allStickyNotes = stickyNotesForDest; // to concat with StickyNotesForSrc... - - React.useEffect(() => { - if (status === 'NOT_INITIALIZED' && destCardId) { - dispatch(API.getStickyNoteLinkAsDest(destCardId)); - } - }, [status, dispatch, destCardId]); - - if (status === 'NOT_INITIALIZED') { - return ; - } else if (status === 'LOADING') { - return ; - } else if (allStickyNotes == null) { - return
no sticky notes list, no display
; - } else if (!destCardId) { - return
No destination card set.
; - } else { - return ( - - ); - } -} diff --git a/colab-webapp/src/main/node/app/src/i18n/en.ts b/colab-webapp/src/main/node/app/src/i18n/en.ts index fc0775e5c5d..e8fb9586ece 100644 --- a/colab-webapp/src/main/node/app/src/i18n/en.ts +++ b/colab-webapp/src/main/node/app/src/i18n/en.ts @@ -719,12 +719,6 @@ export const en = { presence: { date: (name: string, date: number) => `${name} is online (${en.common.ago(date)})`, }, - stickyNotes: { - stickyNotes: 'Sticky notes', - listStickyNotes: 'List of sticky notes stuck on the card', - snDescription: - 'Sticky notes come from a source (card, card specific version, resource, block)', - }, }, ////////////////////////////////////////////////////////////////////////////////////////////////// // Tips diff --git a/colab-webapp/src/main/node/app/src/i18n/fr.ts b/colab-webapp/src/main/node/app/src/i18n/fr.ts index f736b8e1e5f..4b2faf29d8c 100644 --- a/colab-webapp/src/main/node/app/src/i18n/fr.ts +++ b/colab-webapp/src/main/node/app/src/i18n/fr.ts @@ -735,12 +735,6 @@ export const fr: ColabTranslations = { presence: { date: (name: string, date: number) => `${name} est en ligne (${fr.common.ago(date)})`, }, - stickyNotes: { - stickyNotes: 'Post it', - listStickyNotes: 'Liste de post it sur la carte', - snDescription: - "Les post its proviennent d'une source (carte, version spécifique de la carte, documentation, bloc)", - }, }, ////////////////////////////////////////////////////////////////////////////////////////////////// // Tips diff --git a/colab-webapp/src/main/node/app/src/store/selectors/stickyNoteLinkSelector.ts b/colab-webapp/src/main/node/app/src/store/selectors/stickyNoteLinkSelector.ts deleted file mode 100644 index b02262f59f1..00000000000 --- a/colab-webapp/src/main/node/app/src/store/selectors/stickyNoteLinkSelector.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { StickyNoteLink } from 'colab-rest-client'; -import { useAppSelector } from '../hooks'; -import { LoadingStatus } from '../store'; - -//export const useStickyNoteLink = (id: number): StickyNoteLink | 'LOADING' | undefined => { -// return useAppSelector(state => { -// if (id != null) { -// const linkDetail = state.stickynotelinks.links[id]; - -// if (linkDetail === null) { -// return 'LOADING'; -// } else { -// return linkDetail; -// } -// } -// return undefined; -// }); -//}; - -export const useStickyNoteLinksForDest = ( - cardDestId: number | undefined | null, -): { - stickyNotesForDest: StickyNoteLink[]; - status: LoadingStatus; -} => { - return useAppSelector(state => { - if (cardDestId != null) { - const dataInStore = state.stickynotelinks.byCardDest[cardDestId]; - - if (dataInStore === undefined) { - return { - stickyNotesForDest: [], - status: 'NOT_INITIALIZED', - }; - } else { - const { stickyNoteIds, status } = dataInStore; - - if (status == 'LOADING') { - return { - stickyNotesForDest: [], - status: 'LOADING', - }; - } else { - return { - stickyNotesForDest: stickyNoteIds.flatMap(snId => { - const sn = state.stickynotelinks.stickyNotes[snId]; - return sn ? [sn] : []; - }), - status: 'READY', - }; - } - } - } - - return { stickyNotesForDest: [], status: 'NOT_INITIALIZED' }; - }); -}; - -// links: linkIds -// .map(linkId => { -// const p = state.stickynotelinks.allLinks[linkId]; -// return (p ? p.link : null); -// }) -// .filter((link: StickyNoteLink | null): link is StickyNoteLink => { return link != null }), diff --git a/colab-webapp/src/main/node/app/src/store/slice/stickynotelinkSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/stickynotelinkSlice.ts deleted file mode 100644 index 52be684b071..00000000000 --- a/colab-webapp/src/main/node/app/src/store/slice/stickynotelinkSlice.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { createSlice } from '@reduxjs/toolkit'; -import { StickyNoteLink } from 'colab-rest-client'; -import * as API from '../../API/api'; -import { processMessage } from '../../ws/wsThunkActions'; -import { LoadingStatus } from '../store'; - -export interface StickyNoteLinkState { - stickyNotes: Record; - byCardDest: Record; -} - -const initialState: StickyNoteLinkState = { - stickyNotes: {}, - byCardDest: {}, -}; - -// To handle when possible : destination change -const updateStickyNote = (state: StickyNoteLinkState, stickyNote: StickyNoteLink) => { - if (stickyNote.id != null) { - if (stickyNote.destinationCardId) { - const stateForDestCard = state.byCardDest[stickyNote.destinationCardId]; - if (stateForDestCard) { - // new sticky note handling - if (!stateForDestCard.stickyNoteIds.includes(stickyNote.id)) { - stateForDestCard.stickyNoteIds.push(stickyNote.id); - } - } - } - - state.stickyNotes[stickyNote.id] = stickyNote; - } -}; - -const removeStickyNote = (state: StickyNoteLinkState, stickyNoteId: number) => { - const stickyNoteState = state.stickyNotes[stickyNoteId]; - - if (stickyNoteState && stickyNoteState.destinationCardId) { - const stateForDestCard = state.byCardDest[stickyNoteState.destinationCardId]; - if (stateForDestCard) { - const index = stateForDestCard.stickyNoteIds.indexOf(stickyNoteId); - if (index >= 0) { - stateForDestCard.stickyNoteIds.splice(index, 1); - } - } - } - - delete state.stickyNotes[stickyNoteId]; -}; - -const stickyNoteLinksSlice = createSlice({ - name: 'stickynotelinks', - initialState, - reducers: {}, - extraReducers: builder => - builder - .addCase(processMessage.fulfilled, (state, action) => { - action.payload.stickynotelinks.upserted.forEach(sn => updateStickyNote(state, sn)); - action.payload.stickynotelinks.deleted.forEach(indexEntry => - removeStickyNote(state, indexEntry.id), - ); - }) - //.addCase(API.getStickyNoteLink.pending, (state, action) => { - // state.links[action.meta.arg] = null; - //}) - //.addCase(API.getStickyNoteLink.fulfilled, (state, action) => { - // if (action.payload.id) { - // state.links[action.payload.id] = action.payload; - // } - //}) - .addCase(API.getStickyNoteLinkAsDest.pending, (state, action) => { - state.byCardDest[action.meta.arg] = { stickyNoteIds: [], status: 'LOADING' }; - }) - .addCase(API.getStickyNoteLinkAsDest.fulfilled, (state, action) => { - state.byCardDest[action.meta.arg] = { - stickyNoteIds: action.payload.flatMap(sn => (sn.id ? [sn.id] : [])), - status: 'READY', - }; - - action.payload.forEach(stickyNote => { - if (stickyNote && stickyNote.id) { - state.stickyNotes[stickyNote.id] = stickyNote; - } - }); - }) - .addCase(API.closeCurrentProject.fulfilled, () => { - return initialState; - }) - .addCase(API.closeCurrentSession.fulfilled, () => { - return initialState; - }), -}); - -export default stickyNoteLinksSlice.reducer; diff --git a/colab-webapp/src/main/node/app/src/store/store.ts b/colab-webapp/src/main/node/app/src/store/store.ts index 9f02410d287..60a8ed2991e 100644 --- a/colab-webapp/src/main/node/app/src/store/store.ts +++ b/colab-webapp/src/main/node/app/src/store/store.ts @@ -16,13 +16,12 @@ import changeReducer from './slice/changeSlice'; import configReducer from './slice/configurationSlice'; import documentReducer from './slice/documentSlice'; import externalDataReducer from './slice/externalDataSlice'; -import notifReducer from './slice/notificationSlice'; import instanceMakerReducer from './slice/instanceMakerSlice'; +import notifReducer from './slice/notificationSlice'; import presenceReducer from './slice/presenceSlice'; import projectReducer from './slice/projectSlice'; import resourceReducer from './slice/resourceSlice'; import securityReducer from './slice/securitySlice'; -import stickyNoteLinkReducer from './slice/stickynotelinkSlice'; import teamMemberReducer from './slice/teamMemberSlice'; import teamRoleReducer from './slice/teamRoleSlice'; import teamReducer from './slice/teamSlice'; @@ -46,7 +45,6 @@ const rootReducer = combineReducers({ project: projectReducer, resources: resourceReducer, security: securityReducer, - stickynotelinks: stickyNoteLinkReducer, teamMembers: teamMemberReducer, teamRoles: teamRoleReducer, team: teamReducer, diff --git a/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts b/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts index 00250436c61..0a602b2925b 100644 --- a/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts +++ b/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts @@ -22,7 +22,6 @@ import { IndexEntry, InstanceMaker, Project, - StickyNoteLink, TeamMember, TeamRole, TypeMap, @@ -63,7 +62,6 @@ interface EntityBag { presences: Updates; projects: Updates; resources: Updates; - stickynotelinks: Updates; teamMembers: Updates; teamRoles: Updates; users: Updates; @@ -86,7 +84,6 @@ function createBag(): EntityBag { presences: { upserted: [], deleted: [] }, projects: { upserted: [], deleted: [] }, resources: { upserted: [], deleted: [] }, - stickynotelinks: { upserted: [], deleted: [] }, teamMembers: { upserted: [], deleted: [] }, teamRoles: { upserted: [], deleted: [] }, users: { upserted: [], deleted: [] }, @@ -129,7 +126,7 @@ export const processMessage = createAsyncThunk( } else if (indexEntryIs(item, 'AbstractResource')) { bag.resources.deleted.push(item); } else if (indexEntryIs(item, 'StickyNoteLink')) { - bag.stickynotelinks.deleted.push(item); + // nothing to do, we do not handle them anymore } else if (indexEntryIs(item, 'TeamMember')) { bag.teamMembers.deleted.push(item); } else if (indexEntryIs(item, 'TeamRole')) { @@ -175,7 +172,7 @@ export const processMessage = createAsyncThunk( } else if (entityIs(item, 'AbstractResource')) { bag.resources.upserted.push(item); } else if (entityIs(item, 'StickyNoteLink')) { - bag.stickynotelinks.upserted.push(item); + // nothing to do, we do not handle them anymore } else if (entityIs(item, 'TeamMember')) { bag.teamMembers.upserted.push(item); } else if (entityIs(item, 'TeamRole')) { From 22a34fe22f2f0a882fed28db7ec66370451408d9 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:47:08 +0100 Subject: [PATCH 047/116] wsThunkActions review --- .../main/node/app/src/store/slice/projectSlice.ts | 2 +- .../src/main/node/app/src/ws/wsThunkActions.ts | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts b/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts index f8b2531f58a..7c4c5f56b19 100644 --- a/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts +++ b/colab-webapp/src/main/node/app/src/store/slice/projectSlice.ts @@ -66,7 +66,7 @@ const projectSlice = createSlice({ } }); - action.payload.copyParam.upserted.forEach(copyParam => { + action.payload.copyParams.upserted.forEach(copyParam => { if (copyParam.projectId != null) { state.copyParams[copyParam.projectId] = copyParam; } diff --git a/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts b/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts index 0a602b2925b..656f3ef6e70 100644 --- a/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts +++ b/colab-webapp/src/main/node/app/src/ws/wsThunkActions.ts @@ -55,7 +55,7 @@ interface EntityBag { cardTypes: Updates; changes: Updates; contents: Updates; - copyParam: Updates; + copyParams: Updates; documents: Updates; httpSessions: Updates; instanceMakers: Updates; @@ -77,7 +77,7 @@ function createBag(): EntityBag { cardTypes: { upserted: [], deleted: [] }, changes: { upserted: [], deleted: [] }, contents: { upserted: [], deleted: [] }, - copyParam: { upserted: [], deleted: [] }, + copyParams: { upserted: [], deleted: [] }, documents: { upserted: [], deleted: [] }, httpSessions: { upserted: [], deleted: [] }, instanceMakers: { upserted: [], deleted: [] }, @@ -95,9 +95,12 @@ export const processMessage = createAsyncThunk( 'websocket/processUpdate', async (events: WsUpdateMessage[]) => { const bag = createBag(); + logger.info('Process ', events.length, ' messages'); + events.forEach((event, i) => { logger.info(` Message #${i}`, event); + for (const item of event.deleted) { if (indexEntryIs(item, 'Account')) { bag.accounts.deleted.push(item); @@ -114,7 +117,7 @@ export const processMessage = createAsyncThunk( } else if (indexEntryIs(item, 'CardContent')) { bag.contents.deleted.push(item); } else if (indexEntryIs(item, 'CopyParam')) { - bag.copyParam.deleted.push(item); + bag.copyParams.deleted.push(item); } else if (indexEntryIs(item, 'Document')) { bag.documents.deleted.push(item); } else if (indexEntryIs(item, 'HttpSession')) { @@ -160,7 +163,7 @@ export const processMessage = createAsyncThunk( } else if (entityIs(item, 'CardContent')) { bag.contents.upserted.push(item); } else if (entityIs(item, 'CopyParam')) { - bag.copyParam.upserted.push(item); + bag.copyParams.upserted.push(item); } else if (entityIs(item, 'Document')) { bag.documents.upserted.push(item); } else if (entityIs(item, 'HttpSession')) { @@ -182,7 +185,7 @@ export const processMessage = createAsyncThunk( } else if (entityIs(item, 'UserPresence')) { bag.presences.upserted.push(item); } else { - //If next line is erroneous, it means a type of entity is not handled + //If next line is erroneous, it means that a type of entity is not handled checkUnreachable(item); } } From 1a46e16afc3cb3030e351da02bd7b08a34f14e7c Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:57:56 +0100 Subject: [PATCH 048/116] style + theme superficial review --- .../components/common/layout/Collapsible.tsx | 4 +- .../components/resources/ResourcesList.tsx | 4 +- .../app/src/components/team/MembersList.tsx | 4 +- .../node/app/src/components/team/UserName.tsx | 4 +- .../src/main/node/app/src/styling/style.ts | 61 ++++++++++++++----- .../src/main/node/app/src/styling/theme.ts | 26 +++++++- 6 files changed, 78 insertions(+), 25 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/common/layout/Collapsible.tsx b/colab-webapp/src/main/node/app/src/components/common/layout/Collapsible.tsx index cdef21024c7..b080d9aefee 100644 --- a/colab-webapp/src/main/node/app/src/components/common/layout/Collapsible.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/layout/Collapsible.tsx @@ -9,7 +9,7 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; import useTranslations from '../../../i18n/I18nContext'; import { MaterialIconsType } from '../../../styling/IconType'; -import { space_md, space_sm, space_xs, text_semibold, text_xs } from '../../../styling/style'; +import { space_md, space_sm, space_xs, text_semiBold, text_xs } from '../../../styling/style'; import Flex from './Flex'; import Icon from './Icon'; @@ -25,7 +25,7 @@ const closeStyle = css({ const defaultLabelStyle = cx( text_xs, - text_semibold, + text_semiBold, css({ padding: space_xs + ' ' + space_md, backgroundColor: 'var(--bg-secondary)', diff --git a/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx b/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx index 0a3dd18d6d5..7045c964910 100644 --- a/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx +++ b/colab-webapp/src/main/node/app/src/components/resources/ResourcesList.tsx @@ -23,7 +23,7 @@ import { space_md, space_sm, space_xs, - text_semibold, + text_semiBold, text_xs, } from '../../styling/style'; import Tips from '../common/element/Tips'; @@ -494,7 +494,7 @@ function TocHeader({ category }: TocHeaderProps): JSX.Element {

{name}

diff --git a/colab-webapp/src/main/node/app/src/styling/style.ts b/colab-webapp/src/main/node/app/src/styling/style.ts index ed1058258aa..3faa03e4843 100644 --- a/colab-webapp/src/main/node/app/src/styling/style.ts +++ b/colab-webapp/src/main/node/app/src/styling/style.ts @@ -7,7 +7,8 @@ import { css, cx } from '@emotion/css'; import { ThemeType, br, heading, space, text, textOther } from './theme'; -//SPACE VARS +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SPACE export const space_2xs = space['2xs']; export const space_xs = space.xs; export const space_sm = space.sm; @@ -17,6 +18,8 @@ export const space_xl = space.xl; export const space_2xl = space['2xl']; export const space_3xl = space['3xl']; export const space_4xl = space['4xl']; + +//////////////////////////////////////////////////////////////////////////////////////////////////// // PADDING export const p_0 = css({ padding: space['0'] }); export const p_2xs = css({ padding: space['2xs'] }); @@ -29,6 +32,7 @@ export const p_2xl = css({ padding: space['2xl'] }); export const p_3xl = css({ padding: space['3xl'] }); export const p_4xl = css({ padding: space['4xl'] }); +//////////////////////////////////////////////////////////////////////////////////////////////////// // MARGIN export const m_0 = css({ margin: space['0'] }); export const m_2xs = css({ margin: space['2xs'] }); @@ -41,23 +45,27 @@ export const m_2xl = css({ margin: space['2xl'] }); export const m_3xl = css({ margin: space['3xl'] }); export const m_4xl = css({ margin: space['4xl'] }); -//BORDER RADIUS +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BORDER RADIUS export const br_sm = css({ borderRadius: br.sm }); export const br_md = css({ borderRadius: br.md }); export const br_lg = css({ borderRadius: br.lg }); export const br_xl = css({ borderRadius: br.xl }); export const br_full = css({ borderRadius: br.full }); -//TEXT VARS +//////////////////////////////////////////////////////////////////////////////////////////////////// +// TEXT export const text_xs = css({ fontSize: text.xs }); export const text_sm = css({ fontSize: text.sm }); export const text_md = css({ fontSize: text.md }); export const text_lg = css({ fontSize: text.lg }); export const text_xl = css({ fontSize: text.xl }); export const text_regular = css({ fontWeight: text.regular }); -export const text_semibold = css({ fontWeight: text.semibold }); +export const text_semiBold = css({ fontWeight: text.semiBold }); export const text_lineHeight = css({ lineHeight: text.lineHeight }); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// HEADING export const heading_xs = css({ fontSize: heading.xs, fontWeight: heading.weight }); export const heading_sm = css({ fontSize: heading.sm, fontWeight: heading.weight }); export const heading_md = css({ fontSize: heading.md, fontWeight: heading.weight }); @@ -66,7 +74,8 @@ export const heading_xl = css({ fontSize: heading.xl, fontWeight: heading.weight export const heading_weight = css({ fontWeight: heading.weight }); export const heading_lineHeight = css({ lineHeight: heading.lineHeight }); -//TEXT +//////////////////////////////////////////////////////////////////////////////////////////////////// +// TEXT export const lightTextStyle = css({ color: 'var(--text-secondary)', @@ -76,7 +85,9 @@ export const underlineTextStyle = css({ textDecoration: 'underline', }); -//TEXT MODES +//////////////////////////////////////////////////////////////////////////////////////////////////// +// TEXT MODES + export const errorTextStyle = css({ color: 'var(--error-main)', }); @@ -90,18 +101,18 @@ export const disabledTextStyle = css({ color: 'var(--text-disabled)', }); -export const errorborderStyle = css({ +export const errorBorderStyle = css({ border: '1px solid var(--error-main)', }); -export const warningborderStyle = css({ +export const warningBorderStyle = css({ border: '1px solid var(--warning-main)', }); -export const successborderStyle = css({ +export const successBorderStyle = css({ border: '1px solid var(--success-main)', }); +//////////////////////////////////////////////////////////////////////////////////////////////////// // TEXT ELLIPSIS - export const multiLineEllipsisStyle = css({ display: '-webkit-box', WebkitLineClamp: '2', @@ -120,6 +131,7 @@ export const ellipsisStyle = css({ whiteSpace: 'nowrap', }); +//////////////////////////////////////////////////////////////////////////////////////////////////// // GENERAL export const foregroundStyle = css({ zIndex: 9999, @@ -157,7 +169,8 @@ export const disabledStyle = css({ ...disabled, }); -//INPUTS +//////////////////////////////////////////////////////////////////////////////////////////////////// +// INPUTS export const removeOutlineStyle = css({ '&:focus': { @@ -168,7 +181,8 @@ export const removeOutlineStyle = css({ }, }); -//LINKS +//////////////////////////////////////////////////////////////////////////////////////////////////// +// LINKS export const linkStyle = cx( removeOutlineStyle, @@ -195,7 +209,9 @@ export const inheritedDefaultTextStyle = css({ textDecoration: 'none', }); -//ICON BUTTONS STYLES +//////////////////////////////////////////////////////////////////////////////////////////////////// +// ICON BUTTONS STYLES + export const iconButtonStyle = cx( p_sm, br_md, @@ -280,7 +296,9 @@ export function GhostIconButtonStyle(theme?: ThemeType) { } else return ghostIconButtonStyle; } +//////////////////////////////////////////////////////////////////////////////////////////////////// // BUTTON STYLES + export const buttonStyle = cx( br_full, css({ @@ -352,7 +370,9 @@ export function OutlineButtonStyle(theme: ThemeType): string { ); } +//////////////////////////////////////////////////////////////////////////////////////////////////// // CARD + export const cardStyle = cx( br_md, css({ @@ -364,12 +384,16 @@ export const cardStyle = cx( }), ); -//TAG +//////////////////////////////////////////////////////////////////////////////////////////////////// +// TAG + export const labelStyle = css({ fontWeight: 500, }); -//TABLES +//////////////////////////////////////////////////////////////////////////////////////////////////// +// TABLES + const titleCellStyle = css({ fontSize: textOther.th.sm, fontWeight: textOther.th.weight, @@ -382,6 +406,8 @@ const titleCellStyle = css({ export const th_sm = cx(titleCellStyle, text_xs); export const th_lg = cx(titleCellStyle, text_sm); +//////////////////////////////////////////////////////////////////////////////////////////////////// + /* export function rootViewCardsStyle(depth: number, inRootView: boolean) { if (inRootView) { if (depth === 1) { @@ -414,8 +440,11 @@ export const th_lg = cx(titleCellStyle, text_sm); } } } */ +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// // DELETED BANNER + export const deletedBannerStyle = css({ padding: '0 ' + space_sm, color: 'var(--white)', @@ -437,7 +466,9 @@ export const deletedBannerButtonStyle = css({ borderColor: 'var(--white)', }); +//////////////////////////////////////////////////////////////////////////////////////////////////// // BIN + export const binTableStyle = cx( text_xs, css({ diff --git a/colab-webapp/src/main/node/app/src/styling/theme.ts b/colab-webapp/src/main/node/app/src/styling/theme.ts index dd1b8f6a2c3..26a7461e8ae 100644 --- a/colab-webapp/src/main/node/app/src/styling/theme.ts +++ b/colab-webapp/src/main/node/app/src/styling/theme.ts @@ -7,12 +7,16 @@ import { css, cx } from '@emotion/css'; export type GeneralSizeType = 'xs' | 'sm' | 'md' | 'lg'; export type ThemeType = 'primary' | 'success' | 'warning' | 'error'; -// new UI + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// color variations + const basics = css({ '--white': '#FFF', '--black': '#000', '--transparent': 'transparent', }); + const primary = css({ '--primary-50': '#E6FFFA', '--primary-100': '#B2F5EA', @@ -21,6 +25,7 @@ const primary = css({ '--primary-500': '#2C7A7B', '--primary-700': '#285E61', }); + const gray = css({ '--gray-50': '#F7FAFC', '--gray-100': '#EDF2F7', @@ -31,6 +36,7 @@ const gray = css({ '--gray-600': '#43444B', '--gray-700': '#28292D', }); + const blackAlpha = css({ '--blackAlpha-50': '#000000a', '--blackAlpha-100': '#000000f', @@ -43,6 +49,7 @@ const blackAlpha = css({ '--blackAlpha-800': '#000000CC', '--blackAlpha-900': '#000000EB', }); + const whiteAlpha = css({ '--whiteAlpha-50': '#FFFFFFA', '--whiteAlpha-100': '#FFFFFFF', @@ -55,6 +62,7 @@ const whiteAlpha = css({ '--whiteAlpha-800': '#FFFFFFCC', '--whiteAlpha-900': '#FFFFFFEB', }); + const green = css({ '--green-50': '#EDFAF3', '--green-100': '#C2F0D8', @@ -64,6 +72,7 @@ const green = css({ '--green-600': '#238F56', '--green-700': '#19663E', }); + const red = css({ '--red-100': '#FED7D7', '--red-400': '#EA6262', @@ -71,6 +80,7 @@ const red = css({ '--red-600': '#C53030', '--red-700': '#9B2C2C', }); + const orange = css({ '--orange-50': '#FCF4EE', '--orange-100': '#FEEBC8', @@ -79,6 +89,7 @@ const orange = css({ '--orange-600': '#C05621', '--orange-700': '#9C4221', }); + const blue = css({ '--blue-50': '#E7F9FD', '--blue-100': '#BEE3F8', @@ -87,6 +98,7 @@ const blue = css({ '--blue-600': '#2B6CB0', '--blue-700': '#2C5282', }); + /*Colors to be updated -- in progress */ /*const purple = css({ '--blue-50': '#E7F9FD', @@ -97,6 +109,10 @@ const blue = css({ '--blue-700': '#2C5282', }); */ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// color choices + export const projectColors = { yellow: '#ECC94B', orange: '#E68D52', @@ -176,6 +192,8 @@ const otherColors = css({ '--teal-400': projectColors.teal, }); +//////////////////////////////////////////////////////////////////////////////////////////////////// + const colabTheme = cx( basics, primary, @@ -237,12 +255,16 @@ export const lightMode = cx( }), ); +//////////////////////////////////////////////////////////////////////////////////////////////////// //FONT + export const fonts = css({ fontFamily: "'Public Sans', 'sans serif'", }); +//////////////////////////////////////////////////////////////////////////////////////////////////// //TEXT SIZE + export const text = { xs: '12px', sm: '14px', @@ -250,7 +272,7 @@ export const text = { lg: '18px', xl: '20px', lineHeight: '120%', - semibold: 700, + semiBold: 700, regular: 400, }; export const heading = { From 9ff89cf34e17bc7683f4a5040d719f382b88dbd3 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:00:15 +0100 Subject: [PATCH 049/116] import 'react-reflex/styles.css'; review --- .../src/main/node/app/src/components/cards/CardEditor.tsx | 1 + .../src/main/node/app/src/components/cards/CardEditorHeader.tsx | 1 - .../main/node/app/src/components/cards/CardEditorSideMenu.tsx | 1 - .../main/node/app/src/components/cards/CardEditorSidePanel.tsx | 1 - .../main/node/app/src/components/cards/CardEditorSubCards.tsx | 1 - .../main/node/app/src/components/projects/SidePanelWrapper.tsx | 1 + .../main/node/app/src/components/resources/ResourceDisplay.tsx | 1 + 7 files changed, 3 insertions(+), 4 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx index 01a2d3e709b..516dd08d82c 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx @@ -9,6 +9,7 @@ import { css } from '@emotion/css'; import { Card, CardContent } from 'colab-rest-client'; import * as React from 'react'; import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; +import 'react-reflex/styles.css'; import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch } from '../../store/hooks'; diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardEditorHeader.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardEditorHeader.tsx index 27c4a09c7b9..4af3ada8fc7 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardEditorHeader.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardEditorHeader.tsx @@ -8,7 +8,6 @@ import { css } from '@emotion/css'; import { Card, CardContent, entityIs } from 'colab-rest-client'; import * as React from 'react'; -import 'react-reflex/styles.css'; import { useNavigate } from 'react-router-dom'; import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardEditorSideMenu.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardEditorSideMenu.tsx index 0cc9fa4bbd5..12eb462f34e 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardEditorSideMenu.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardEditorSideMenu.tsx @@ -8,7 +8,6 @@ import { css } from '@emotion/css'; import { Card, CardContent } from 'colab-rest-client'; import * as React from 'react'; -import 'react-reflex/styles.css'; import { useVariantsOrLoad } from '../../store/selectors/cardSelector'; import { useAndLoadNbDirectActiveResources } from '../../store/selectors/resourceSelector'; import SideCollapsibleMenu from '../common/layout/SideCollapsibleMenu'; diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardEditorSidePanel.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardEditorSidePanel.tsx index 136781b8830..3ff08ae271b 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardEditorSidePanel.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardEditorSidePanel.tsx @@ -8,7 +8,6 @@ import { css } from '@emotion/css'; import { Card, CardContent } from 'colab-rest-client'; import * as React from 'react'; -import 'react-reflex/styles.css'; import { useVariantsOrLoad } from '../../store/selectors/cardSelector'; import SideCollapsiblePanel from '../common/layout/SideCollapsiblePanel'; import { DisplayMode, ResourcesCtx } from '../resources/ResourcesMainView'; diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardEditorSubCards.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardEditorSubCards.tsx index 488f36ed91d..235c631a313 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardEditorSubCards.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardEditorSubCards.tsx @@ -8,7 +8,6 @@ import { css } from '@emotion/css'; import { Card, CardContent } from 'colab-rest-client'; import * as React from 'react'; -import 'react-reflex/styles.css'; import { useVariantsOrLoad } from '../../store/selectors/cardSelector'; import Flex from '../common/layout/Flex'; import CardThumb from './CardThumb'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/SidePanelWrapper.tsx b/colab-webapp/src/main/node/app/src/components/projects/SidePanelWrapper.tsx index 3bac94579f1..b2c4ae29bb8 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/SidePanelWrapper.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/SidePanelWrapper.tsx @@ -7,6 +7,7 @@ import { css } from '@emotion/css'; import * as React from 'react'; import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; +import 'react-reflex/styles.css'; import { useNavigate } from 'react-router-dom'; import { space_md, space_sm } from '../../styling/style'; import IconButton from '../common/element/IconButton'; diff --git a/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx b/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx index 2bfbbb4b607..f3ed174b5e0 100644 --- a/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx +++ b/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx @@ -8,6 +8,7 @@ import { css, cx } from '@emotion/css'; import * as React from 'react'; import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; +import 'react-reflex/styles.css'; import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch } from '../../store/hooks'; From 38eb1da99dde3140931aa049db3b8014ed08ecd1 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:02:32 +0100 Subject: [PATCH 050/116] Black&white picto / logo put in main picto / logo --- .../src/main/node/app/src/styling/Logo.tsx | 16 ++++++++++ .../src/main/node/app/src/styling/Picto.tsx | 4 +++ .../src/main/node/app/src/styling/PictoBw.tsx | 17 ----------- .../main/node/app/src/styling/WhiteLogo.tsx | 29 ------------------- 4 files changed, 20 insertions(+), 46 deletions(-) delete mode 100644 colab-webapp/src/main/node/app/src/styling/PictoBw.tsx delete mode 100644 colab-webapp/src/main/node/app/src/styling/WhiteLogo.tsx diff --git a/colab-webapp/src/main/node/app/src/styling/Logo.tsx b/colab-webapp/src/main/node/app/src/styling/Logo.tsx index 924fd1c0c36..c84a37f49fc 100644 --- a/colab-webapp/src/main/node/app/src/styling/Logo.tsx +++ b/colab-webapp/src/main/node/app/src/styling/Logo.tsx @@ -5,6 +5,7 @@ * Licensed under the MIT License */ +import { css, cx } from '@emotion/css'; import * as React from 'react'; import LogoSvg from '../images/logo.svg'; @@ -15,3 +16,18 @@ export interface LogoProps { export default function Logo({ className }: LogoProps): JSX.Element { return ; } + +export function WhiteLogo({ className }: LogoProps): JSX.Element { + return ( + path': { + fill: 'var(--text-primary)', + }, + }), + className, + )} + /> + ); +} diff --git a/colab-webapp/src/main/node/app/src/styling/Picto.tsx b/colab-webapp/src/main/node/app/src/styling/Picto.tsx index 7b029a2200d..9330f55d0b8 100644 --- a/colab-webapp/src/main/node/app/src/styling/Picto.tsx +++ b/colab-webapp/src/main/node/app/src/styling/Picto.tsx @@ -15,3 +15,7 @@ export interface PictoProps { export default function Picto({ className }: PictoProps): JSX.Element { return ; } + +export function PictoBw({ className }: PictoProps): JSX.Element { + return ; +} diff --git a/colab-webapp/src/main/node/app/src/styling/PictoBw.tsx b/colab-webapp/src/main/node/app/src/styling/PictoBw.tsx deleted file mode 100644 index 22d16a71390..00000000000 --- a/colab-webapp/src/main/node/app/src/styling/PictoBw.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import * as React from 'react'; -import Picto from '../images/picto_bw.svg'; - -export interface PictoProps { - className?: string; -} - -export default function PictoBw({ className }: PictoProps): JSX.Element { - return ; -} diff --git a/colab-webapp/src/main/node/app/src/styling/WhiteLogo.tsx b/colab-webapp/src/main/node/app/src/styling/WhiteLogo.tsx deleted file mode 100644 index 41b47f471cc..00000000000 --- a/colab-webapp/src/main/node/app/src/styling/WhiteLogo.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { css, cx } from '@emotion/css'; -import * as React from 'react'; -import Logo from './Logo'; - -export interface LogoProps { - className?: string; -} - -export default function WhiteLogo({ className }: LogoProps): JSX.Element { - return ( - path': { - fill: 'var(--text-primary)', - }, - }), - className, - )} - /> - ); -} From b6535110a025468f8ecdf86f5731f6ae7c6c09db Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:17:49 +0100 Subject: [PATCH 051/116] use default chosen icons --- .../src/main/node/app/src/components/admin/LiveMonitor.tsx | 3 ++- .../main/node/app/src/components/cards/CardEditorHeader.tsx | 4 ++-- .../src/main/node/app/src/components/cards/CardThumb.tsx | 4 ++-- .../node/app/src/components/cardtypes/CardTypeEditor.tsx | 3 ++- .../main/node/app/src/components/cardtypes/CardTypeItem.tsx | 6 ++++-- .../node/app/src/components/cardtypes/CardTypeThumbnail.tsx | 3 ++- .../app/src/components/documents/DocumentEditorToolbox.tsx | 5 +++-- .../FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx | 5 +++-- .../src/main/node/app/src/components/live/ChangeTree.tsx | 5 +++-- .../main/node/app/src/components/projects/ProjectThumb.tsx | 4 ++-- .../projects/creation/ProjectDataInitialization.tsx | 5 +++-- .../app/src/components/projects/models/SharedModelsList.tsx | 6 ++++-- .../node/app/src/components/resources/ResourceDisplay.tsx | 4 ++-- .../node/app/src/components/resources/ResourcesList.tsx | 4 ++-- .../main/node/app/src/components/settings/UserSessions.tsx | 6 +++++- .../node/app/src/components/team/InstanceMakersList.tsx | 3 ++- .../src/main/node/app/src/components/team/MembersList.tsx | 3 ++- .../src/main/node/app/src/components/team/RolesTable.tsx | 3 ++- 18 files changed, 47 insertions(+), 29 deletions(-) diff --git a/colab-webapp/src/main/node/app/src/components/admin/LiveMonitor.tsx b/colab-webapp/src/main/node/app/src/components/admin/LiveMonitor.tsx index a0d53016ee1..7a97a91ae03 100644 --- a/colab-webapp/src/main/node/app/src/components/admin/LiveMonitor.tsx +++ b/colab-webapp/src/main/node/app/src/components/admin/LiveMonitor.tsx @@ -10,6 +10,7 @@ import { BlockMonitoring } from 'colab-rest-client'; import * as React from 'react'; import * as API from '../../API/api'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; +import { putInBinDefaultIcon } from '../../styling/IconDefault'; import AvailabilityStatusIndicator from '../common/element/AvailabilityStatusIndicator'; import Button from '../common/element/Button'; import IconButton from '../common/element/IconButton'; @@ -59,7 +60,7 @@ function Grid({ data, sync }: { data: BlockMonitoring[]; sync: () => void }): JS {entry.status === 'DELETED' && ( } className={css({ diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx index 5184e947bbc..18c7398ee24 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeItem.tsx @@ -12,6 +12,7 @@ import * as API from '../../API/api'; import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch } from '../../store/hooks'; import { useCurrentProjectId } from '../../store/selectors/projectSelector'; +import { dropDownMenuDefaultIcon, putInBinDefaultIcon } from '../../styling/IconDefault'; import { lightIconButtonStyle, space_lg, space_sm } from '../../styling/style'; import { CardTypeAllInOne as CardType } from '../../types/cardTypeDefinition'; import { ConfirmDeleteModal } from '../common/layout/ConfirmDeleteModal'; @@ -55,7 +56,7 @@ export default function CardTypeItem({ cardType, usage }: CardTypeItemProps): JS

{cardType.title || i18n.modules.cardType.titlePlaceholder}

- {i18n.common.delete} + {' '} + {i18n.common.delete} ), action: () => setShowDelete(true), diff --git a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx index dcf12f48bb5..739d6d05d24 100644 --- a/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx +++ b/colab-webapp/src/main/node/app/src/components/cardtypes/CardTypeThumbnail.tsx @@ -14,6 +14,7 @@ import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch, useLoadingState } from '../../store/hooks'; import { useAllProjectCardTypes } from '../../store/selectors/cardSelector'; import { useCurrentProjectId } from '../../store/selectors/projectSelector'; +import { dropDownMenuDefaultIcon } from '../../styling/IconDefault'; import { lightIconButtonStyle, multiLineEllipsisStyle, @@ -101,7 +102,7 @@ export default function CardTypeThumbnail({
{editable && ( {}} className={toolboxButtonStyle} diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx index 1ed1e0879a8..96551c2c9ea 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/FloatingToolbarPlugin/FloatingLinkEditorPlugin.tsx @@ -23,6 +23,7 @@ import { import * as React from 'react'; import { createPortal } from 'react-dom'; import useTranslations from '../../../../../i18n/I18nContext'; +import { putInBinDefaultIcon } from '../../../../../styling/IconDefault'; import { lightIconButtonStyle, space_md } from '../../../../../styling/style'; import IconButton from '../../../../common/element/IconButton'; import { inputStyle } from '../../../../common/element/Input'; @@ -31,7 +32,7 @@ import Icon from '../../../../common/layout/Icon'; import { getSelectedNode } from '../../utils/getSelectedNode'; import { setFloatingElemPosition } from '../../utils/setFloatingElemPosition'; import { sanitizeUrl } from '../../utils/url'; -import { activeToolbarButtonStyle, TOGGLE_LINK_MENU_COMMAND } from '../ToolbarPlugin/ToolbarPlugin'; +import { TOGGLE_LINK_MENU_COMMAND, activeToolbarButtonStyle } from '../ToolbarPlugin/ToolbarPlugin'; import { floatingToolbarStyle } from './FloatingTextFormatPlugin'; const linkStyle = css({ @@ -291,7 +292,7 @@ function FloatingLinkEditor({ className={activeToolbarButtonStyle} />

{i18n.modules.content.tree}

{onDelete ? ( - + ) : null}
{ diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx index b5326abe2c2..7354fa7f45e 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx @@ -7,7 +7,7 @@ import useTranslations from '../../i18n/I18nContext'; import { useAppDispatch } from '../../store/hooks'; import { useCurrentUser } from '../../store/selectors/userSelector'; import { addNotification } from '../../store/slice/notificationSlice'; -import { putInBinDefaultIcon } from '../../styling/IconDefault'; +import { dropDownMenuDefaultIcon, putInBinDefaultIcon } from '../../styling/IconDefault'; import { ellipsisStyle, lightIconButtonStyle, @@ -99,7 +99,7 @@ export default function ProjectThumb({ project, className }: ProjectThumbProps) {guest} {!readOnly && ( removeGuest(guest)} className={lightIconButtonStyle} diff --git a/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx b/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx index 81dc19de179..54a50a74a1f 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx @@ -16,6 +16,7 @@ import { useAppDispatch } from '../../../store/hooks'; import { useAndLoadInstanceableModels } from '../../../store/selectors/projectSelector'; import { compareById } from '../../../store/selectors/selectorHelper'; import { AvailabilityStatus } from '../../../store/store'; +import { dropDownMenuDefaultIcon, putInBinDefaultIcon } from '../../../styling/IconDefault'; import { br_lg, lightIconButtonStyle, @@ -115,7 +116,7 @@ export default function SharedModelsList({ : i18n.modules.project.info.emptyProject} - remove from list + remove + from list ), //action: () => ... diff --git a/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx b/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx index f3ed174b5e0..bc0452b252f 100644 --- a/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx +++ b/colab-webapp/src/main/node/app/src/components/resources/ResourceDisplay.tsx @@ -15,7 +15,7 @@ import { useAppDispatch } from '../../store/hooks'; import { useAndLoadTextOfDocument } from '../../store/selectors/documentSelector'; import { useCurrentUser } from '../../store/selectors/userSelector'; import { addNotification } from '../../store/slice/notificationSlice'; -import { putInBinDefaultIcon } from '../../styling/IconDefault'; +import { dropDownMenuDefaultIcon, putInBinDefaultIcon } from '../../styling/IconDefault'; import { lightIconButtonStyle, oneLineEllipsisStyle, @@ -245,7 +245,7 @@ export function ResourceDisplay({
) : ( )} */} {!isMySession(s) ? ( - - } - modalBodyClassName={css({ alignItems: 'stretch' })} - footer={close => ( - - - - {showBackButton && ( - - )} - - {showNextButton && } - - {showCreateButton && ( - - )} - - )} - > - {() => ( - <> - {status === 'chooseModel' ? ( - - setData({ - ...data, - projectModel: selectedModel, - illustration: { - ...(selectedModel?.illustration || defaultData.illustration), - }, - }) - } - whenDone={oneStepForwardCb} - /> - ) : ( - setData({ ...data, name: name })} - setDescription={description => setData({ ...data, description: description })} - setIllustration={illustration => setData({ ...data, illustration: illustration })} - addGuest={guestEmailAddress => { - if (guestEmailAddress != null && guestEmailAddress.length > 0) { - const guests = data.guests; - guests.push(guestEmailAddress); - setData({ ...data, guests: guests }); - } - }} - removeGuest={guestEmailAddress => { - const guests = data.guests; - const index = guests.indexOf(guestEmailAddress); - guests.splice(index, 1); - setData({ ...data, guests: guests }); - }} - /> - )} - {/* debug mode */} - {/* - {data.name || 'no name'} - {data.description || 'no description'} - - - - {data.guests.length} - {data.projectModel?.name || 'no project model'} - */} - - )} - - ); -} diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx deleted file mode 100644 index 4fc6094d34d..00000000000 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/ProjectDataInitialization.tsx +++ /dev/null @@ -1,202 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import { css, cx } from '@emotion/css'; -import { Illustration } from 'colab-rest-client'; -import * as React from 'react'; -import { assertEmailFormat } from '../../../helper'; -import useTranslations from '../../../i18n/I18nContext'; -import { putInBinDefaultIcon } from '../../../styling/IconDefault'; -import { - OutlineButtonStyle, - labelStyle, - lightIconButtonStyle, - space_lg, - space_sm, - text_sm, -} from '../../../styling/style'; -import Button from '../../common/element/Button'; -import { ConfirmIconButton } from '../../common/element/ConfirmIconButton'; -import Form from '../../common/element/Form'; -import IllustrationDisplay from '../../common/element/IllustrationDisplay'; -import { FormInput } from '../../common/element/Input'; -import IllustrationPicker from '../../common/illustration/IllustrationPicker'; -import Flex from '../../common/layout/Flex'; -import Icon from '../../common/layout/Icon'; -import { defaultProjectIllustration, projectIcons } from '../ProjectCommon'; -import { ProjectCreationData } from './ProjectCreator'; - -const projectIllustrationOverlay = css({ - position: 'absolute', - top: 0, - left: 0, - bottom: 0, - right: 0, - opacity: 0, - padding: space_sm, - '&:hover': { - backgroundColor: 'rgba(256, 256, 256, 0.4)', - opacity: 1, - cursor: 'pointer', - }, -}); - -interface ProjectDataInitializationProps { - data: ProjectCreationData; - readOnly?: boolean; - setName: (value: string) => void; - setDescription: (value: string) => void; - setIllustration: (value: Illustration) => void; - addGuest: (emailAddress: string) => void; - removeGuest: (emailAddress: string) => void; -} - -export default function ProjectDataInitialization({ - data, - readOnly, - setName, - setDescription, - setIllustration, - addGuest, - removeGuest, -}: ProjectDataInitializationProps): JSX.Element { - const i18n = useTranslations(); - - const [editIllustration, setEditIllustration] = React.useState(false); - const [currentIllustration, setCurrentIllustration] = React.useState( - data.projectModel?.illustration || defaultProjectIllustration, - ); - - return ( - -
{i18n.common.icon}
- {editIllustration ? ( - - - - - - - - ) : ( - setEditIllustration(true)} - > - - - - - - )} - setName(name)} - /> - { - setDescription(description); - }} - /> - - {/* */} - - -
value.email.length > 0 && !assertEmailFormat(value.email), - errorMessage: i18n.authentication.error.emailAddressNotValid, - }, - ]} - value={{ email: '' }} - onSubmit={fields => { - if (!readOnly) { - addGuest(fields.email); - fields.email = ''; - } - }} - submitLabel={i18n.common.add} - className={css({ flexDirection: 'row', alignItems: 'flex-end' })} - buttonClassName={cx( - css({ alignSelf: 'flex-end', margin: space_sm }), - OutlineButtonStyle('primary'), - )} - /> - - - {data.guests.map(guest => ( - - {guest} - {!readOnly && ( - removeGuest(guest)} - className={lightIconButtonStyle} - /> - )} - - ))} - - - - ); -} From 27c6fbc3a6b524bc9386bfef1ce868ef99f3021a Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Wed, 27 Dec 2023 12:29:54 +0100 Subject: [PATCH 054/116] move color + illustration --- .../app/src/components/cards/CardEditor.tsx | 2 +- .../app/src/components/cards/CardThumb.tsx | 2 +- .../common/element/{ => color}/ColorPicker.tsx | 0 .../{ => illustration}/IllustrationDisplay.tsx | 10 +++++----- .../illustration/IllustrationPicker.tsx | 18 +++++++++--------- .../plugins/ToolbarPlugin/ToolbarPlugin.tsx | 2 +- .../app/src/components/projects/ProjectNav.tsx | 2 +- .../src/components/projects/ProjectThumb.tsx | 2 +- .../projects/creation/NewProjectCreator.tsx | 4 ++-- .../projects/models/ProjectModelExtractor.tsx | 4 ++-- .../projects/models/ProjectModelSelector.tsx | 2 +- .../projects/models/SharedModelsList.tsx | 2 +- .../settings/ProjectSettingsGeneral.tsx | 2 +- 13 files changed, 26 insertions(+), 26 deletions(-) rename colab-webapp/src/main/node/app/src/components/common/element/{ => color}/ColorPicker.tsx (100%) rename colab-webapp/src/main/node/app/src/components/common/element/{ => illustration}/IllustrationDisplay.tsx (85%) rename colab-webapp/src/main/node/app/src/components/common/{ => element}/illustration/IllustrationPicker.tsx (89%) diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx index 516dd08d82c..a48509a4130 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardEditor.tsx @@ -17,7 +17,7 @@ import { useCardACLForCurrentUser } from '../../store/selectors/aclSelector'; import { useAndLoadSubCards } from '../../store/selectors/cardSelector'; import { space_md, space_sm, space_xs } from '../../styling/style'; import { cardColors } from '../../styling/theme'; -import { ColorPicker } from '../common/element/ColorPicker'; +import { ColorPicker } from '../common/element/color/ColorPicker'; import Flex from '../common/layout/Flex'; import { Item, SideCollapsibleCtx } from '../common/layout/SideCollapsibleContext'; import { TextEditorContext } from '../documents/texteditor/TextEditorContext'; diff --git a/colab-webapp/src/main/node/app/src/components/cards/CardThumb.tsx b/colab-webapp/src/main/node/app/src/components/cards/CardThumb.tsx index 74570eb835f..dd6404d1acf 100644 --- a/colab-webapp/src/main/node/app/src/components/cards/CardThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/cards/CardThumb.tsx @@ -24,11 +24,11 @@ import { text_xs, } from '../../styling/style'; import { cardColors } from '../../styling/theme'; -import { ColorPicker } from '../common/element/ColorPicker'; import DeletionStatusIndicator from '../common/element/DeletionStatusIndicator'; import { DiscreetInput, DiscreetTextArea } from '../common/element/Input'; import { Link } from '../common/element/Link'; import { FeaturePreview } from '../common/element/Tips'; +import { ColorPicker } from '../common/element/color/ColorPicker'; import DropDownMenu from '../common/layout/DropDownMenu'; import Flex from '../common/layout/Flex'; import Icon from '../common/layout/Icon'; diff --git a/colab-webapp/src/main/node/app/src/components/common/element/ColorPicker.tsx b/colab-webapp/src/main/node/app/src/components/common/element/color/ColorPicker.tsx similarity index 100% rename from colab-webapp/src/main/node/app/src/components/common/element/ColorPicker.tsx rename to colab-webapp/src/main/node/app/src/components/common/element/color/ColorPicker.tsx diff --git a/colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx b/colab-webapp/src/main/node/app/src/components/common/element/illustration/IllustrationDisplay.tsx similarity index 85% rename from colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx rename to colab-webapp/src/main/node/app/src/components/common/element/illustration/IllustrationDisplay.tsx index b6724d155fe..4d0fbed58ec 100644 --- a/colab-webapp/src/main/node/app/src/components/common/element/IllustrationDisplay.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/illustration/IllustrationDisplay.tsx @@ -8,11 +8,11 @@ import { css, cx } from '@emotion/css'; import { Illustration } from 'colab-rest-client'; import * as React from 'react'; -import { MaterialIconsType } from '../../../styling/IconType'; -import { space_sm } from '../../../styling/style'; -import { defaultProjectIllustration } from '../../projects/ProjectCommon'; -import Flex, { FlexProps } from '../layout/Flex'; -import Icon, { IconSize } from '../layout/Icon'; +import { MaterialIconsType } from '../../../../styling/IconType'; +import { space_sm } from '../../../../styling/style'; +import { defaultProjectIllustration } from '../../../projects/ProjectCommon'; +import Flex, { FlexProps } from '../../layout/Flex'; +import Icon, { IconSize } from '../../layout/Icon'; interface IllustrationDisplayProps { illustration: Illustration | undefined | null; diff --git a/colab-webapp/src/main/node/app/src/components/common/illustration/IllustrationPicker.tsx b/colab-webapp/src/main/node/app/src/components/common/element/illustration/IllustrationPicker.tsx similarity index 89% rename from colab-webapp/src/main/node/app/src/components/common/illustration/IllustrationPicker.tsx rename to colab-webapp/src/main/node/app/src/components/common/element/illustration/IllustrationPicker.tsx index 0c203206bb2..fe2a614fa9e 100644 --- a/colab-webapp/src/main/node/app/src/components/common/illustration/IllustrationPicker.tsx +++ b/colab-webapp/src/main/node/app/src/components/common/element/illustration/IllustrationPicker.tsx @@ -8,15 +8,15 @@ import { css, cx } from '@emotion/css'; import { Illustration } from 'colab-rest-client'; import * as React from 'react'; -import useTranslations from '../../../i18n/I18nContext'; -import { MaterialIconsType } from '../../../styling/IconType'; -import { labelStyle, space_lg, space_md, space_sm, space_xs } from '../../../styling/style'; -import { projectColors } from '../../../styling/theme'; -import { defaultProjectIllustration } from '../../projects/ProjectCommon'; -import { ColorPicker } from '../element/ColorPicker'; -import IconButton from '../element/IconButton'; -import Flex from '../layout/Flex'; -import Icon from '../layout/Icon'; +import useTranslations from '../../../../i18n/I18nContext'; +import { MaterialIconsType } from '../../../../styling/IconType'; +import { labelStyle, space_lg, space_md, space_sm, space_xs } from '../../../../styling/style'; +import { projectColors } from '../../../../styling/theme'; +import { defaultProjectIllustration } from '../../../projects/ProjectCommon'; +import Flex from '../../layout/Flex'; +import Icon from '../../layout/Icon'; +import IconButton from '../IconButton'; +import { ColorPicker } from '../color/ColorPicker'; interface IllustrationPickerProps { illustration: Illustration | undefined | null; diff --git a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/ToolbarPlugin.tsx b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/ToolbarPlugin.tsx index 95592677039..bf2796d954e 100644 --- a/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/ToolbarPlugin.tsx +++ b/colab-webapp/src/main/node/app/src/components/documents/texteditor/plugins/ToolbarPlugin/ToolbarPlugin.tsx @@ -41,9 +41,9 @@ import { space_2xs, } from '../../../../../styling/style'; import { textBackgroundColors, textColors } from '../../../../../styling/theme'; -import { ColorPicker } from '../../../../common/element/ColorPicker'; import IconButton from '../../../../common/element/IconButton'; import { TipsCtx } from '../../../../common/element/Tips'; +import { ColorPicker } from '../../../../common/element/color/ColorPicker'; import DropDownMenu from '../../../../common/layout/DropDownMenu'; import Flex from '../../../../common/layout/Flex'; import Icon from '../../../../common/layout/Icon'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx index 0a338b2c274..668e5afd83b 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectNav.tsx @@ -16,9 +16,9 @@ import { binAccessDefaultIcon } from '../../styling/IconDefault'; import { br_md, m_sm, p_xs, space_2xs, space_xs } from '../../styling/style'; import { UserDropDown } from '../MainNav'; import Badge from '../common/element/Badge'; -import { IllustrationIconDisplay } from '../common/element/IllustrationDisplay'; import { DiscreetInput } from '../common/element/Input'; import { MainMenuLink } from '../common/element/Link'; +import { IllustrationIconDisplay } from '../common/element/illustration/IllustrationDisplay'; import Flex from '../common/layout/Flex'; import Icon from '../common/layout/Icon'; import Monkeys from '../debugger/monkey/Monkeys'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx index 268ac9bd386..1e149c80f81 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/ProjectThumb.tsx @@ -19,7 +19,7 @@ import { text_sm, } from '../../styling/style'; import DeletionStatusIndicator from '../common/element/DeletionStatusIndicator'; -import IllustrationDisplay from '../common/element/IllustrationDisplay'; +import IllustrationDisplay from '../common/element/illustration/IllustrationDisplay'; import DropDownMenu from '../common/layout/DropDownMenu'; import Flex from '../common/layout/Flex'; import Icon from '../common/layout/Icon'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx b/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx index e9fbea57360..973e7b3b3e1 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/creation/NewProjectCreator.tsx @@ -14,9 +14,9 @@ import { useAppDispatch, useLoadingState } from '../../../store/hooks'; import { heading_xs, space_lg, space_md, space_sm } from '../../../styling/style'; import Button from '../../common/element/Button'; import IconButton from '../../common/element/IconButton'; -import IllustrationDisplay from '../../common/element/IllustrationDisplay'; import { FormInput } from '../../common/element/Input'; -import IllustrationPicker from '../../common/illustration/IllustrationPicker'; +import IllustrationDisplay from '../../common/element/illustration/IllustrationDisplay'; +import IllustrationPicker from '../../common/element/illustration/IllustrationPicker'; import Flex from '../../common/layout/Flex'; import Icon from '../../common/layout/Icon'; import OpenModalOnClick from '../../common/layout/OpenModalOnClick'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelExtractor.tsx b/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelExtractor.tsx index b6e4b8eb1ee..0a17b01e373 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelExtractor.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelExtractor.tsx @@ -17,9 +17,9 @@ import { space_lg, space_sm, space_xl } from '../../../styling/style'; import AvailabilityStatusIndicator from '../../common/element/AvailabilityStatusIndicator'; import Button from '../../common/element/Button'; import Checkbox from '../../common/element/Checkbox'; -import IllustrationDisplay from '../../common/element/IllustrationDisplay'; import { LabeledInput, LabeledTextArea } from '../../common/element/Input'; -import IllustrationPicker from '../../common/illustration/IllustrationPicker'; +import IllustrationDisplay from '../../common/element/illustration/IllustrationDisplay'; +import IllustrationPicker from '../../common/element/illustration/IllustrationPicker'; import Flex from '../../common/layout/Flex'; import Modal from '../../common/layout/Modal'; import { defaultProjectIllustration, projectIcons } from '../ProjectCommon'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSelector.tsx b/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSelector.tsx index e1a75fcb92a..92ae8e73d23 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSelector.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/models/ProjectModelSelector.tsx @@ -22,7 +22,7 @@ import { import ItemThumbnailsSelection from '../../common/collection/ItemThumbnailsSelection'; import AvailabilityStatusIndicator from '../../common/element/AvailabilityStatusIndicator'; import DeletionStatusIndicator from '../../common/element/DeletionStatusIndicator'; -import IllustrationDisplay from '../../common/element/IllustrationDisplay'; +import IllustrationDisplay from '../../common/element/illustration/IllustrationDisplay'; import Flex from '../../common/layout/Flex'; import Icon from '../../common/layout/Icon'; import { defaultProjectIllustration, noModelIllustration } from '../ProjectCommon'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx b/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx index 54a50a74a1f..0360068d327 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/models/SharedModelsList.tsx @@ -27,8 +27,8 @@ import { text_sm, } from '../../../styling/style'; import DeletionStatusIndicator from '../../common/element/DeletionStatusIndicator'; -import IllustrationDisplay from '../../common/element/IllustrationDisplay'; import InlineLoading from '../../common/element/InlineLoading'; +import IllustrationDisplay from '../../common/element/illustration/IllustrationDisplay'; import DropDownMenu from '../../common/layout/DropDownMenu'; import Flex from '../../common/layout/Flex'; import Icon from '../../common/layout/Icon'; diff --git a/colab-webapp/src/main/node/app/src/components/projects/settings/ProjectSettingsGeneral.tsx b/colab-webapp/src/main/node/app/src/components/projects/settings/ProjectSettingsGeneral.tsx index f66382ca988..609b023b4f8 100644 --- a/colab-webapp/src/main/node/app/src/components/projects/settings/ProjectSettingsGeneral.tsx +++ b/colab-webapp/src/main/node/app/src/components/projects/settings/ProjectSettingsGeneral.tsx @@ -15,7 +15,7 @@ import { space_xl } from '../../../styling/style'; import AvailabilityStatusIndicator from '../../common/element/AvailabilityStatusIndicator'; import InlineLoading from '../../common/element/InlineLoading'; import { LabeledInput, LabeledTextArea } from '../../common/element/Input'; -import ProjectIllustrationPicker from '../../common/illustration/IllustrationPicker'; +import ProjectIllustrationPicker from '../../common/element/illustration/IllustrationPicker'; import Flex from '../../common/layout/Flex'; import Modal from '../../common/layout/Modal'; import { projectIcons } from '../ProjectCommon'; From a086a3cb365cd44eb425bf397bcafd57be3ff1d9 Mon Sep 17 00:00:00 2001 From: Sandra Monnier <70577952+SandraMonnier@users.noreply.github.com> Date: Wed, 27 Dec 2023 12:46:13 +0100 Subject: [PATCH 055/116] remove CleverTextarea --- .../common/element/CleverTextarea.tsx | 87 ------------------- .../app/src/components/live/LiveEditor.tsx | 14 ++- 2 files changed, 12 insertions(+), 89 deletions(-) delete mode 100644 colab-webapp/src/main/node/app/src/components/common/element/CleverTextarea.tsx diff --git a/colab-webapp/src/main/node/app/src/components/common/element/CleverTextarea.tsx b/colab-webapp/src/main/node/app/src/components/common/element/CleverTextarea.tsx deleted file mode 100644 index db18c549995..00000000000 --- a/colab-webapp/src/main/node/app/src/components/common/element/CleverTextarea.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/* - * The coLAB project - * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO - * - * Licensed under the MIT License - */ - -import * as React from 'react'; -import * as LiveHelper from '../../../LiveHelper'; -import logger from '../../../logger'; - -export interface CleverTextareaProps { - value: string; - onChange: (newValue: string) => void; - className?: string; -} - -/** - * Get new selection range by applying offsets to current selection - */ -function computeSelectionOffsets(offsets: LiveHelper.Offsets, node: HTMLTextAreaElement) { - const startIndex = node.selectionStart; - const endIndex = node.selectionEnd; - - const newRange = { - start: startIndex, - end: endIndex, - }; - logger.trace('Move selection ', startIndex, ':', endIndex, ' according to offsets: ', offsets); - - for (const sKey in offsets) { - const key = +sKey; - const offset = offsets[key]!; - if (key < startIndex) { - newRange.start += offset; - } - if (key < endIndex) { - newRange.end += offset; - } - } - - logger.trace('New Range: ', newRange); - return newRange; -} - -/** - * Managed textarea which try to keep selected text across updates - */ -export default function CleverTextarea({ - value, - onChange, - className, -}: CleverTextareaProps): JSX.Element { - // use a ref to manage the input directly - const inputRef = React.useRef(null); - - React.useLayoutEffect(() => { - const ta = inputRef.current; - if (ta != null) { - if (ta.value !== value) { - const diff = LiveHelper.getMicroChange(ta.value, value); - const offsets = LiveHelper.computeOffsets(diff); - const range = computeSelectionOffsets(offsets, ta); - ta.value = value; - ta.selectionStart = range.start; - ta.selectionEnd = range.end; - } - } - }, [value]); - - const onInternalChangeCb = React.useCallback( - (e: React.ChangeEvent) => { - const newValue = e.target.value; - onChange(newValue); - }, - [onChange], - ); - - return ( -