From 008d6d529be382fdbe863005198542d99012fbe8 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Sun, 14 Apr 2024 09:01:29 +0800 Subject: [PATCH 01/21] frontend: Update node version in .nvmrc --- frontend/.nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/.nvmrc b/frontend/.nvmrc index 8cbe1856..5802c69c 100644 --- a/frontend/.nvmrc +++ b/frontend/.nvmrc @@ -1 +1 @@ -18.x.x \ No newline at end of file +20.12.2 \ No newline at end of file From 7f88c98d0223ef54332cc8c25b76115b5c309d49 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Sun, 14 Apr 2024 09:11:04 +0800 Subject: [PATCH 02/21] frontend: generate client based on updated openapi.json --- frontend/src/client/index.ts | 13 ++ .../models/Body_login_login_access_token.ts | 1 + frontend/src/client/models/ChatMessage.ts | 12 ++ frontend/src/client/models/ChatMessageType.ts | 6 + .../src/client/models/HTTPValidationError.ts | 1 + frontend/src/client/models/ItemCreate.ts | 1 + frontend/src/client/models/ItemOut.ts | 1 + frontend/src/client/models/ItemUpdate.ts | 1 + frontend/src/client/models/ItemsOut.ts | 1 + frontend/src/client/models/Message.ts | 1 + frontend/src/client/models/NewPassword.ts | 1 + frontend/src/client/models/TeamChat.ts | 11 ++ frontend/src/client/models/TeamCreate.ts | 10 ++ frontend/src/client/models/TeamOut.ts | 12 ++ frontend/src/client/models/TeamsOut.ts | 12 ++ frontend/src/client/models/Token.ts | 1 + frontend/src/client/models/UpdatePassword.ts | 1 + frontend/src/client/models/UserCreate.ts | 1 + frontend/src/client/models/UserCreateOpen.ts | 1 + frontend/src/client/models/UserOut.ts | 1 + frontend/src/client/models/UserUpdate.ts | 1 + frontend/src/client/models/UserUpdateMe.ts | 1 + frontend/src/client/models/UsersOut.ts | 1 + frontend/src/client/models/ValidationError.ts | 1 + .../schemas/$Body_login_login_access_token.ts | 60 +++---- frontend/src/client/schemas/$ChatMessage.ts | 16 ++ .../src/client/schemas/$ChatMessageType.ts | 7 + .../client/schemas/$HTTPValidationError.ts | 10 +- frontend/src/client/schemas/$ItemCreate.ts | 20 +-- frontend/src/client/schemas/$ItemOut.ts | 32 ++-- frontend/src/client/schemas/$ItemUpdate.ts | 28 +-- frontend/src/client/schemas/$ItemsOut.ts | 18 +- frontend/src/client/schemas/$Message.ts | 6 +- frontend/src/client/schemas/$NewPassword.ts | 12 +- frontend/src/client/schemas/$TeamChat.ts | 15 ++ frontend/src/client/schemas/$TeamCreate.ts | 20 +++ frontend/src/client/schemas/$TeamOut.ts | 28 +++ frontend/src/client/schemas/$TeamsOut.ts | 19 ++ frontend/src/client/schemas/$Token.ts | 10 +- .../src/client/schemas/$UpdatePassword.ts | 12 +- frontend/src/client/schemas/$UserCreate.ts | 34 ++-- .../src/client/schemas/$UserCreateOpen.ts | 26 +-- frontend/src/client/schemas/$UserOut.ts | 34 ++-- frontend/src/client/schemas/$UserUpdate.ts | 50 +++--- frontend/src/client/schemas/$UserUpdateMe.ts | 28 +-- frontend/src/client/schemas/$UsersOut.ts | 18 +- .../src/client/schemas/$ValidationError.ts | 34 ++-- frontend/src/client/services/ItemsService.ts | 48 ++--- frontend/src/client/services/LoginService.ts | 47 +++-- frontend/src/client/services/TeamsService.ts | 164 ++++++++++++++++++ frontend/src/client/services/UsersService.ts | 72 ++++---- frontend/src/client/services/UtilsService.ts | 30 +--- 52 files changed, 677 insertions(+), 314 deletions(-) create mode 100644 frontend/src/client/models/ChatMessage.ts create mode 100644 frontend/src/client/models/ChatMessageType.ts create mode 100644 frontend/src/client/models/TeamChat.ts create mode 100644 frontend/src/client/models/TeamCreate.ts create mode 100644 frontend/src/client/models/TeamOut.ts create mode 100644 frontend/src/client/models/TeamsOut.ts create mode 100644 frontend/src/client/schemas/$ChatMessage.ts create mode 100644 frontend/src/client/schemas/$ChatMessageType.ts create mode 100644 frontend/src/client/schemas/$TeamChat.ts create mode 100644 frontend/src/client/schemas/$TeamCreate.ts create mode 100644 frontend/src/client/schemas/$TeamOut.ts create mode 100644 frontend/src/client/schemas/$TeamsOut.ts create mode 100644 frontend/src/client/services/TeamsService.ts diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts index fb94ef69..b788a9a5 100644 --- a/frontend/src/client/index.ts +++ b/frontend/src/client/index.ts @@ -8,6 +8,8 @@ export { OpenAPI } from './core/OpenAPI'; export type { OpenAPIConfig } from './core/OpenAPI'; export type { Body_login_login_access_token } from './models/Body_login_login_access_token'; +export type { ChatMessage } from './models/ChatMessage'; +export type { ChatMessageType } from './models/ChatMessageType'; export type { HTTPValidationError } from './models/HTTPValidationError'; export type { ItemCreate } from './models/ItemCreate'; export type { ItemOut } from './models/ItemOut'; @@ -15,6 +17,10 @@ export type { ItemsOut } from './models/ItemsOut'; export type { ItemUpdate } from './models/ItemUpdate'; export type { Message } from './models/Message'; export type { NewPassword } from './models/NewPassword'; +export type { TeamChat } from './models/TeamChat'; +export type { TeamCreate } from './models/TeamCreate'; +export type { TeamOut } from './models/TeamOut'; +export type { TeamsOut } from './models/TeamsOut'; export type { Token } from './models/Token'; export type { UpdatePassword } from './models/UpdatePassword'; export type { UserCreate } from './models/UserCreate'; @@ -26,6 +32,8 @@ export type { UserUpdateMe } from './models/UserUpdateMe'; export type { ValidationError } from './models/ValidationError'; export { $Body_login_login_access_token } from './schemas/$Body_login_login_access_token'; +export { $ChatMessage } from './schemas/$ChatMessage'; +export { $ChatMessageType } from './schemas/$ChatMessageType'; export { $HTTPValidationError } from './schemas/$HTTPValidationError'; export { $ItemCreate } from './schemas/$ItemCreate'; export { $ItemOut } from './schemas/$ItemOut'; @@ -33,6 +41,10 @@ export { $ItemsOut } from './schemas/$ItemsOut'; export { $ItemUpdate } from './schemas/$ItemUpdate'; export { $Message } from './schemas/$Message'; export { $NewPassword } from './schemas/$NewPassword'; +export { $TeamChat } from './schemas/$TeamChat'; +export { $TeamCreate } from './schemas/$TeamCreate'; +export { $TeamOut } from './schemas/$TeamOut'; +export { $TeamsOut } from './schemas/$TeamsOut'; export { $Token } from './schemas/$Token'; export { $UpdatePassword } from './schemas/$UpdatePassword'; export { $UserCreate } from './schemas/$UserCreate'; @@ -45,5 +57,6 @@ export { $ValidationError } from './schemas/$ValidationError'; export { ItemsService } from './services/ItemsService'; export { LoginService } from './services/LoginService'; +export { TeamsService } from './services/TeamsService'; export { UsersService } from './services/UsersService'; export { UtilsService } from './services/UtilsService'; diff --git a/frontend/src/client/models/Body_login_login_access_token.ts b/frontend/src/client/models/Body_login_login_access_token.ts index 7798e611..b1bec7ba 100644 --- a/frontend/src/client/models/Body_login_login_access_token.ts +++ b/frontend/src/client/models/Body_login_login_access_token.ts @@ -11,3 +11,4 @@ export type Body_login_login_access_token = { client_id?: (string | null); client_secret?: (string | null); }; + diff --git a/frontend/src/client/models/ChatMessage.ts b/frontend/src/client/models/ChatMessage.ts new file mode 100644 index 00000000..49c0ed8d --- /dev/null +++ b/frontend/src/client/models/ChatMessage.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ChatMessageType } from './ChatMessageType'; + +export type ChatMessage = { + type: ChatMessageType; + content: string; +}; + diff --git a/frontend/src/client/models/ChatMessageType.ts b/frontend/src/client/models/ChatMessageType.ts new file mode 100644 index 00000000..23fdf1e8 --- /dev/null +++ b/frontend/src/client/models/ChatMessageType.ts @@ -0,0 +1,6 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type ChatMessageType = 'human' | 'ai'; diff --git a/frontend/src/client/models/HTTPValidationError.ts b/frontend/src/client/models/HTTPValidationError.ts index e218a9f3..c0bcc87c 100644 --- a/frontend/src/client/models/HTTPValidationError.ts +++ b/frontend/src/client/models/HTTPValidationError.ts @@ -8,3 +8,4 @@ import type { ValidationError } from './ValidationError'; export type HTTPValidationError = { detail?: Array; }; + diff --git a/frontend/src/client/models/ItemCreate.ts b/frontend/src/client/models/ItemCreate.ts index aeefb6dd..50e8e4dd 100644 --- a/frontend/src/client/models/ItemCreate.ts +++ b/frontend/src/client/models/ItemCreate.ts @@ -7,3 +7,4 @@ export type ItemCreate = { title: string; description?: (string | null); }; + diff --git a/frontend/src/client/models/ItemOut.ts b/frontend/src/client/models/ItemOut.ts index cbe6c02c..1ae52896 100644 --- a/frontend/src/client/models/ItemOut.ts +++ b/frontend/src/client/models/ItemOut.ts @@ -9,3 +9,4 @@ export type ItemOut = { id: number; owner_id: number; }; + diff --git a/frontend/src/client/models/ItemUpdate.ts b/frontend/src/client/models/ItemUpdate.ts index 89ccb4e0..7062eea6 100644 --- a/frontend/src/client/models/ItemUpdate.ts +++ b/frontend/src/client/models/ItemUpdate.ts @@ -7,3 +7,4 @@ export type ItemUpdate = { title?: (string | null); description?: (string | null); }; + diff --git a/frontend/src/client/models/ItemsOut.ts b/frontend/src/client/models/ItemsOut.ts index e45794bf..4b4a988a 100644 --- a/frontend/src/client/models/ItemsOut.ts +++ b/frontend/src/client/models/ItemsOut.ts @@ -9,3 +9,4 @@ export type ItemsOut = { data: Array; count: number; }; + diff --git a/frontend/src/client/models/Message.ts b/frontend/src/client/models/Message.ts index 6220861f..5e05da75 100644 --- a/frontend/src/client/models/Message.ts +++ b/frontend/src/client/models/Message.ts @@ -6,3 +6,4 @@ export type Message = { message: string; }; + diff --git a/frontend/src/client/models/NewPassword.ts b/frontend/src/client/models/NewPassword.ts index 9d5512b3..ee5c1368 100644 --- a/frontend/src/client/models/NewPassword.ts +++ b/frontend/src/client/models/NewPassword.ts @@ -7,3 +7,4 @@ export type NewPassword = { token: string; new_password: string; }; + diff --git a/frontend/src/client/models/TeamChat.ts b/frontend/src/client/models/TeamChat.ts new file mode 100644 index 00000000..f0f6dc66 --- /dev/null +++ b/frontend/src/client/models/TeamChat.ts @@ -0,0 +1,11 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ChatMessage } from './ChatMessage'; + +export type TeamChat = { + messages: Array; +}; + diff --git a/frontend/src/client/models/TeamCreate.ts b/frontend/src/client/models/TeamCreate.ts new file mode 100644 index 00000000..14f6eb3d --- /dev/null +++ b/frontend/src/client/models/TeamCreate.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type TeamCreate = { + name: string; + description?: (string | null); +}; + diff --git a/frontend/src/client/models/TeamOut.ts b/frontend/src/client/models/TeamOut.ts new file mode 100644 index 00000000..289b0933 --- /dev/null +++ b/frontend/src/client/models/TeamOut.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type TeamOut = { + name: string; + description?: (string | null); + id: number; + owner_id: number; +}; + diff --git a/frontend/src/client/models/TeamsOut.ts b/frontend/src/client/models/TeamsOut.ts new file mode 100644 index 00000000..39674daa --- /dev/null +++ b/frontend/src/client/models/TeamsOut.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { TeamOut } from './TeamOut'; + +export type TeamsOut = { + data: Array; + count: number; +}; + diff --git a/frontend/src/client/models/Token.ts b/frontend/src/client/models/Token.ts index ea3120bf..29b10b07 100644 --- a/frontend/src/client/models/Token.ts +++ b/frontend/src/client/models/Token.ts @@ -7,3 +7,4 @@ export type Token = { access_token: string; token_type?: string; }; + diff --git a/frontend/src/client/models/UpdatePassword.ts b/frontend/src/client/models/UpdatePassword.ts index f0c4b694..9e53ca06 100644 --- a/frontend/src/client/models/UpdatePassword.ts +++ b/frontend/src/client/models/UpdatePassword.ts @@ -7,3 +7,4 @@ export type UpdatePassword = { current_password: string; new_password: string; }; + diff --git a/frontend/src/client/models/UserCreate.ts b/frontend/src/client/models/UserCreate.ts index f49d0bff..c14aef68 100644 --- a/frontend/src/client/models/UserCreate.ts +++ b/frontend/src/client/models/UserCreate.ts @@ -10,3 +10,4 @@ export type UserCreate = { full_name?: (string | null); password: string; }; + diff --git a/frontend/src/client/models/UserCreateOpen.ts b/frontend/src/client/models/UserCreateOpen.ts index f859e9b1..b2ef96b0 100644 --- a/frontend/src/client/models/UserCreateOpen.ts +++ b/frontend/src/client/models/UserCreateOpen.ts @@ -8,3 +8,4 @@ export type UserCreateOpen = { password: string; full_name?: (string | null); }; + diff --git a/frontend/src/client/models/UserOut.ts b/frontend/src/client/models/UserOut.ts index 8387dc6d..59a00e44 100644 --- a/frontend/src/client/models/UserOut.ts +++ b/frontend/src/client/models/UserOut.ts @@ -10,3 +10,4 @@ export type UserOut = { full_name?: (string | null); id: number; }; + diff --git a/frontend/src/client/models/UserUpdate.ts b/frontend/src/client/models/UserUpdate.ts index 9ba346a4..08171163 100644 --- a/frontend/src/client/models/UserUpdate.ts +++ b/frontend/src/client/models/UserUpdate.ts @@ -10,3 +10,4 @@ export type UserUpdate = { full_name?: (string | null); password?: (string | null); }; + diff --git a/frontend/src/client/models/UserUpdateMe.ts b/frontend/src/client/models/UserUpdateMe.ts index aa7a2fbb..6c1f85ea 100644 --- a/frontend/src/client/models/UserUpdateMe.ts +++ b/frontend/src/client/models/UserUpdateMe.ts @@ -7,3 +7,4 @@ export type UserUpdateMe = { full_name?: (string | null); email?: (string | null); }; + diff --git a/frontend/src/client/models/UsersOut.ts b/frontend/src/client/models/UsersOut.ts index 0e317ab4..ba51b5e4 100644 --- a/frontend/src/client/models/UsersOut.ts +++ b/frontend/src/client/models/UsersOut.ts @@ -9,3 +9,4 @@ export type UsersOut = { data: Array; count: number; }; + diff --git a/frontend/src/client/models/ValidationError.ts b/frontend/src/client/models/ValidationError.ts index 0a3e90e9..18997ec7 100644 --- a/frontend/src/client/models/ValidationError.ts +++ b/frontend/src/client/models/ValidationError.ts @@ -8,3 +8,4 @@ export type ValidationError = { msg: string; type: string; }; + diff --git a/frontend/src/client/schemas/$Body_login_login_access_token.ts b/frontend/src/client/schemas/$Body_login_login_access_token.ts index 5d701cc4..f545b710 100644 --- a/frontend/src/client/schemas/$Body_login_login_access_token.ts +++ b/frontend/src/client/schemas/$Body_login_login_access_token.ts @@ -5,40 +5,40 @@ export const $Body_login_login_access_token = { properties: { grant_type: { - type: 'any-of', - contains: [{ - type: 'string', - pattern: 'password', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + pattern: 'password', + }, { + type: 'null', + }], + }, username: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, password: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, scope: { - type: 'string', -}, + type: 'string', + }, client_id: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, client_secret: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$ChatMessage.ts b/frontend/src/client/schemas/$ChatMessage.ts new file mode 100644 index 00000000..a97c8fc2 --- /dev/null +++ b/frontend/src/client/schemas/$ChatMessage.ts @@ -0,0 +1,16 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ChatMessage = { + properties: { + type: { + type: 'ChatMessageType', + isRequired: true, + }, + content: { + type: 'string', + isRequired: true, + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$ChatMessageType.ts b/frontend/src/client/schemas/$ChatMessageType.ts new file mode 100644 index 00000000..f2d02e46 --- /dev/null +++ b/frontend/src/client/schemas/$ChatMessageType.ts @@ -0,0 +1,7 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ChatMessageType = { + type: 'Enum', +} as const; diff --git a/frontend/src/client/schemas/$HTTPValidationError.ts b/frontend/src/client/schemas/$HTTPValidationError.ts index 4206c7c4..f8eb5c82 100644 --- a/frontend/src/client/schemas/$HTTPValidationError.ts +++ b/frontend/src/client/schemas/$HTTPValidationError.ts @@ -5,10 +5,10 @@ export const $HTTPValidationError = { properties: { detail: { - type: 'array', - contains: { - type: 'ValidationError', - }, -}, + type: 'array', + contains: { + type: 'ValidationError', + }, + }, }, } as const; diff --git a/frontend/src/client/schemas/$ItemCreate.ts b/frontend/src/client/schemas/$ItemCreate.ts index 70037eeb..de80a67a 100644 --- a/frontend/src/client/schemas/$ItemCreate.ts +++ b/frontend/src/client/schemas/$ItemCreate.ts @@ -5,16 +5,16 @@ export const $ItemCreate = { properties: { title: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, description: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$ItemOut.ts b/frontend/src/client/schemas/$ItemOut.ts index 015a5181..7a20bca1 100644 --- a/frontend/src/client/schemas/$ItemOut.ts +++ b/frontend/src/client/schemas/$ItemOut.ts @@ -5,24 +5,24 @@ export const $ItemOut = { properties: { title: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, description: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, id: { - type: 'number', - isRequired: true, -}, + type: 'number', + isRequired: true, + }, owner_id: { - type: 'number', - isRequired: true, -}, + type: 'number', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$ItemUpdate.ts b/frontend/src/client/schemas/$ItemUpdate.ts index bf76d61a..a7b52c53 100644 --- a/frontend/src/client/schemas/$ItemUpdate.ts +++ b/frontend/src/client/schemas/$ItemUpdate.ts @@ -5,20 +5,20 @@ export const $ItemUpdate = { properties: { title: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, description: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$ItemsOut.ts b/frontend/src/client/schemas/$ItemsOut.ts index 782b68d3..cb053281 100644 --- a/frontend/src/client/schemas/$ItemsOut.ts +++ b/frontend/src/client/schemas/$ItemsOut.ts @@ -5,15 +5,15 @@ export const $ItemsOut = { properties: { data: { - type: 'array', - contains: { - type: 'ItemOut', - }, - isRequired: true, -}, + type: 'array', + contains: { + type: 'ItemOut', + }, + isRequired: true, + }, count: { - type: 'number', - isRequired: true, -}, + type: 'number', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$Message.ts b/frontend/src/client/schemas/$Message.ts index d2abdc13..5d514529 100644 --- a/frontend/src/client/schemas/$Message.ts +++ b/frontend/src/client/schemas/$Message.ts @@ -5,8 +5,8 @@ export const $Message = { properties: { message: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$NewPassword.ts b/frontend/src/client/schemas/$NewPassword.ts index f6b19e2d..49599381 100644 --- a/frontend/src/client/schemas/$NewPassword.ts +++ b/frontend/src/client/schemas/$NewPassword.ts @@ -5,12 +5,12 @@ export const $NewPassword = { properties: { token: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, new_password: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$TeamChat.ts b/frontend/src/client/schemas/$TeamChat.ts new file mode 100644 index 00000000..b177c5cf --- /dev/null +++ b/frontend/src/client/schemas/$TeamChat.ts @@ -0,0 +1,15 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $TeamChat = { + properties: { + messages: { + type: 'array', + contains: { + type: 'ChatMessage', + }, + isRequired: true, + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$TeamCreate.ts b/frontend/src/client/schemas/$TeamCreate.ts new file mode 100644 index 00000000..944de0e6 --- /dev/null +++ b/frontend/src/client/schemas/$TeamCreate.ts @@ -0,0 +1,20 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $TeamCreate = { + properties: { + name: { + type: 'string', + isRequired: true, + }, + description: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$TeamOut.ts b/frontend/src/client/schemas/$TeamOut.ts new file mode 100644 index 00000000..f12568cd --- /dev/null +++ b/frontend/src/client/schemas/$TeamOut.ts @@ -0,0 +1,28 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $TeamOut = { + properties: { + name: { + type: 'string', + isRequired: true, + }, + description: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + id: { + type: 'number', + isRequired: true, + }, + owner_id: { + type: 'number', + isRequired: true, + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$TeamsOut.ts b/frontend/src/client/schemas/$TeamsOut.ts new file mode 100644 index 00000000..dc51f271 --- /dev/null +++ b/frontend/src/client/schemas/$TeamsOut.ts @@ -0,0 +1,19 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $TeamsOut = { + properties: { + data: { + type: 'array', + contains: { + type: 'TeamOut', + }, + isRequired: true, + }, + count: { + type: 'number', + isRequired: true, + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$Token.ts b/frontend/src/client/schemas/$Token.ts index 88946bc6..d05d203f 100644 --- a/frontend/src/client/schemas/$Token.ts +++ b/frontend/src/client/schemas/$Token.ts @@ -5,11 +5,11 @@ export const $Token = { properties: { access_token: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, token_type: { - type: 'string', -}, + type: 'string', + }, }, } as const; diff --git a/frontend/src/client/schemas/$UpdatePassword.ts b/frontend/src/client/schemas/$UpdatePassword.ts index 18758819..35828f74 100644 --- a/frontend/src/client/schemas/$UpdatePassword.ts +++ b/frontend/src/client/schemas/$UpdatePassword.ts @@ -5,12 +5,12 @@ export const $UpdatePassword = { properties: { current_password: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, new_password: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$UserCreate.ts b/frontend/src/client/schemas/$UserCreate.ts index 84503be3..8251ec91 100644 --- a/frontend/src/client/schemas/$UserCreate.ts +++ b/frontend/src/client/schemas/$UserCreate.ts @@ -5,26 +5,26 @@ export const $UserCreate = { properties: { email: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, is_active: { - type: 'boolean', -}, + type: 'boolean', + }, is_superuser: { - type: 'boolean', -}, + type: 'boolean', + }, full_name: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, password: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$UserCreateOpen.ts b/frontend/src/client/schemas/$UserCreateOpen.ts index ae2fff5b..3e5e20db 100644 --- a/frontend/src/client/schemas/$UserCreateOpen.ts +++ b/frontend/src/client/schemas/$UserCreateOpen.ts @@ -5,20 +5,20 @@ export const $UserCreateOpen = { properties: { email: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, password: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, full_name: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$UserOut.ts b/frontend/src/client/schemas/$UserOut.ts index 82614024..a4f00534 100644 --- a/frontend/src/client/schemas/$UserOut.ts +++ b/frontend/src/client/schemas/$UserOut.ts @@ -5,26 +5,26 @@ export const $UserOut = { properties: { email: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, is_active: { - type: 'boolean', -}, + type: 'boolean', + }, is_superuser: { - type: 'boolean', -}, + type: 'boolean', + }, full_name: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, id: { - type: 'number', - isRequired: true, -}, + type: 'number', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$UserUpdate.ts b/frontend/src/client/schemas/$UserUpdate.ts index 396e6173..a87f79ee 100644 --- a/frontend/src/client/schemas/$UserUpdate.ts +++ b/frontend/src/client/schemas/$UserUpdate.ts @@ -5,34 +5,34 @@ export const $UserUpdate = { properties: { email: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, is_active: { - type: 'boolean', -}, + type: 'boolean', + }, is_superuser: { - type: 'boolean', -}, + type: 'boolean', + }, full_name: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, password: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$UserUpdateMe.ts b/frontend/src/client/schemas/$UserUpdateMe.ts index ed9c0112..ad5ef55d 100644 --- a/frontend/src/client/schemas/$UserUpdateMe.ts +++ b/frontend/src/client/schemas/$UserUpdateMe.ts @@ -5,20 +5,20 @@ export const $UserUpdateMe = { properties: { full_name: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, email: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'null', -}], -}, + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$UsersOut.ts b/frontend/src/client/schemas/$UsersOut.ts index 9c228688..4aa6617f 100644 --- a/frontend/src/client/schemas/$UsersOut.ts +++ b/frontend/src/client/schemas/$UsersOut.ts @@ -5,15 +5,15 @@ export const $UsersOut = { properties: { data: { - type: 'array', - contains: { - type: 'UserOut', - }, - isRequired: true, -}, + type: 'array', + contains: { + type: 'UserOut', + }, + isRequired: true, + }, count: { - type: 'number', - isRequired: true, -}, + type: 'number', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$ValidationError.ts b/frontend/src/client/schemas/$ValidationError.ts index b040db7c..3a48f2ab 100644 --- a/frontend/src/client/schemas/$ValidationError.ts +++ b/frontend/src/client/schemas/$ValidationError.ts @@ -5,24 +5,24 @@ export const $ValidationError = { properties: { loc: { - type: 'array', - contains: { - type: 'any-of', - contains: [{ - type: 'string', -}, { - type: 'number', -}], -}, - isRequired: true, -}, + type: 'array', + contains: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'number', + }], + }, + isRequired: true, + }, msg: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, type: { - type: 'string', - isRequired: true, -}, + type: 'string', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/services/ItemsService.ts b/frontend/src/client/services/ItemsService.ts index b68a28ac..331581e3 100644 --- a/frontend/src/client/services/ItemsService.ts +++ b/frontend/src/client/services/ItemsService.ts @@ -21,12 +21,12 @@ export class ItemsService { * @throws ApiError */ public static readItems({ -skip, -limit = 100, -}: { -skip?: number, -limit?: number, -}): CancelablePromise { + skip, + limit = 100, + }: { + skip?: number, + limit?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/api/v1/items/', @@ -47,10 +47,10 @@ limit?: number, * @throws ApiError */ public static createItem({ -requestBody, -}: { -requestBody: ItemCreate, -}): CancelablePromise { + requestBody, + }: { + requestBody: ItemCreate, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/items/', @@ -69,10 +69,10 @@ requestBody: ItemCreate, * @throws ApiError */ public static readItem({ -id, -}: { -id: number, -}): CancelablePromise { + id, + }: { + id: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/api/v1/items/{id}', @@ -92,12 +92,12 @@ id: number, * @throws ApiError */ public static updateItem({ -id, -requestBody, -}: { -id: number, -requestBody: ItemUpdate, -}): CancelablePromise { + id, + requestBody, + }: { + id: number, + requestBody: ItemUpdate, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/api/v1/items/{id}', @@ -119,10 +119,10 @@ requestBody: ItemUpdate, * @throws ApiError */ public static deleteItem({ -id, -}: { -id: number, -}): CancelablePromise { + id, + }: { + id: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/api/v1/items/{id}', diff --git a/frontend/src/client/services/LoginService.ts b/frontend/src/client/services/LoginService.ts index e40899d3..e7679cab 100644 --- a/frontend/src/client/services/LoginService.ts +++ b/frontend/src/client/services/LoginService.ts @@ -21,10 +21,10 @@ export class LoginService { * @throws ApiError */ public static loginAccessToken({ -formData, -}: { -formData: Body_login_login_access_token, -}): CancelablePromise { + formData, + }: { + formData: Body_login_login_access_token, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/login/access-token', @@ -56,10 +56,10 @@ formData: Body_login_login_access_token, * @throws ApiError */ public static recoverPassword({ -email, -}: { -email: string, -}): CancelablePromise { + email, + }: { + email: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/password-recovery/{email}', @@ -79,10 +79,10 @@ email: string, * @throws ApiError */ public static resetPassword({ -requestBody, -}: { -requestBody: NewPassword, -}): CancelablePromise { + requestBody, + }: { + requestBody: NewPassword, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/reset-password/', @@ -94,4 +94,27 @@ requestBody: NewPassword, }); } + /** + * Recover Password Html Content + * HTML Content for Password Recovery + * @returns string Successful Response + * @throws ApiError + */ + public static recoverPasswordHtmlContent({ + email, + }: { + email: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/password-recovery-html-content/{email}', + path: { + 'email': email, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + } diff --git a/frontend/src/client/services/TeamsService.ts b/frontend/src/client/services/TeamsService.ts new file mode 100644 index 00000000..f6a3447f --- /dev/null +++ b/frontend/src/client/services/TeamsService.ts @@ -0,0 +1,164 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { TeamChat } from '../models/TeamChat'; +import type { TeamCreate } from '../models/TeamCreate'; +import type { TeamOut } from '../models/TeamOut'; +import type { TeamsOut } from '../models/TeamsOut'; + +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; + +export class TeamsService { + + /** + * Read Teams + * Retrieve teams + * @returns TeamsOut Successful Response + * @throws ApiError + */ + public static readTeams({ + skip, + limit = 100, + }: { + skip?: number, + limit?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/teams/', + query: { + 'skip': skip, + 'limit': limit, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Create Team + * Create new team. + * @returns TeamOut Successful Response + * @throws ApiError + */ + public static createTeam({ + requestBody, + }: { + requestBody: TeamCreate, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/teams/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Read Team + * Get team by ID. + * @returns TeamOut Successful Response + * @throws ApiError + */ + public static readTeam({ + id, + }: { + id: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/teams/{id}', + path: { + 'id': id, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Update Team + * Update a team. + * @returns TeamOut Successful Response + * @throws ApiError + */ + public static updateTeam({ + id, + requestBody, + }: { + id: number, + requestBody: TeamCreate, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PUT', + url: '/api/v1/teams/{id}', + path: { + 'id': id, + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Delete Team + * Delete a team. + * @returns any Successful Response + * @throws ApiError + */ + public static deleteTeam({ + id, + }: { + id: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/api/v1/teams/{id}', + path: { + 'id': id, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Stream + * Stream a response to a user's input. + * @returns any Successful Response + * @throws ApiError + */ + public static stream({ + id, + requestBody, + }: { + id: number, + requestBody: TeamChat, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/teams/{id}/stream', + path: { + 'id': id, + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + +} diff --git a/frontend/src/client/services/UsersService.ts b/frontend/src/client/services/UsersService.ts index 055debe5..94684b4f 100644 --- a/frontend/src/client/services/UsersService.ts +++ b/frontend/src/client/services/UsersService.ts @@ -24,12 +24,12 @@ export class UsersService { * @throws ApiError */ public static readUsers({ -skip, -limit = 100, -}: { -skip?: number, -limit?: number, -}): CancelablePromise { + skip, + limit = 100, + }: { + skip?: number, + limit?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/api/v1/users/', @@ -50,10 +50,10 @@ limit?: number, * @throws ApiError */ public static createUser({ -requestBody, -}: { -requestBody: UserCreate, -}): CancelablePromise { + requestBody, + }: { + requestBody: UserCreate, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/users/', @@ -85,10 +85,10 @@ requestBody: UserCreate, * @throws ApiError */ public static updateUserMe({ -requestBody, -}: { -requestBody: UserUpdateMe, -}): CancelablePromise { + requestBody, + }: { + requestBody: UserUpdateMe, + }): CancelablePromise { return __request(OpenAPI, { method: 'PATCH', url: '/api/v1/users/me', @@ -107,10 +107,10 @@ requestBody: UserUpdateMe, * @throws ApiError */ public static updatePasswordMe({ -requestBody, -}: { -requestBody: UpdatePassword, -}): CancelablePromise { + requestBody, + }: { + requestBody: UpdatePassword, + }): CancelablePromise { return __request(OpenAPI, { method: 'PATCH', url: '/api/v1/users/me/password', @@ -129,10 +129,10 @@ requestBody: UpdatePassword, * @throws ApiError */ public static createUserOpen({ -requestBody, -}: { -requestBody: UserCreateOpen, -}): CancelablePromise { + requestBody, + }: { + requestBody: UserCreateOpen, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/users/open', @@ -151,10 +151,10 @@ requestBody: UserCreateOpen, * @throws ApiError */ public static readUserById({ -userId, -}: { -userId: number, -}): CancelablePromise { + userId, + }: { + userId: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/api/v1/users/{user_id}', @@ -174,12 +174,12 @@ userId: number, * @throws ApiError */ public static updateUser({ -userId, -requestBody, -}: { -userId: number, -requestBody: UserUpdate, -}): CancelablePromise { + userId, + requestBody, + }: { + userId: number, + requestBody: UserUpdate, + }): CancelablePromise { return __request(OpenAPI, { method: 'PATCH', url: '/api/v1/users/{user_id}', @@ -201,10 +201,10 @@ requestBody: UserUpdate, * @throws ApiError */ public static deleteUser({ -userId, -}: { -userId: number, -}): CancelablePromise { + userId, + }: { + userId: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/api/v1/users/{user_id}', diff --git a/frontend/src/client/services/UtilsService.ts b/frontend/src/client/services/UtilsService.ts index a7ed0bb4..bc6f97ef 100644 --- a/frontend/src/client/services/UtilsService.ts +++ b/frontend/src/client/services/UtilsService.ts @@ -10,28 +10,6 @@ import { request as __request } from '../core/request'; export class UtilsService { - /** - * Test Celery - * Test Celery worker. - * @returns Message Successful Response - * @throws ApiError - */ - public static testCelery({ -requestBody, -}: { -requestBody: Message, -}): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/v1/utils/test-celery/', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** * Test Email * Test emails. @@ -39,10 +17,10 @@ requestBody: Message, * @throws ApiError */ public static testEmail({ -emailTo, -}: { -emailTo: string, -}): CancelablePromise { + emailTo, + }: { + emailTo: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v1/utils/test-email/', From 56e7ba8dcb3dd21368e9b90c941b49f37e191758 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Sun, 14 Apr 2024 13:06:38 +0800 Subject: [PATCH 03/21] Fix update_team endpoint request type --- backend/app/api/routes/teams.py | 4 ++-- frontend/src/client/index.ts | 2 ++ frontend/src/client/models/TeamUpdate.ts | 10 ++++++++ frontend/src/client/schemas/$TeamUpdate.ts | 24 ++++++++++++++++++++ frontend/src/client/services/TeamsService.ts | 3 ++- frontend/src/routeTree.gen.ts | 11 +++++++++ 6 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 frontend/src/client/models/TeamUpdate.ts create mode 100644 frontend/src/client/schemas/$TeamUpdate.ts diff --git a/backend/app/api/routes/teams.py b/backend/app/api/routes/teams.py index 22bdcb04..673f4ce3 100644 --- a/backend/app/api/routes/teams.py +++ b/backend/app/api/routes/teams.py @@ -5,7 +5,7 @@ from app.core.graph.build import generator from app.api.deps import CurrentUser, SessionDep -from app.models import TeamChat, TeamsOut, TeamCreate, TeamOut, Team, Message +from app.models import TeamChat, TeamsOut, TeamCreate, TeamUpdate, TeamOut, Team, Message # TODO: To remove teams = { @@ -107,7 +107,7 @@ def create_team( @router.put("/{id}", response_model=TeamOut) def update_team( - *, session: SessionDep, current_user: CurrentUser, id: int, team_in: TeamCreate + *, session: SessionDep, current_user: CurrentUser, id: int, team_in: TeamUpdate ) -> Any: """ Update a team. diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts index b788a9a5..2d4cf462 100644 --- a/frontend/src/client/index.ts +++ b/frontend/src/client/index.ts @@ -21,6 +21,7 @@ export type { TeamChat } from './models/TeamChat'; export type { TeamCreate } from './models/TeamCreate'; export type { TeamOut } from './models/TeamOut'; export type { TeamsOut } from './models/TeamsOut'; +export type { TeamUpdate } from './models/TeamUpdate'; export type { Token } from './models/Token'; export type { UpdatePassword } from './models/UpdatePassword'; export type { UserCreate } from './models/UserCreate'; @@ -45,6 +46,7 @@ export { $TeamChat } from './schemas/$TeamChat'; export { $TeamCreate } from './schemas/$TeamCreate'; export { $TeamOut } from './schemas/$TeamOut'; export { $TeamsOut } from './schemas/$TeamsOut'; +export { $TeamUpdate } from './schemas/$TeamUpdate'; export { $Token } from './schemas/$Token'; export { $UpdatePassword } from './schemas/$UpdatePassword'; export { $UserCreate } from './schemas/$UserCreate'; diff --git a/frontend/src/client/models/TeamUpdate.ts b/frontend/src/client/models/TeamUpdate.ts new file mode 100644 index 00000000..f28a7a71 --- /dev/null +++ b/frontend/src/client/models/TeamUpdate.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type TeamUpdate = { + name?: (string | null); + description?: (string | null); +}; + diff --git a/frontend/src/client/schemas/$TeamUpdate.ts b/frontend/src/client/schemas/$TeamUpdate.ts new file mode 100644 index 00000000..52857980 --- /dev/null +++ b/frontend/src/client/schemas/$TeamUpdate.ts @@ -0,0 +1,24 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $TeamUpdate = { + properties: { + name: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + description: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + }, +} as const; diff --git a/frontend/src/client/services/TeamsService.ts b/frontend/src/client/services/TeamsService.ts index f6a3447f..4fe9504d 100644 --- a/frontend/src/client/services/TeamsService.ts +++ b/frontend/src/client/services/TeamsService.ts @@ -6,6 +6,7 @@ import type { TeamChat } from '../models/TeamChat'; import type { TeamCreate } from '../models/TeamCreate'; import type { TeamOut } from '../models/TeamOut'; import type { TeamsOut } from '../models/TeamsOut'; +import type { TeamUpdate } from '../models/TeamUpdate'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; @@ -95,7 +96,7 @@ export class TeamsService { requestBody, }: { id: number, - requestBody: TeamCreate, + requestBody: TeamUpdate, }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 395866a4..6bbb6738 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -16,6 +16,7 @@ import { Route as RecoverPasswordImport } from './routes/recover-password' import { Route as LoginImport } from './routes/login' import { Route as LayoutImport } from './routes/_layout' import { Route as LayoutIndexImport } from './routes/_layout/index' +import { Route as LayoutTeamsImport } from './routes/_layout/teams' import { Route as LayoutSettingsImport } from './routes/_layout/settings' import { Route as LayoutItemsImport } from './routes/_layout/items' import { Route as LayoutAdminImport } from './routes/_layout/admin' @@ -47,6 +48,11 @@ const LayoutIndexRoute = LayoutIndexImport.update({ getParentRoute: () => LayoutRoute, } as any) +const LayoutTeamsRoute = LayoutTeamsImport.update({ + path: '/teams', + getParentRoute: () => LayoutRoute, +} as any) + const LayoutSettingsRoute = LayoutSettingsImport.update({ path: '/settings', getParentRoute: () => LayoutRoute, @@ -94,6 +100,10 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutSettingsImport parentRoute: typeof LayoutImport } + '/_layout/teams': { + preLoaderRoute: typeof LayoutTeamsImport + parentRoute: typeof LayoutImport + } '/_layout/': { preLoaderRoute: typeof LayoutIndexImport parentRoute: typeof LayoutImport @@ -108,6 +118,7 @@ export const routeTree = rootRoute.addChildren([ LayoutAdminRoute, LayoutItemsRoute, LayoutSettingsRoute, + LayoutTeamsRoute, LayoutIndexRoute, ]), LoginRoute, From 6245e20534e1ae7c84fa0f4c6d54b3458ceb4312 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Sun, 14 Apr 2024 13:33:50 +0800 Subject: [PATCH 04/21] frontend: Add teams page --- .../src/components/Common/ActionsMenu.tsx | 13 +- .../src/components/Common/DeleteAlert.tsx | 8 +- frontend/src/components/Common/Navbar.tsx | 11 +- frontend/src/components/Teams/AddTeam.tsx | 116 ++++++++++++++++ frontend/src/components/Teams/EditTeam.tsx | 126 ++++++++++++++++++ frontend/src/routeTree.gen.ts | 58 ++++---- frontend/src/routes/_layout/teams.tsx | 90 +++++++++++++ 7 files changed, 387 insertions(+), 35 deletions(-) create mode 100644 frontend/src/components/Teams/AddTeam.tsx create mode 100644 frontend/src/components/Teams/EditTeam.tsx create mode 100644 frontend/src/routes/_layout/teams.tsx diff --git a/frontend/src/components/Common/ActionsMenu.tsx b/frontend/src/components/Common/ActionsMenu.tsx index 3cc2dc0c..9dc5fd33 100644 --- a/frontend/src/components/Common/ActionsMenu.tsx +++ b/frontend/src/components/Common/ActionsMenu.tsx @@ -9,14 +9,15 @@ import { import { BsThreeDotsVertical } from "react-icons/bs" import { FiEdit, FiTrash } from "react-icons/fi" -import type { ItemOut, UserOut } from "../../client" +import type { ItemOut, TeamOut, UserOut } from "../../client" import EditUser from "../Admin/EditUser" import EditItem from "../Items/EditItem" +import EditTeam from "../Teams/EditTeam" import Delete from "./DeleteAlert" interface ActionsMenuProps { type: string - value: ItemOut | UserOut + value: ItemOut | UserOut | TeamOut disabled?: boolean } @@ -54,12 +55,18 @@ const ActionsMenu = ({ type, value, disabled }: ActionsMenuProps) => { isOpen={editUserModal.isOpen} onClose={editUserModal.onClose} /> - ) : ( + ) : type === "Item" ? ( + ) : ( + )} { await ItemsService.deleteItem({ id: id }) } else if (type === "User") { await UsersService.deleteUser({ userId: id }) + } else if (type === "Team") { + await TeamsService.deleteTeam({ id: id }) } else { throw new Error(`Unexpected type: ${type}`) } @@ -57,7 +59,9 @@ const Delete = ({ type, id, isOpen, onClose }: DeleteProps) => { ) }, onSettled: () => { - queryClient.invalidateQueries(type === "Item" ? "items" : "users") + queryClient.invalidateQueries( + type === "Item" ? "items" : type === "User" ? "users" : "teams", + ) }, }) diff --git a/frontend/src/components/Common/Navbar.tsx b/frontend/src/components/Common/Navbar.tsx index 6fcd3a1f..b52db606 100644 --- a/frontend/src/components/Common/Navbar.tsx +++ b/frontend/src/components/Common/Navbar.tsx @@ -3,6 +3,7 @@ import { FaPlus } from "react-icons/fa" import AddUser from "../Admin/AddUser" import AddItem from "../Items/AddItem" +import AddTeam from "../Teams/AddTeam" interface NavbarProps { type: string @@ -11,6 +12,7 @@ interface NavbarProps { const Navbar = ({ type }: NavbarProps) => { const addUserModal = useDisclosure() const addItemModal = useDisclosure() + const addTeamModal = useDisclosure() return ( <> @@ -26,12 +28,19 @@ const Navbar = ({ type }: NavbarProps) => { variant="primary" gap={1} fontSize={{ base: "sm", md: "inherit" }} - onClick={type === "User" ? addUserModal.onOpen : addItemModal.onOpen} + onClick={ + type === "User" + ? addUserModal.onOpen + : type === "Item" + ? addItemModal.onOpen + : addTeamModal.onOpen + } > Add {type} + ) diff --git a/frontend/src/components/Teams/AddTeam.tsx b/frontend/src/components/Teams/AddTeam.tsx new file mode 100644 index 00000000..79799350 --- /dev/null +++ b/frontend/src/components/Teams/AddTeam.tsx @@ -0,0 +1,116 @@ +import { + Button, + FormControl, + FormErrorMessage, + FormLabel, + Input, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, +} from "@chakra-ui/react" +import { type SubmitHandler, useForm } from "react-hook-form" +import { useMutation, useQueryClient } from "react-query" + +import { type ApiError, type TeamCreate, TeamsService } from "../../client" +import useCustomToast from "../../hooks/useCustomToast" + +interface AddTeamProps { + isOpen: boolean + onClose: () => void +} + +const AddTeam = ({ isOpen, onClose }: AddTeamProps) => { + const queryClient = useQueryClient() + const showToast = useCustomToast() + const { + register, + handleSubmit, + reset, + formState: { errors, isSubmitting }, + } = useForm({ + mode: "onBlur", + criteriaMode: "all", + defaultValues: { + name: "", + description: "", + }, + }) + + const addTeam = async (data: TeamCreate) => { + await TeamsService.createTeam({ requestBody: data }) + } + + const mutation = useMutation(addTeam, { + onSuccess: () => { + showToast("Success!", "Team created successfully.", "success") + reset() + onClose() + }, + onError: (err: ApiError) => { + const errDetail = err.body?.detail + showToast("Something went wrong.", `${errDetail}`, "error") + }, + onSettled: () => { + queryClient.invalidateQueries("teams") + }, + }) + + const onSubmit: SubmitHandler = (data) => { + mutation.mutate(data) + } + + return ( + <> + + + + Add Team + + + + Name + + {errors.name && ( + {errors.name.message} + )} + + + Description + + + + + + + + + + + + ) +} + +export default AddTeam diff --git a/frontend/src/components/Teams/EditTeam.tsx b/frontend/src/components/Teams/EditTeam.tsx new file mode 100644 index 00000000..74cfb1c0 --- /dev/null +++ b/frontend/src/components/Teams/EditTeam.tsx @@ -0,0 +1,126 @@ +import { + Button, + FormControl, + FormErrorMessage, + FormLabel, + Input, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, +} from "@chakra-ui/react" +import { type SubmitHandler, useForm } from "react-hook-form" + +import { useMutation, useQueryClient } from "react-query" +import { + type ApiError, + type TeamOut, + type TeamUpdate, + TeamsService, +} from "../../client" +import useCustomToast from "../../hooks/useCustomToast" + +interface EditTeamProps { + team: TeamOut + isOpen: boolean + onClose: () => void +} + +const EditTeam = ({ team, isOpen, onClose }: EditTeamProps) => { + const queryClient = useQueryClient() + const showToast = useCustomToast() + const { + register, + handleSubmit, + reset, + formState: { isSubmitting, errors, isDirty }, + } = useForm({ + mode: "onBlur", + criteriaMode: "all", + defaultValues: team, + }) + + const updateTeam = async (data: TeamUpdate) => { + await TeamsService.updateTeam({ id: team.id, requestBody: data }) + } + + const mutation = useMutation(updateTeam, { + onSuccess: () => { + showToast("Success!", "Team updated successfully.", "success") + onClose() + }, + onError: (err: ApiError) => { + const errDetail = err.body?.detail + showToast("Something went wrong.", `${errDetail}`, "error") + }, + onSettled: () => { + queryClient.invalidateQueries("teams") + }, + }) + + const onSubmit: SubmitHandler = async (data) => { + mutation.mutate(data) + } + + const onCancel = () => { + reset() + onClose() + } + + return ( + <> + + + + Edit Team + + + + Name + + {errors.name && ( + {errors.name.message} + )} + + + Description + + + + + + + + + + + ) +} + +export default EditTeam diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 6bbb6738..8d35934d 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -10,101 +10,101 @@ // Import Routes -import { Route as rootRoute } from './routes/__root' -import { Route as ResetPasswordImport } from './routes/reset-password' -import { Route as RecoverPasswordImport } from './routes/recover-password' -import { Route as LoginImport } from './routes/login' -import { Route as LayoutImport } from './routes/_layout' -import { Route as LayoutIndexImport } from './routes/_layout/index' -import { Route as LayoutTeamsImport } from './routes/_layout/teams' -import { Route as LayoutSettingsImport } from './routes/_layout/settings' -import { Route as LayoutItemsImport } from './routes/_layout/items' -import { Route as LayoutAdminImport } from './routes/_layout/admin' +import { Route as rootRoute } from "./routes/__root" +import { Route as LayoutImport } from "./routes/_layout" +import { Route as LayoutAdminImport } from "./routes/_layout/admin" +import { Route as LayoutIndexImport } from "./routes/_layout/index" +import { Route as LayoutItemsImport } from "./routes/_layout/items" +import { Route as LayoutSettingsImport } from "./routes/_layout/settings" +import { Route as LayoutTeamsImport } from "./routes/_layout/teams" +import { Route as LoginImport } from "./routes/login" +import { Route as RecoverPasswordImport } from "./routes/recover-password" +import { Route as ResetPasswordImport } from "./routes/reset-password" // Create/Update Routes const ResetPasswordRoute = ResetPasswordImport.update({ - path: '/reset-password', + path: "/reset-password", getParentRoute: () => rootRoute, } as any) const RecoverPasswordRoute = RecoverPasswordImport.update({ - path: '/recover-password', + path: "/recover-password", getParentRoute: () => rootRoute, } as any) const LoginRoute = LoginImport.update({ - path: '/login', + path: "/login", getParentRoute: () => rootRoute, } as any) const LayoutRoute = LayoutImport.update({ - id: '/_layout', + id: "/_layout", getParentRoute: () => rootRoute, } as any) const LayoutIndexRoute = LayoutIndexImport.update({ - path: '/', + path: "/", getParentRoute: () => LayoutRoute, } as any) const LayoutTeamsRoute = LayoutTeamsImport.update({ - path: '/teams', + path: "/teams", getParentRoute: () => LayoutRoute, } as any) const LayoutSettingsRoute = LayoutSettingsImport.update({ - path: '/settings', + path: "/settings", getParentRoute: () => LayoutRoute, } as any) const LayoutItemsRoute = LayoutItemsImport.update({ - path: '/items', + path: "/items", getParentRoute: () => LayoutRoute, } as any) const LayoutAdminRoute = LayoutAdminImport.update({ - path: '/admin', + path: "/admin", getParentRoute: () => LayoutRoute, } as any) // Populate the FileRoutesByPath interface -declare module '@tanstack/react-router' { +declare module "@tanstack/react-router" { interface FileRoutesByPath { - '/_layout': { + "/_layout": { preLoaderRoute: typeof LayoutImport parentRoute: typeof rootRoute } - '/login': { + "/login": { preLoaderRoute: typeof LoginImport parentRoute: typeof rootRoute } - '/recover-password': { + "/recover-password": { preLoaderRoute: typeof RecoverPasswordImport parentRoute: typeof rootRoute } - '/reset-password': { + "/reset-password": { preLoaderRoute: typeof ResetPasswordImport parentRoute: typeof rootRoute } - '/_layout/admin': { + "/_layout/admin": { preLoaderRoute: typeof LayoutAdminImport parentRoute: typeof LayoutImport } - '/_layout/items': { + "/_layout/items": { preLoaderRoute: typeof LayoutItemsImport parentRoute: typeof LayoutImport } - '/_layout/settings': { + "/_layout/settings": { preLoaderRoute: typeof LayoutSettingsImport parentRoute: typeof LayoutImport } - '/_layout/teams': { + "/_layout/teams": { preLoaderRoute: typeof LayoutTeamsImport parentRoute: typeof LayoutImport } - '/_layout/': { + "/_layout/": { preLoaderRoute: typeof LayoutIndexImport parentRoute: typeof LayoutImport } diff --git a/frontend/src/routes/_layout/teams.tsx b/frontend/src/routes/_layout/teams.tsx new file mode 100644 index 00000000..5d00e1fa --- /dev/null +++ b/frontend/src/routes/_layout/teams.tsx @@ -0,0 +1,90 @@ +import { + Container, + Flex, + Heading, + Spinner, + Table, + TableContainer, + Tbody, + Td, + Th, + Thead, + Tr, +} from "@chakra-ui/react" +import { createFileRoute } from "@tanstack/react-router" +import { useQuery } from "react-query" +import { type ApiError, TeamsService } from "../../client" +import ActionsMenu from "../../components/Common/ActionsMenu" +import Navbar from "../../components/Common/Navbar" +import useCustomToast from "../../hooks/useCustomToast" + +export const Route = createFileRoute("/_layout/teams")({ + component: Teams, +}) + +function Teams() { + const showToast = useCustomToast() + const { + data: teams, + isLoading, + isError, + error, + } = useQuery("teams", () => TeamsService.readTeams({})) + + if (isError) { + const errDetail = (error as ApiError).body?.detail + showToast("Something went wrong.", `${errDetail}`, "error") + } + + return ( + <> + {isLoading ? ( + // TODO: Add skeleton + + + + ) : ( + teams && ( + + + Teams Management + + + + + + + + + + + + + + {teams.data.map((team) => ( + + + + + + + ))} + +
IDTitleDescriptionActions
{team.id}{team.name} + {team.description || "N/A"} + + +
+
+
+ ) + )} + + ) +} + +export default Teams From 09a40309a32db8c3f72c359246d227870e6f4963 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Sun, 14 Apr 2024 13:39:43 +0800 Subject: [PATCH 05/21] Add biome.json to root so vscode respects the config when formatting documents --- .vscode/launch.json | 49 +++++++++++++++++++++------------------------ biome.json | 31 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 biome.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 24eae850..3ba4463d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,28 +1,25 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Debug FastAPI Project backend: Python Debugger", - "type": "debugpy", - "request": "launch", - "module": "uvicorn", - "args": [ - "app.main:app", - "--reload" - ], - "cwd": "${workspaceFolder}/backend", - "jinja": true, - "envFile": "${workspaceFolder}/.env", - }, - { - "type": "chrome", - "request": "launch", - "name": "Debug Frontend: Launch Chrome against http://localhost:5173", - "url": "http://localhost:5173", - "webRoot": "${workspaceFolder}/frontend" - }, - ] + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug FastAPI Project backend: Python Debugger", + "type": "debugpy", + "request": "launch", + "module": "uvicorn", + "args": ["app.main:app", "--reload"], + "cwd": "${workspaceFolder}/backend", + "jinja": true, + "envFile": "${workspaceFolder}/.env" + }, + { + "type": "chrome", + "request": "launch", + "name": "Debug Frontend: Launch Chrome against http://localhost:5173", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}/frontend" + } + ] } diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..4d49b98b --- /dev/null +++ b/biome.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.6.1/schema.json", + "organizeImports": { + "enabled": true + }, + "files": { + "ignore": ["node_modules", "src/client/"] + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "off", + "noArrayIndexKey": "off" + }, + "style": { + "noNonNullAssertion": "off" + } + } + }, + "formatter": { + "indentStyle": "space" + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "semicolons": "asNeeded" + } + } +} From c5958e13d8b732c4cb91a9ca0cd9282ed7d48543 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Mon, 15 Apr 2024 20:23:40 +0800 Subject: [PATCH 06/21] frontend: Add team page and update sidebar to show teams button --- .../src/components/Common/SidebarItems.tsx | 2 + frontend/src/routeTree.gen.ts | 83 +++++++++++-------- frontend/src/routes/_layout/teams.$teamId.tsx | 76 +++++++++++++++++ .../_layout/{teams.tsx => teams.index.tsx} | 29 ++++--- 4 files changed, 143 insertions(+), 47 deletions(-) create mode 100644 frontend/src/routes/_layout/teams.$teamId.tsx rename frontend/src/routes/_layout/{teams.tsx => teams.index.tsx} (80%) diff --git a/frontend/src/components/Common/SidebarItems.tsx b/frontend/src/components/Common/SidebarItems.tsx index d075b09d..d6aad6e7 100644 --- a/frontend/src/components/Common/SidebarItems.tsx +++ b/frontend/src/components/Common/SidebarItems.tsx @@ -1,6 +1,7 @@ import { Box, Flex, Icon, Text, useColorModeValue } from "@chakra-ui/react" import { Link } from "@tanstack/react-router" import { FiBriefcase, FiHome, FiSettings, FiUsers } from "react-icons/fi" +import { LuNetwork } from "react-icons/lu" import { useQueryClient } from "react-query" import type { UserOut } from "../../client" @@ -8,6 +9,7 @@ import type { UserOut } from "../../client" const items = [ { icon: FiHome, title: "Dashboard", path: "/" }, { icon: FiBriefcase, title: "Items", path: "/items" }, + { icon: LuNetwork, title: "Teams", path: "/teams" }, { icon: FiSettings, title: "User Settings", path: "/settings" }, ] diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 8d35934d..edcede33 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -10,102 +10,112 @@ // Import Routes -import { Route as rootRoute } from "./routes/__root" -import { Route as LayoutImport } from "./routes/_layout" -import { Route as LayoutAdminImport } from "./routes/_layout/admin" -import { Route as LayoutIndexImport } from "./routes/_layout/index" -import { Route as LayoutItemsImport } from "./routes/_layout/items" -import { Route as LayoutSettingsImport } from "./routes/_layout/settings" -import { Route as LayoutTeamsImport } from "./routes/_layout/teams" -import { Route as LoginImport } from "./routes/login" -import { Route as RecoverPasswordImport } from "./routes/recover-password" -import { Route as ResetPasswordImport } from "./routes/reset-password" +import { Route as rootRoute } from './routes/__root' +import { Route as ResetPasswordImport } from './routes/reset-password' +import { Route as RecoverPasswordImport } from './routes/recover-password' +import { Route as LoginImport } from './routes/login' +import { Route as LayoutImport } from './routes/_layout' +import { Route as LayoutIndexImport } from './routes/_layout/index' +import { Route as LayoutSettingsImport } from './routes/_layout/settings' +import { Route as LayoutItemsImport } from './routes/_layout/items' +import { Route as LayoutAdminImport } from './routes/_layout/admin' +import { Route as LayoutTeamsIndexImport } from './routes/_layout/teams.index' +import { Route as LayoutTeamsTeamIdImport } from './routes/_layout/teams.$teamId' // Create/Update Routes const ResetPasswordRoute = ResetPasswordImport.update({ - path: "/reset-password", + path: '/reset-password', getParentRoute: () => rootRoute, } as any) const RecoverPasswordRoute = RecoverPasswordImport.update({ - path: "/recover-password", + path: '/recover-password', getParentRoute: () => rootRoute, } as any) const LoginRoute = LoginImport.update({ - path: "/login", + path: '/login', getParentRoute: () => rootRoute, } as any) const LayoutRoute = LayoutImport.update({ - id: "/_layout", + id: '/_layout', getParentRoute: () => rootRoute, } as any) const LayoutIndexRoute = LayoutIndexImport.update({ - path: "/", - getParentRoute: () => LayoutRoute, -} as any) - -const LayoutTeamsRoute = LayoutTeamsImport.update({ - path: "/teams", + path: '/', getParentRoute: () => LayoutRoute, } as any) const LayoutSettingsRoute = LayoutSettingsImport.update({ - path: "/settings", + path: '/settings', getParentRoute: () => LayoutRoute, } as any) const LayoutItemsRoute = LayoutItemsImport.update({ - path: "/items", + path: '/items', getParentRoute: () => LayoutRoute, } as any) const LayoutAdminRoute = LayoutAdminImport.update({ - path: "/admin", + path: '/admin', + getParentRoute: () => LayoutRoute, +} as any) + +const LayoutTeamsIndexRoute = LayoutTeamsIndexImport.update({ + path: '/teams/', + getParentRoute: () => LayoutRoute, +} as any) + +const LayoutTeamsTeamIdRoute = LayoutTeamsTeamIdImport.update({ + path: '/teams/$teamId', getParentRoute: () => LayoutRoute, } as any) // Populate the FileRoutesByPath interface -declare module "@tanstack/react-router" { +declare module '@tanstack/react-router' { interface FileRoutesByPath { - "/_layout": { + '/_layout': { preLoaderRoute: typeof LayoutImport parentRoute: typeof rootRoute } - "/login": { + '/login': { preLoaderRoute: typeof LoginImport parentRoute: typeof rootRoute } - "/recover-password": { + '/recover-password': { preLoaderRoute: typeof RecoverPasswordImport parentRoute: typeof rootRoute } - "/reset-password": { + '/reset-password': { preLoaderRoute: typeof ResetPasswordImport parentRoute: typeof rootRoute } - "/_layout/admin": { + '/_layout/admin': { preLoaderRoute: typeof LayoutAdminImport parentRoute: typeof LayoutImport } - "/_layout/items": { + '/_layout/items': { preLoaderRoute: typeof LayoutItemsImport parentRoute: typeof LayoutImport } - "/_layout/settings": { + '/_layout/settings': { preLoaderRoute: typeof LayoutSettingsImport parentRoute: typeof LayoutImport } - "/_layout/teams": { - preLoaderRoute: typeof LayoutTeamsImport + '/_layout/': { + preLoaderRoute: typeof LayoutIndexImport + parentRoute: typeof LayoutImport + } + '/_layout/teams/$teamId': { + preLoaderRoute: typeof LayoutTeamsTeamIdImport parentRoute: typeof LayoutImport } - "/_layout/": { - preLoaderRoute: typeof LayoutIndexImport + '/_layout/teams/': { + preLoaderRoute: typeof LayoutTeamsIndexImport parentRoute: typeof LayoutImport } } @@ -118,8 +128,9 @@ export const routeTree = rootRoute.addChildren([ LayoutAdminRoute, LayoutItemsRoute, LayoutSettingsRoute, - LayoutTeamsRoute, LayoutIndexRoute, + LayoutTeamsTeamIdRoute, + LayoutTeamsIndexRoute, ]), LoginRoute, RecoverPasswordRoute, diff --git a/frontend/src/routes/_layout/teams.$teamId.tsx b/frontend/src/routes/_layout/teams.$teamId.tsx new file mode 100644 index 00000000..2ede3d40 --- /dev/null +++ b/frontend/src/routes/_layout/teams.$teamId.tsx @@ -0,0 +1,76 @@ +import { + Flex, + Spinner, + Container, + Heading, + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, +} from "@chakra-ui/react" +import { Link, createFileRoute } from "@tanstack/react-router" +import { useQuery } from "react-query" +import { TeamsService, type ApiError } from "../../client" +import useCustomToast from "../../hooks/useCustomToast" +import { ChevronRightIcon } from "@chakra-ui/icons" + +export const Route = createFileRoute("/_layout/teams/$teamId")({ + component: Team, +}) + +function Team() { + const showToast = useCustomToast() + const { teamId } = Route.useParams() + const { + data: team, + isLoading, + isError, + error, + } = useQuery(`team/${teamId}`, () => + TeamsService.readTeam({ id: Number.parseInt(teamId) }), + ) + + if (isError) { + const errDetail = (error as ApiError).body?.detail + showToast("Something went wrong.", `${errDetail}`, "error") + } + + return ( + <> + {isLoading ? ( + // TODO: Add skeleton + + + + ) : ( + team && ( + + } + > + + + Teams + + + + + {team.name} + + + + + {team.name} + + + ) + )} + + ) +} + +export default Team diff --git a/frontend/src/routes/_layout/teams.tsx b/frontend/src/routes/_layout/teams.index.tsx similarity index 80% rename from frontend/src/routes/_layout/teams.tsx rename to frontend/src/routes/_layout/teams.index.tsx index 5d00e1fa..229e439d 100644 --- a/frontend/src/routes/_layout/teams.tsx +++ b/frontend/src/routes/_layout/teams.index.tsx @@ -1,24 +1,27 @@ import { - Container, Flex, - Heading, Spinner, - Table, + Container, + Heading, TableContainer, - Tbody, - Td, - Th, + Table, Thead, Tr, + Th, + Tbody, + Td, + LinkBox, + LinkOverlay, + textDecoration, } from "@chakra-ui/react" -import { createFileRoute } from "@tanstack/react-router" +import { Link, createFileRoute } from "@tanstack/react-router" import { useQuery } from "react-query" -import { type ApiError, TeamsService } from "../../client" +import { TeamsService, type ApiError } from "../../client" import ActionsMenu from "../../components/Common/ActionsMenu" import Navbar from "../../components/Common/Navbar" import useCustomToast from "../../hooks/useCustomToast" -export const Route = createFileRoute("/_layout/teams")({ +export const Route = createFileRoute("/_layout/teams/")({ component: Teams, }) @@ -59,7 +62,7 @@ function Teams() { ID - Title + Name Description Actions @@ -68,7 +71,11 @@ function Teams() { {teams.data.map((team) => ( {team.id} - {team.name} + + + {team.name} + + {team.description || "N/A"} From 1d99a55777daf9842450e30ec8ad7292e1a2cd21 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Tue, 16 Apr 2024 22:38:11 +0800 Subject: [PATCH 07/21] backend: Add team member route --- backend/app/api/main.py | 3 +- backend/app/api/routes/members.py | 123 ++++++++++++++++++++++++++++++ backend/app/models.py | 2 +- 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 backend/app/api/routes/members.py diff --git a/backend/app/api/main.py b/backend/app/api/main.py index c4de0e06..2e555293 100644 --- a/backend/app/api/main.py +++ b/backend/app/api/main.py @@ -1,6 +1,6 @@ from fastapi import APIRouter -from app.api.routes import items, login, users, utils, teams +from app.api.routes import items, login, members, users, utils, teams api_router = APIRouter() api_router.include_router(login.router, tags=["login"]) @@ -8,3 +8,4 @@ api_router.include_router(utils.router, prefix="/utils", tags=["utils"]) api_router.include_router(items.router, prefix="/items", tags=["items"]) api_router.include_router(teams.router, prefix="/teams", tags=["teams"]) +api_router.include_router(members.router, prefix="/teams/{team_id}", tags=["team members"]) diff --git a/backend/app/api/routes/members.py b/backend/app/api/routes/members.py new file mode 100644 index 00000000..b1de4804 --- /dev/null +++ b/backend/app/api/routes/members.py @@ -0,0 +1,123 @@ +from typing import Any + +from fastapi import APIRouter, HTTPException +from sqlmodel import func, select + +from app.api.deps import CurrentUser, SessionDep +from app.models import Member, MemberCreate, MemberOut, MemberUpdate, MembersOut, Message, Team + +router = APIRouter() + + +@router.get("/members", response_model=MembersOut) +def read_members( + session: SessionDep, current_user: CurrentUser, team_id: int, skip: int = 0, limit: int = 100 +) -> Any: + """ + Retrieve members from team. + """ + + if current_user.is_superuser: + count_statement = select(func.count()).select_from(Member) + count = session.exec(count_statement).one() + statement = select(Member).where(Member.belongs_to == team_id).offset(skip).limit(limit) + members = session.exec(statement).all() + else: + count_statement = ( + select(func.count()) + .select_from(Member) + .join(Team) + .where(Team.owner_id == current_user.id, Member.belongs_to == team_id) + ) + count = session.exec(count_statement).one() + statement = ( + select(Member) + .join(Team) + .where(Team.owner_id == current_user.id, Member.belongs_to == team_id) + .offset(skip) + .limit(limit) + ) + members = session.exec(statement).all() + + return MembersOut(data=members, count=count) + + +@router.get("/members/{id}", response_model=MemberOut) +def read_member(session: SessionDep, current_user: CurrentUser, team_id: int, id: int) -> Any: + """ + Get member by ID. + """ + if current_user.is_superuser: + statement = select(Member).join(Team).where(Member.id == id, Member.belongs_to == team_id) + member = session.exec(statement).first() + else: + statement = select(Member).join(Team).where(Member.id == id, Member.belongs_to == team_id, Team.owner_id == current_user.id,) + member = session.exec(statement).first() + + if not member: + raise HTTPException(status_code=404, detail="Member not found") + return member + + +@router.post("/", response_model=MemberOut) +def create_member( + *, session: SessionDep, current_user: CurrentUser, team_id: int, member_in: MemberCreate +) -> Any: + """ + Create new member. + """ + if not current_user.is_superuser: + team = session.get(Team, team_id) + if team.owner_id != current_user.id: + raise HTTPException(status_code=400, detail="Not enough permissions") + print(member_in) + member = Member.model_validate(member_in, update={"belongs_to": team_id}) + session.add(member) + session.commit() + session.refresh(member) + return member + + +@router.put("/{id}", response_model=MemberOut) +def update_item( + *, session: SessionDep, current_user: CurrentUser, team_id: int, id: int, member_in: MemberUpdate +) -> Any: + """ + Update a member. + """ + if current_user.is_superuser: + statement = select(Member).join(Team).where(Member.id == id, Member.belongs_to == team_id) + member = session.exec(statement).first() + else: + statement = select(Member).join(Team).where(Member.id == id, Member.belongs_to == team_id, Team.owner_id == current_user.id) + member = session.exec(statement).first() + + if not member: + raise HTTPException(status_code=404, detail="Member not found") + + update_dict = member_in.model_dump(exclude_unset=True) + member.sqlmodel_update(update_dict) + session.add(member) + session.commit() + session.refresh(member) + return member + + +@router.delete("/{id}") +def delete_item(session: SessionDep, current_user: CurrentUser, team_id: int, id: int) -> Message: + """ + Delete a member. + """ + if current_user.is_superuser: + statement = select(Member).join(Team).where(Member.id == id, Member.belongs_to == team_id) + member = session.exec(statement).first() + else: + statement = select(Member).join(Team).where(Member.id == id, Member.belongs_to == team_id, Team.owner_id == current_user.id) + member = session.exec(statement).first() + + if not member: + raise HTTPException(status_code=404, detail="Member not found") + + session.delete(member) + session.commit() + return Message(message="Member deleted successfully") diff --git a/backend/app/models.py b/backend/app/models.py index bfa13604..f3e5f826 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -191,7 +191,7 @@ class MemberBase(SQLModel): backstory: str | None = None role: str type: str - owner_of: int | None = int + owner_of: int | None = None class MemberCreate(MemberBase): name: str From abe07f634ab677e0d3598c3c7feb0677b5c2c980 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Tue, 16 Apr 2024 22:50:53 +0800 Subject: [PATCH 08/21] frontend: Add autogen code for frontend. Rename backend endpoint --- backend/app/api/main.py | 2 +- backend/app/api/routes/members.py | 4 +- frontend/src/client/index.ts | 9 + frontend/src/client/models/MemberCreate.ts | 13 ++ frontend/src/client/models/MemberOut.ts | 15 ++ frontend/src/client/models/MemberUpdate.ts | 14 ++ frontend/src/client/models/MembersOut.ts | 12 ++ frontend/src/client/schemas/$MemberCreate.ts | 36 ++++ frontend/src/client/schemas/$MemberOut.ts | 45 +++++ frontend/src/client/schemas/$MemberUpdate.ts | 56 +++++++ frontend/src/client/schemas/$MembersOut.ts | 19 +++ .../src/client/services/MembersService.ts | 157 ++++++++++++++++++ 12 files changed, 379 insertions(+), 3 deletions(-) create mode 100644 frontend/src/client/models/MemberCreate.ts create mode 100644 frontend/src/client/models/MemberOut.ts create mode 100644 frontend/src/client/models/MemberUpdate.ts create mode 100644 frontend/src/client/models/MembersOut.ts create mode 100644 frontend/src/client/schemas/$MemberCreate.ts create mode 100644 frontend/src/client/schemas/$MemberOut.ts create mode 100644 frontend/src/client/schemas/$MemberUpdate.ts create mode 100644 frontend/src/client/schemas/$MembersOut.ts create mode 100644 frontend/src/client/services/MembersService.ts diff --git a/backend/app/api/main.py b/backend/app/api/main.py index 2e555293..b3e9b047 100644 --- a/backend/app/api/main.py +++ b/backend/app/api/main.py @@ -8,4 +8,4 @@ api_router.include_router(utils.router, prefix="/utils", tags=["utils"]) api_router.include_router(items.router, prefix="/items", tags=["items"]) api_router.include_router(teams.router, prefix="/teams", tags=["teams"]) -api_router.include_router(members.router, prefix="/teams/{team_id}", tags=["team members"]) +api_router.include_router(members.router, prefix="/teams/{team_id}", tags=["members"]) diff --git a/backend/app/api/routes/members.py b/backend/app/api/routes/members.py index b1de4804..5af0e9fc 100644 --- a/backend/app/api/routes/members.py +++ b/backend/app/api/routes/members.py @@ -79,7 +79,7 @@ def create_member( @router.put("/{id}", response_model=MemberOut) -def update_item( +def update_member( *, session: SessionDep, current_user: CurrentUser, team_id: int, id: int, member_in: MemberUpdate ) -> Any: """ @@ -104,7 +104,7 @@ def update_item( @router.delete("/{id}") -def delete_item(session: SessionDep, current_user: CurrentUser, team_id: int, id: int) -> Message: +def delete_member(session: SessionDep, current_user: CurrentUser, team_id: int, id: int) -> Message: """ Delete a member. """ diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts index 2d4cf462..2eaf2bd2 100644 --- a/frontend/src/client/index.ts +++ b/frontend/src/client/index.ts @@ -15,6 +15,10 @@ export type { ItemCreate } from './models/ItemCreate'; export type { ItemOut } from './models/ItemOut'; export type { ItemsOut } from './models/ItemsOut'; export type { ItemUpdate } from './models/ItemUpdate'; +export type { MemberCreate } from './models/MemberCreate'; +export type { MemberOut } from './models/MemberOut'; +export type { MembersOut } from './models/MembersOut'; +export type { MemberUpdate } from './models/MemberUpdate'; export type { Message } from './models/Message'; export type { NewPassword } from './models/NewPassword'; export type { TeamChat } from './models/TeamChat'; @@ -40,6 +44,10 @@ export { $ItemCreate } from './schemas/$ItemCreate'; export { $ItemOut } from './schemas/$ItemOut'; export { $ItemsOut } from './schemas/$ItemsOut'; export { $ItemUpdate } from './schemas/$ItemUpdate'; +export { $MemberCreate } from './schemas/$MemberCreate'; +export { $MemberOut } from './schemas/$MemberOut'; +export { $MembersOut } from './schemas/$MembersOut'; +export { $MemberUpdate } from './schemas/$MemberUpdate'; export { $Message } from './schemas/$Message'; export { $NewPassword } from './schemas/$NewPassword'; export { $TeamChat } from './schemas/$TeamChat'; @@ -59,6 +67,7 @@ export { $ValidationError } from './schemas/$ValidationError'; export { ItemsService } from './services/ItemsService'; export { LoginService } from './services/LoginService'; +export { MembersService } from './services/MembersService'; export { TeamsService } from './services/TeamsService'; export { UsersService } from './services/UsersService'; export { UtilsService } from './services/UtilsService'; diff --git a/frontend/src/client/models/MemberCreate.ts b/frontend/src/client/models/MemberCreate.ts new file mode 100644 index 00000000..1127f6b8 --- /dev/null +++ b/frontend/src/client/models/MemberCreate.ts @@ -0,0 +1,13 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type MemberCreate = { + name: string; + backstory?: (string | null); + role: string; + type: string; + owner_of?: (number | null); +}; + diff --git a/frontend/src/client/models/MemberOut.ts b/frontend/src/client/models/MemberOut.ts new file mode 100644 index 00000000..38565525 --- /dev/null +++ b/frontend/src/client/models/MemberOut.ts @@ -0,0 +1,15 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type MemberOut = { + name: string; + backstory?: (string | null); + role: string; + type: string; + owner_of: (number | null); + id: number; + belongs_to: number; +}; + diff --git a/frontend/src/client/models/MemberUpdate.ts b/frontend/src/client/models/MemberUpdate.ts new file mode 100644 index 00000000..ca09dc3b --- /dev/null +++ b/frontend/src/client/models/MemberUpdate.ts @@ -0,0 +1,14 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type MemberUpdate = { + name?: (string | null); + backstory?: (string | null); + role?: (string | null); + type?: (string | null); + owner_of?: (number | null); + belongs_to?: (number | null); +}; + diff --git a/frontend/src/client/models/MembersOut.ts b/frontend/src/client/models/MembersOut.ts new file mode 100644 index 00000000..4f472953 --- /dev/null +++ b/frontend/src/client/models/MembersOut.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { MemberOut } from './MemberOut'; + +export type MembersOut = { + data: Array; + count: number; +}; + diff --git a/frontend/src/client/schemas/$MemberCreate.ts b/frontend/src/client/schemas/$MemberCreate.ts new file mode 100644 index 00000000..84e1a30f --- /dev/null +++ b/frontend/src/client/schemas/$MemberCreate.ts @@ -0,0 +1,36 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $MemberCreate = { + properties: { + name: { + type: 'string', + isRequired: true, + }, + backstory: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + role: { + type: 'string', + isRequired: true, + }, + type: { + type: 'string', + isRequired: true, + }, + owner_of: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$MemberOut.ts b/frontend/src/client/schemas/$MemberOut.ts new file mode 100644 index 00000000..ec275cfa --- /dev/null +++ b/frontend/src/client/schemas/$MemberOut.ts @@ -0,0 +1,45 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $MemberOut = { + properties: { + name: { + type: 'string', + isRequired: true, + }, + backstory: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + role: { + type: 'string', + isRequired: true, + }, + type: { + type: 'string', + isRequired: true, + }, + owner_of: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + isRequired: true, + }, + id: { + type: 'number', + isRequired: true, + }, + belongs_to: { + type: 'number', + isRequired: true, + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$MemberUpdate.ts b/frontend/src/client/schemas/$MemberUpdate.ts new file mode 100644 index 00000000..f8474f77 --- /dev/null +++ b/frontend/src/client/schemas/$MemberUpdate.ts @@ -0,0 +1,56 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $MemberUpdate = { + properties: { + name: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + backstory: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + role: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + type: { + type: 'any-of', + contains: [{ + type: 'string', + }, { + type: 'null', + }], + }, + owner_of: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, + belongs_to: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, + }, +} as const; diff --git a/frontend/src/client/schemas/$MembersOut.ts b/frontend/src/client/schemas/$MembersOut.ts new file mode 100644 index 00000000..488077fe --- /dev/null +++ b/frontend/src/client/schemas/$MembersOut.ts @@ -0,0 +1,19 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $MembersOut = { + properties: { + data: { + type: 'array', + contains: { + type: 'MemberOut', + }, + isRequired: true, + }, + count: { + type: 'number', + isRequired: true, + }, + }, +} as const; diff --git a/frontend/src/client/services/MembersService.ts b/frontend/src/client/services/MembersService.ts new file mode 100644 index 00000000..1159a854 --- /dev/null +++ b/frontend/src/client/services/MembersService.ts @@ -0,0 +1,157 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { MemberCreate } from '../models/MemberCreate'; +import type { MemberOut } from '../models/MemberOut'; +import type { MembersOut } from '../models/MembersOut'; +import type { MemberUpdate } from '../models/MemberUpdate'; +import type { Message } from '../models/Message'; + +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; + +export class MembersService { + + /** + * Read Members + * Retrieve members from team. + * @returns MembersOut Successful Response + * @throws ApiError + */ + public static readMembers({ + teamId, + skip, + limit = 100, + }: { + teamId: number, + skip?: number, + limit?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/teams/{team_id}/members', + path: { + 'team_id': teamId, + }, + query: { + 'skip': skip, + 'limit': limit, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Read Member + * Get member by ID. + * @returns MemberOut Successful Response + * @throws ApiError + */ + public static readMember({ + teamId, + id, + }: { + teamId: number, + id: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/teams/{team_id}/members/{id}', + path: { + 'team_id': teamId, + 'id': id, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Create Member + * Create new member. + * @returns MemberOut Successful Response + * @throws ApiError + */ + public static createMember({ + teamId, + requestBody, + }: { + teamId: number, + requestBody: MemberCreate, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/teams/{team_id}/', + path: { + 'team_id': teamId, + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Update Member + * Update a member. + * @returns MemberOut Successful Response + * @throws ApiError + */ + public static updateMember({ + teamId, + id, + requestBody, + }: { + teamId: number, + id: number, + requestBody: MemberUpdate, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PUT', + url: '/api/v1/teams/{team_id}/{id}', + path: { + 'team_id': teamId, + 'id': id, + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + + /** + * Delete Member + * Delete a member. + * @returns Message Successful Response + * @throws ApiError + */ + public static deleteMember({ + teamId, + id, + }: { + teamId: number, + id: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/api/v1/teams/{team_id}/{id}', + path: { + 'team_id': teamId, + 'id': id, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + +} From a1931cc13c1a49fbef528811aca7069b94478e23 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Wed, 17 Apr 2024 23:23:27 +0800 Subject: [PATCH 09/21] Add position columns in member model --- backend/app/models.py | 6 ++++++ frontend/src/client/models/MemberCreate.ts | 2 ++ frontend/src/client/models/MemberOut.ts | 2 ++ frontend/src/client/models/MemberUpdate.ts | 2 ++ frontend/src/client/schemas/$MemberCreate.ts | 8 ++++++++ frontend/src/client/schemas/$MemberOut.ts | 8 ++++++++ frontend/src/client/schemas/$MemberUpdate.ts | 16 ++++++++++++++++ 7 files changed, 44 insertions(+) diff --git a/backend/app/models.py b/backend/app/models.py index f3e5f826..c0416fc8 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -192,6 +192,9 @@ class MemberBase(SQLModel): role: str type: str owner_of: int | None = None + position_x: float + position_y: float + class MemberCreate(MemberBase): name: str @@ -201,6 +204,9 @@ class MemberUpdate(MemberBase): role: str | None = None type: str | None = None belongs_to: int | None = None + position_x: float | None = None + position_y: float | None = None + class Member(MemberBase, table=True): id: int | None = Field(default=None, primary_key=True) diff --git a/frontend/src/client/models/MemberCreate.ts b/frontend/src/client/models/MemberCreate.ts index 1127f6b8..22c38499 100644 --- a/frontend/src/client/models/MemberCreate.ts +++ b/frontend/src/client/models/MemberCreate.ts @@ -9,5 +9,7 @@ export type MemberCreate = { role: string; type: string; owner_of?: (number | null); + position_x: number; + position_y: number; }; diff --git a/frontend/src/client/models/MemberOut.ts b/frontend/src/client/models/MemberOut.ts index 38565525..a29d5c40 100644 --- a/frontend/src/client/models/MemberOut.ts +++ b/frontend/src/client/models/MemberOut.ts @@ -9,6 +9,8 @@ export type MemberOut = { role: string; type: string; owner_of: (number | null); + position_x: number; + position_y: number; id: number; belongs_to: number; }; diff --git a/frontend/src/client/models/MemberUpdate.ts b/frontend/src/client/models/MemberUpdate.ts index ca09dc3b..8d5b3d21 100644 --- a/frontend/src/client/models/MemberUpdate.ts +++ b/frontend/src/client/models/MemberUpdate.ts @@ -9,6 +9,8 @@ export type MemberUpdate = { role?: (string | null); type?: (string | null); owner_of?: (number | null); + position_x?: (number | null); + position_y?: (number | null); belongs_to?: (number | null); }; diff --git a/frontend/src/client/schemas/$MemberCreate.ts b/frontend/src/client/schemas/$MemberCreate.ts index 84e1a30f..699eba38 100644 --- a/frontend/src/client/schemas/$MemberCreate.ts +++ b/frontend/src/client/schemas/$MemberCreate.ts @@ -32,5 +32,13 @@ export const $MemberCreate = { type: 'null', }], }, + position_x: { + type: 'number', + isRequired: true, + }, + position_y: { + type: 'number', + isRequired: true, + }, }, } as const; diff --git a/frontend/src/client/schemas/$MemberOut.ts b/frontend/src/client/schemas/$MemberOut.ts index ec275cfa..5bae119d 100644 --- a/frontend/src/client/schemas/$MemberOut.ts +++ b/frontend/src/client/schemas/$MemberOut.ts @@ -33,6 +33,14 @@ export const $MemberOut = { }], isRequired: true, }, + position_x: { + type: 'number', + isRequired: true, + }, + position_y: { + type: 'number', + isRequired: true, + }, id: { type: 'number', isRequired: true, diff --git a/frontend/src/client/schemas/$MemberUpdate.ts b/frontend/src/client/schemas/$MemberUpdate.ts index f8474f77..0596b60b 100644 --- a/frontend/src/client/schemas/$MemberUpdate.ts +++ b/frontend/src/client/schemas/$MemberUpdate.ts @@ -44,6 +44,22 @@ export const $MemberUpdate = { type: 'null', }], }, + position_x: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, + position_y: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, belongs_to: { type: 'any-of', contains: [{ From 53c4576631d216870bb23e78e9433af7ff88f426 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Thu, 18 Apr 2024 21:30:12 +0800 Subject: [PATCH 10/21] backend: Allow deleted team to cascade delete it's members --- backend/app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/models.py b/backend/app/models.py index c0416fc8..8f6cf92e 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -161,7 +161,7 @@ class Team(TeamBase, table=True): id: int | None = Field(default=None, primary_key=True) owner_id: int | None = Field(default=None, foreign_key="user.id", nullable=False) owner: User | None = Relationship(back_populates="teams") - members: list["Member"] = Relationship(back_populates="belongs") + members: list["Member"] = Relationship(back_populates="belongs", sa_relationship_kwargs={"cascade": "delete"}) # Properties to return via API, id is always required class TeamOut(TeamBase): From 3e42d38b61611aa3f63d1f769549a8d735e0840d Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Thu, 18 Apr 2024 22:09:50 +0800 Subject: [PATCH 11/21] Add source column to members table --- backend/app/models.py | 1 + frontend/src/client/models/MemberCreate.ts | 1 + frontend/src/client/models/MemberOut.ts | 1 + frontend/src/client/models/MemberUpdate.ts | 1 + frontend/src/client/schemas/$MemberCreate.ts | 8 ++++++++ frontend/src/client/schemas/$MemberOut.ts | 8 ++++++++ frontend/src/client/schemas/$MemberUpdate.ts | 8 ++++++++ frontend/src/client/services/TeamsService.ts | 2 +- 8 files changed, 29 insertions(+), 1 deletion(-) diff --git a/backend/app/models.py b/backend/app/models.py index 8f6cf92e..fbc22711 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -194,6 +194,7 @@ class MemberBase(SQLModel): owner_of: int | None = None position_x: float position_y: float + source: int | None = None class MemberCreate(MemberBase): name: str diff --git a/frontend/src/client/models/MemberCreate.ts b/frontend/src/client/models/MemberCreate.ts index 22c38499..2b49def1 100644 --- a/frontend/src/client/models/MemberCreate.ts +++ b/frontend/src/client/models/MemberCreate.ts @@ -11,5 +11,6 @@ export type MemberCreate = { owner_of?: (number | null); position_x: number; position_y: number; + source?: (number | null); }; diff --git a/frontend/src/client/models/MemberOut.ts b/frontend/src/client/models/MemberOut.ts index a29d5c40..260f0a27 100644 --- a/frontend/src/client/models/MemberOut.ts +++ b/frontend/src/client/models/MemberOut.ts @@ -11,6 +11,7 @@ export type MemberOut = { owner_of: (number | null); position_x: number; position_y: number; + source?: (number | null); id: number; belongs_to: number; }; diff --git a/frontend/src/client/models/MemberUpdate.ts b/frontend/src/client/models/MemberUpdate.ts index 8d5b3d21..069d056e 100644 --- a/frontend/src/client/models/MemberUpdate.ts +++ b/frontend/src/client/models/MemberUpdate.ts @@ -11,6 +11,7 @@ export type MemberUpdate = { owner_of?: (number | null); position_x?: (number | null); position_y?: (number | null); + source?: (number | null); belongs_to?: (number | null); }; diff --git a/frontend/src/client/schemas/$MemberCreate.ts b/frontend/src/client/schemas/$MemberCreate.ts index 699eba38..525a9a2b 100644 --- a/frontend/src/client/schemas/$MemberCreate.ts +++ b/frontend/src/client/schemas/$MemberCreate.ts @@ -40,5 +40,13 @@ export const $MemberCreate = { type: 'number', isRequired: true, }, + source: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, }, } as const; diff --git a/frontend/src/client/schemas/$MemberOut.ts b/frontend/src/client/schemas/$MemberOut.ts index 5bae119d..236fa7d7 100644 --- a/frontend/src/client/schemas/$MemberOut.ts +++ b/frontend/src/client/schemas/$MemberOut.ts @@ -41,6 +41,14 @@ export const $MemberOut = { type: 'number', isRequired: true, }, + source: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, id: { type: 'number', isRequired: true, diff --git a/frontend/src/client/schemas/$MemberUpdate.ts b/frontend/src/client/schemas/$MemberUpdate.ts index 0596b60b..912f311d 100644 --- a/frontend/src/client/schemas/$MemberUpdate.ts +++ b/frontend/src/client/schemas/$MemberUpdate.ts @@ -60,6 +60,14 @@ export const $MemberUpdate = { type: 'null', }], }, + source: { + type: 'any-of', + contains: [{ + type: 'number', + }, { + type: 'null', + }], + }, belongs_to: { type: 'any-of', contains: [{ diff --git a/frontend/src/client/services/TeamsService.ts b/frontend/src/client/services/TeamsService.ts index 4fe9504d..b3a6f349 100644 --- a/frontend/src/client/services/TeamsService.ts +++ b/frontend/src/client/services/TeamsService.ts @@ -42,7 +42,7 @@ export class TeamsService { /** * Create Team - * Create new team. + * Create new team and it's team leader * @returns TeamOut Successful Response * @throws ApiError */ From de52420dce6a36e1260bbe865bb4b881b3ad1ac5 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Thu, 18 Apr 2024 23:48:42 +0800 Subject: [PATCH 12/21] Fix member endpoint urls --- backend/app/api/main.py | 2 +- backend/app/api/routes/members.py | 4 +- .../src/client/services/MembersService.ts | 40 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/backend/app/api/main.py b/backend/app/api/main.py index b3e9b047..6ba032c5 100644 --- a/backend/app/api/main.py +++ b/backend/app/api/main.py @@ -8,4 +8,4 @@ api_router.include_router(utils.router, prefix="/utils", tags=["utils"]) api_router.include_router(items.router, prefix="/items", tags=["items"]) api_router.include_router(teams.router, prefix="/teams", tags=["teams"]) -api_router.include_router(members.router, prefix="/teams/{team_id}", tags=["members"]) +api_router.include_router(members.router, prefix="/teams/{team_id}/members", tags=["members"]) diff --git a/backend/app/api/routes/members.py b/backend/app/api/routes/members.py index 5af0e9fc..41b60ea5 100644 --- a/backend/app/api/routes/members.py +++ b/backend/app/api/routes/members.py @@ -9,7 +9,7 @@ router = APIRouter() -@router.get("/members", response_model=MembersOut) +@router.get("/", response_model=MembersOut) def read_members( session: SessionDep, current_user: CurrentUser, team_id: int, skip: int = 0, limit: int = 100 ) -> Any: @@ -42,7 +42,7 @@ def read_members( return MembersOut(data=members, count=count) -@router.get("/members/{id}", response_model=MemberOut) +@router.get("/{id}", response_model=MemberOut) def read_member(session: SessionDep, current_user: CurrentUser, team_id: int, id: int) -> Any: """ Get member by ID. diff --git a/frontend/src/client/services/MembersService.ts b/frontend/src/client/services/MembersService.ts index 1159a854..c8394efb 100644 --- a/frontend/src/client/services/MembersService.ts +++ b/frontend/src/client/services/MembersService.ts @@ -31,7 +31,7 @@ export class MembersService { }): CancelablePromise { return __request(OpenAPI, { method: 'GET', - url: '/api/v1/teams/{team_id}/members', + url: '/api/v1/teams/{team_id}/members/', path: { 'team_id': teamId, }, @@ -46,25 +46,26 @@ export class MembersService { } /** - * Read Member - * Get member by ID. + * Create Member + * Create new member. * @returns MemberOut Successful Response * @throws ApiError */ - public static readMember({ + public static createMember({ teamId, - id, + requestBody, }: { teamId: number, - id: number, + requestBody: MemberCreate, }): CancelablePromise { return __request(OpenAPI, { - method: 'GET', - url: '/api/v1/teams/{team_id}/members/{id}', + method: 'POST', + url: '/api/v1/teams/{team_id}/members/', path: { 'team_id': teamId, - 'id': id, }, + body: requestBody, + mediaType: 'application/json', errors: { 422: `Validation Error`, }, @@ -72,26 +73,25 @@ export class MembersService { } /** - * Create Member - * Create new member. + * Read Member + * Get member by ID. * @returns MemberOut Successful Response * @throws ApiError */ - public static createMember({ + public static readMember({ teamId, - requestBody, + id, }: { teamId: number, - requestBody: MemberCreate, + id: number, }): CancelablePromise { return __request(OpenAPI, { - method: 'POST', - url: '/api/v1/teams/{team_id}/', + method: 'GET', + url: '/api/v1/teams/{team_id}/members/{id}', path: { 'team_id': teamId, + 'id': id, }, - body: requestBody, - mediaType: 'application/json', errors: { 422: `Validation Error`, }, @@ -115,7 +115,7 @@ export class MembersService { }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', - url: '/api/v1/teams/{team_id}/{id}', + url: '/api/v1/teams/{team_id}/members/{id}', path: { 'team_id': teamId, 'id': id, @@ -143,7 +143,7 @@ export class MembersService { }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', - url: '/api/v1/teams/{team_id}/{id}', + url: '/api/v1/teams/{team_id}/members/{id}', path: { 'team_id': teamId, 'id': id, From f5ff4c98b7bbe33753928829546473213bfc2343 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Fri, 19 Apr 2024 22:21:35 +0800 Subject: [PATCH 13/21] backend: Create root member when creating team --- backend/app/api/routes/teams.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/app/api/routes/teams.py b/backend/app/api/routes/teams.py index 673f4ce3..460e0f8d 100644 --- a/backend/app/api/routes/teams.py +++ b/backend/app/api/routes/teams.py @@ -5,7 +5,7 @@ from app.core.graph.build import generator from app.api.deps import CurrentUser, SessionDep -from app.models import TeamChat, TeamsOut, TeamCreate, TeamUpdate, TeamOut, Team, Message +from app.models import Member, TeamChat, TeamsOut, TeamCreate, TeamUpdate, TeamOut, Team, Message # TODO: To remove teams = { @@ -97,12 +97,17 @@ def create_team( *, session: SessionDep, current_user: CurrentUser, team_in: TeamCreate ) -> Any: """ - Create new team. + Create new team and it's team leader """ team = Team.model_validate(team_in, update={"owner_id": current_user.id}) session.add(team) session.commit() - session.refresh(team) + + # Create team leader + member= Member(**{'name': 'Team Leader', 'type': 'root', 'role': 'Gather inputs from your team and answer the question.', 'owner_of': team.id, 'position_x': 0, 'position_y': 0, "belongs_to": team.id}) + session.add(member) + session.commit() + return team @router.put("/{id}", response_model=TeamOut) From 8b1fa757cd27184bb4c48c7b41a55a265a728313 Mon Sep 17 00:00:00 2001 From: StreetLamb Date: Fri, 19 Apr 2024 22:25:51 +0800 Subject: [PATCH 14/21] frontend: Add team page to create, update and delete team members via reactflow --- frontend/package-lock.json | 1037 ++++++++++++++++- frontend/package.json | 2 + .../src/components/Members/EditMember.tsx | 172 +++ frontend/src/components/ReactFlow/Flow.tsx | 323 +++++ .../components/ReactFlow/Nodes/MemberNode.tsx | 65 ++ .../components/ReactFlow/Nodes/RootNode.tsx | 58 + .../src/components/ReactFlow/Nodes/index.ts | 10 + frontend/src/routes/_layout/teams.$teamId.tsx | 4 +- frontend/src/routes/_layout/teams.index.tsx | 1 - 9 files changed, 1660 insertions(+), 12 deletions(-) create mode 100644 frontend/src/components/Members/EditMember.tsx create mode 100644 frontend/src/components/ReactFlow/Flow.tsx create mode 100644 frontend/src/components/ReactFlow/Nodes/MemberNode.tsx create mode 100644 frontend/src/components/ReactFlow/Nodes/RootNode.tsx create mode 100644 frontend/src/components/ReactFlow/Nodes/index.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1a59e7c4..c0c29833 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,6 +14,7 @@ "@emotion/styled": "11.11.0", "@tanstack/react-router": "1.19.1", "axios": "1.6.2", + "chakra-react-select": "^4.7.6", "form-data": "4.0.0", "framer-motion": "10.16.16", "react": "^18.2.0", @@ -21,6 +22,7 @@ "react-hook-form": "7.49.3", "react-icons": "5.0.1", "react-query": "3.39.3", + "reactflow": "^11.11.1", "zustand": "4.5.0" }, "devDependencies": { @@ -2072,6 +2074,28 @@ "node": ">=12" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -2087,6 +2111,102 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@reactflow/background": { + "version": "11.3.11", + "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.11.tgz", + "integrity": "sha512-27ahQyHuX2YTc1lABvAPpd5JWBH5P3qTHLGOO+Qfqq4mbicwQ0UGQ2bVDWDwoHOyep2EuMuphrLttaMr0hiviw==", + "dependencies": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/controls": { + "version": "11.2.11", + "resolved": "https://registry.npmjs.org/@reactflow/controls/-/controls-11.2.11.tgz", + "integrity": "sha512-FyqQv5pWEc2ycEGgIaLPmD5ezW3chsNwqMCjBMETxRj45R4uy6j+gDNi5EgURCan7T12uvoFeQopSZ96JL8XDQ==", + "dependencies": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/core": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@reactflow/core/-/core-11.11.1.tgz", + "integrity": "sha512-O9f/q9SZ+29am/XdoZgm/LTdkgQdypcVj9a1yZZgcS6rVDkij1yIiOT3nkGxwnNkJz0rwCn2xtL5SkK038AQ7w==", + "dependencies": { + "@types/d3": "^7.4.0", + "@types/d3-drag": "^3.0.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/minimap": { + "version": "11.7.11", + "resolved": "https://registry.npmjs.org/@reactflow/minimap/-/minimap-11.7.11.tgz", + "integrity": "sha512-zXxv+IExvWuaZ+gmRIfmU09A+slG9rMKTVfjqd+ewFV4LFcCyMNMIx3gZybdLZtgUDKIOoU/hAWIY+FbU7GTKw==", + "dependencies": { + "@reactflow/core": "11.11.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-resizer": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.2.11.tgz", + "integrity": "sha512-g/5iLo5vPBoFozU+2WXub+mbpNkQhR+PRX9o0YvH/lYs1pS7JYFSzCOHdHpLHAImoCGrKY1XN5scYly36jWkDw==", + "dependencies": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-toolbar": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@reactflow/node-toolbar/-/node-toolbar-1.3.11.tgz", + "integrity": "sha512-PKcTrtC88WZjNQz4ACnPgbNDBprsLJVDxyV1x8drGMNRePPrErkUNxsbhrr49L8ffmIavd4kxW5XVNOx8Kswmw==", + "dependencies": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz", @@ -2552,6 +2672,233 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.9.tgz", + "integrity": "sha512-IKtvyFdb4Q0LWna6ymywQsEYjK/94SGhPrMfEr1TIc5OBeziTi+1jcCvttts8e0UWZIxpasjnQk9MNk/3iS+kA==" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2588,14 +2935,12 @@ "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "devOptional": true + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { "version": "18.2.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2611,11 +2956,18 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "devOptional": true + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" }, "node_modules/@vitejs/plugin-react-swc": { "version": "3.5.0", @@ -2756,6 +3108,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/chakra-react-select": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/chakra-react-select/-/chakra-react-select-4.7.6.tgz", + "integrity": "sha512-ZL43hyXPnWf1g/HjsZDecbeJ4F2Q6tTPYJozlKWkrQ7lIX7ORP0aZYwmc5/Wly4UNzMimj2Vuosl6MmIXH+G2g==", + "dependencies": { + "react-select": "5.7.7" + }, + "peerDependencies": { + "@chakra-ui/form-control": "^2.0.0", + "@chakra-ui/icon": "^3.0.0", + "@chakra-ui/layout": "^2.0.0", + "@chakra-ui/media-query": "^3.0.0", + "@chakra-ui/menu": "^2.0.0", + "@chakra-ui/spinner": "^2.0.0", + "@chakra-ui/system": "^2.0.0", + "@emotion/react": "^11.8.1", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" + }, "node_modules/clsx": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", @@ -2841,6 +3218,102 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -2875,6 +3348,15 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3288,6 +3770,11 @@ "remove-accents": "0.5.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/microseconds": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", @@ -3674,6 +4161,26 @@ } } }, + "node_modules/react-select": { + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.7.tgz", + "integrity": "sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -3696,6 +4203,38 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/reactflow": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.11.1.tgz", + "integrity": "sha512-2GEh0bTkYR7rzAV3qdeN6C1o4qumtETZl7yQv1GVrfgr3c77nCUAOKsv5hetRejOGNnJudRwn6axeWFAY+IjNg==", + "dependencies": { + "@reactflow/background": "11.3.11", + "@reactflow/controls": "11.2.11", + "@reactflow/core": "11.11.1", + "@reactflow/minimap": "11.7.11", + "@reactflow/node-resizer": "2.2.11", + "@reactflow/node-toolbar": "1.3.11" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -3912,6 +4451,19 @@ } } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", @@ -5463,6 +6015,28 @@ "dev": true, "optional": true }, + "@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "requires": { + "@floating-ui/utils": "^0.2.1" + } + }, + "@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "requires": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -5474,6 +6048,78 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, + "@reactflow/background": { + "version": "11.3.11", + "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.11.tgz", + "integrity": "sha512-27ahQyHuX2YTc1lABvAPpd5JWBH5P3qTHLGOO+Qfqq4mbicwQ0UGQ2bVDWDwoHOyep2EuMuphrLttaMr0hiviw==", + "requires": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + } + }, + "@reactflow/controls": { + "version": "11.2.11", + "resolved": "https://registry.npmjs.org/@reactflow/controls/-/controls-11.2.11.tgz", + "integrity": "sha512-FyqQv5pWEc2ycEGgIaLPmD5ezW3chsNwqMCjBMETxRj45R4uy6j+gDNi5EgURCan7T12uvoFeQopSZ96JL8XDQ==", + "requires": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + } + }, + "@reactflow/core": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@reactflow/core/-/core-11.11.1.tgz", + "integrity": "sha512-O9f/q9SZ+29am/XdoZgm/LTdkgQdypcVj9a1yZZgcS6rVDkij1yIiOT3nkGxwnNkJz0rwCn2xtL5SkK038AQ7w==", + "requires": { + "@types/d3": "^7.4.0", + "@types/d3-drag": "^3.0.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + } + }, + "@reactflow/minimap": { + "version": "11.7.11", + "resolved": "https://registry.npmjs.org/@reactflow/minimap/-/minimap-11.7.11.tgz", + "integrity": "sha512-zXxv+IExvWuaZ+gmRIfmU09A+slG9rMKTVfjqd+ewFV4LFcCyMNMIx3gZybdLZtgUDKIOoU/hAWIY+FbU7GTKw==", + "requires": { + "@reactflow/core": "11.11.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + } + }, + "@reactflow/node-resizer": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.2.11.tgz", + "integrity": "sha512-g/5iLo5vPBoFozU+2WXub+mbpNkQhR+PRX9o0YvH/lYs1pS7JYFSzCOHdHpLHAImoCGrKY1XN5scYly36jWkDw==", + "requires": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.4.1" + } + }, + "@reactflow/node-toolbar": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@reactflow/node-toolbar/-/node-toolbar-1.3.11.tgz", + "integrity": "sha512-PKcTrtC88WZjNQz4ACnPgbNDBprsLJVDxyV1x8drGMNRePPrErkUNxsbhrr49L8ffmIavd4kxW5XVNOx8Kswmw==", + "requires": { + "@reactflow/core": "11.11.1", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + } + }, "@rollup/rollup-android-arm-eabi": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz", @@ -5713,6 +6359,233 @@ "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.1.3.tgz", "integrity": "sha512-GnolmC8Fr4mvsHE1fGQmR3Nm0eBO3KnZjDU0a+P3TeQNM/dDscFGxtA7p31NplQNW3KwBw4t1RVFmz0VeKLxcw==" }, + "@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "requires": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" + }, + "@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "requires": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" + }, + "@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==" + }, + "@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==" + }, + "@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "requires": { + "@types/d3-dsv": "*" + } + }, + "@types/d3-force": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.9.tgz", + "integrity": "sha512-IKtvyFdb4Q0LWna6ymywQsEYjK/94SGhPrMfEr1TIc5OBeziTi+1jcCvttts8e0UWZIxpasjnQk9MNk/3iS+kA==" + }, + "@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==" + }, + "@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "requires": { + "@types/geojson": "*" + } + }, + "@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==" + }, + "@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "requires": { + "@types/d3-color": "*" + } + }, + "@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==" + }, + "@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==" + }, + "@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==" + }, + "@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "requires": { + "@types/d3-time": "*" + } + }, + "@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + }, + "@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + }, + "@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "requires": { + "@types/d3-path": "*" + } + }, + "@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==" + }, + "@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, + "@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "requires": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, "@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -5749,14 +6622,12 @@ "@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "devOptional": true + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "@types/react": { "version": "18.2.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", - "devOptional": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -5772,11 +6643,18 @@ "@types/react": "*" } }, + "@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "devOptional": true + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" }, "@vitejs/plugin-react-swc": { "version": "3.5.0", @@ -5895,6 +6773,19 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, + "chakra-react-select": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/chakra-react-select/-/chakra-react-select-4.7.6.tgz", + "integrity": "sha512-ZL43hyXPnWf1g/HjsZDecbeJ4F2Q6tTPYJozlKWkrQ7lIX7ORP0aZYwmc5/Wly4UNzMimj2Vuosl6MmIXH+G2g==", + "requires": { + "react-select": "5.7.7" + } + }, + "classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" + }, "clsx": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", @@ -5968,6 +6859,72 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, "date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -5992,6 +6949,15 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6306,6 +7272,11 @@ "remove-accents": "0.5.0" } }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "microseconds": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", @@ -6552,6 +7523,22 @@ "tslib": "^2.0.0" } }, + "react-select": { + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.7.tgz", + "integrity": "sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + } + }, "react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -6562,6 +7549,30 @@ "tslib": "^2.0.0" } }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "reactflow": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.11.1.tgz", + "integrity": "sha512-2GEh0bTkYR7rzAV3qdeN6C1o4qumtETZl7yQv1GVrfgr3c77nCUAOKsv5hetRejOGNnJudRwn6axeWFAY+IjNg==", + "requires": { + "@reactflow/background": "11.3.11", + "@reactflow/controls": "11.2.11", + "@reactflow/core": "11.11.1", + "@reactflow/minimap": "11.7.11", + "@reactflow/node-resizer": "2.2.11", + "@reactflow/node-toolbar": "1.3.11" + } + }, "regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -6713,6 +7724,12 @@ "tslib": "^2.0.0" } }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, "use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index a1ac410a..8f474a4f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,7 @@ "@emotion/styled": "11.11.0", "@tanstack/react-router": "1.19.1", "axios": "1.6.2", + "chakra-react-select": "^4.7.6", "form-data": "4.0.0", "framer-motion": "10.16.16", "react": "^18.2.0", @@ -24,6 +25,7 @@ "react-hook-form": "7.49.3", "react-icons": "5.0.1", "react-query": "3.39.3", + "reactflow": "^11.11.1", "zustand": "4.5.0" }, "devDependencies": { diff --git a/frontend/src/components/Members/EditMember.tsx b/frontend/src/components/Members/EditMember.tsx new file mode 100644 index 00000000..973ef8f0 --- /dev/null +++ b/frontend/src/components/Members/EditMember.tsx @@ -0,0 +1,172 @@ +import { + Button, + FormControl, + FormErrorMessage, + FormLabel, + Input, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Select, + Textarea, +} from "@chakra-ui/react" +import useCustomToast from "../../hooks/useCustomToast" +import { useMutation, useQueryClient } from "react-query" +import { + type ApiError, + MembersService, + type TeamUpdate, + type MemberOut, + type MemberUpdate, +} from "../../client" +import { type SubmitHandler, useForm } from "react-hook-form" + +interface EditMemberProps { + member: MemberOut + teamId: number + isOpen: boolean + onClose: () => void +} + +export function EditMember({ + member, + teamId, + isOpen, + onClose, +}: EditMemberProps) { + const queryClient = useQueryClient() + const showToast = useCustomToast() + const { + register, + handleSubmit, + reset, + formState: { isSubmitting, errors, isDirty }, + } = useForm({ + mode: "onBlur", + criteriaMode: "all", + values: member, + }) + + const updateMember = async (data: MemberUpdate) => { + await MembersService.updateMember({ + id: member.id, + teamId: teamId, + requestBody: data, + }) + } + + const mutation = useMutation(updateMember, { + onSuccess: () => { + showToast("Success!", "Team updated successfully.", "success") + onClose() + }, + onError: (err: ApiError) => { + const errDetail = err.body?.detail + showToast("Something went wrong.", `${errDetail}`, "error") + }, + onSettled: () => { + queryClient.invalidateQueries(`teams/${teamId}/members`) + }, + }) + + const onSubmit: SubmitHandler = async (data) => { + mutation.mutate(data) + } + + const onCancel = () => { + reset() + onClose() + } + + return ( + + + + Update Team Member + + + + Type + + + + Name + + {errors.name && ( + {errors.name.message} + )} + + + Role + + {errors.role && ( + {errors.role.message} + )} + + + Backstory +