From 1a40f6235626eb63e80747e94608aa16963129cf Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 12 Jul 2026 16:19:47 +0200 Subject: [PATCH 1/3] feat: optimize member management by improving member addition and null checks --- .../ce/src/member/services/Member.service.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/packages/ce/src/member/services/Member.service.ts b/src/packages/ce/src/member/services/Member.service.ts index 4a9f7aa4..1ff4d0ec 100644 --- a/src/packages/ce/src/member/services/Member.service.ts +++ b/src/packages/ce/src/member/services/Member.service.ts @@ -27,7 +27,6 @@ export type MemberDependencies = { export class MemberService extends ReactiveArrayService { private readonly client: GraphqlClient - private i = 0 constructor(client: GraphqlClient, store: ReactiveArrayStore>) { super(store) @@ -55,7 +54,7 @@ export class MemberService extends ReactiveArrayService { if (member && !this.hasById(member.id)) { - this.set(this.i++, new View(member)) + this.add(new View(member)) } }) }) @@ -65,7 +64,7 @@ export class MemberService extends ReactiveArrayService o.id === id) + const member = super.values().find(o => o?.id === id) return member !== undefined } @@ -87,7 +86,7 @@ export class MemberService extends ReactiveArrayService m.id === payload.memberId) + const index = super.values().findIndex(m => m?.id === payload.memberId) const newMember: NamespaceMember = { ...currentMember, @@ -113,8 +112,8 @@ export class MemberService extends ReactiveArrayService m.id == member.id) - this.delete(index) + const index = super.values().findIndex(m => m?.id == member.id) + if (index >= 0) this.delete(index) } return result.data?.namespacesMembersDelete ?? undefined @@ -130,7 +129,7 @@ export class MemberService extends ReactiveArrayService { if (!this.hasById(member.id)) { - this.set(this.i++, new View(member)) + this.add(new View(member)) } }) From c744e90fa59fd45f029f822acff73d8c37ed5377 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 12 Jul 2026 16:19:54 +0200 Subject: [PATCH 2/3] feat: update member addition logic to ensure only blocked users are invited --- src/packages/ce/src/member/pages/MemberAddPage.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/packages/ce/src/member/pages/MemberAddPage.tsx b/src/packages/ce/src/member/pages/MemberAddPage.tsx index bcb8d24b..29c365ca 100644 --- a/src/packages/ce/src/member/pages/MemberAddPage.tsx +++ b/src/packages/ce/src/member/pages/MemberAddPage.tsx @@ -7,8 +7,7 @@ import {useParams, useRouter} from "next/navigation"; import {Namespace, User} from "@code0-tech/sagittarius-graphql-types"; import Link from "next/link"; import {UserService} from "@edition/user/services/User.service"; -import {InputSyntaxSegment} from "@code0-tech/pictor/dist/components/form/Input.syntax.hook"; -import {UserInputComponent} from "@edition/user/components/UserInputComponent"; +import {UserInputComponent, UserSyntaxSegment} from "@edition/user/components/UserInputComponent"; import {addIslandSuccessNotification} from "@code0-tech/pictor/dist/components/island/Island.hook"; export const MemberAddPage: React.FC = () => { @@ -32,13 +31,13 @@ export const MemberAddPage: React.FC = () => { } }, [members]) - const [inputs, validate] = useForm<{ users: null | InputSyntaxSegment[] }>({ + const [inputs, validate] = useForm<{ users: null | UserSyntaxSegment[] }>({ useInitialValidation: false, initialValues: formInitialValues, validate: { users: (value) => { if (!value) return "Please select at least one user" - if (value.length <= 0) return "Please select at least one user" + if (value.filter(segment => segment.type === "block").length <= 0) return "Please select at least one user" return null } }, @@ -47,7 +46,9 @@ export const MemberAddPage: React.FC = () => { const payload = await memberService.memberBulkInvite({ namespaceId: namespaceId!!, - userIds: values.users!!.map((value) => (value.value).id!!) + userIds: values.users!! + .filter(segment => segment.type === "block") + .map(segment => segment.valueData!!.id!!) }) if ((payload?.errors?.length ?? 0) <= 0) { From b76f5695bb9b9bcf56f95034269ba03affd69d49 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 12 Jul 2026 16:19:59 +0200 Subject: [PATCH 3/3] feat: extend UserInputComponent to include valueData in user syntax segments --- .../ce/src/user/components/UserInputComponent.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/packages/ce/src/user/components/UserInputComponent.tsx b/src/packages/ce/src/user/components/UserInputComponent.tsx index 4c63a6c4..eeb4d752 100644 --- a/src/packages/ce/src/user/components/UserInputComponent.tsx +++ b/src/packages/ce/src/user/components/UserInputComponent.tsx @@ -21,6 +21,8 @@ export interface UserInputComponentProps extends TextInputProps { filter?: (user: User, index: number) => boolean } +export type UserSyntaxSegment = InputSyntaxSegment & { valueData?: User } + export const UserInputComponent: React.FC = (props) => { const {filter = () => true, ...rest} = props @@ -43,7 +45,7 @@ export const UserInputComponent: React.FC = (props) => const transformSyntax = ( _?: string | null, appliedParts: (InputSuggestion | any)[] = [], - ): InputSyntaxSegment[] => { + ): UserSyntaxSegment[] => { let cursor = 0 @@ -51,7 +53,11 @@ export const UserInputComponent: React.FC = (props) => if (typeof part === "object") { const segment = { type: "block", - value: part.valueData, + // value must stay the raw suggestion value (username) so pictor can + // re-match the segment to its token on re-serialization; the User + // object travels alongside in valueData + value: part.value, + valueData: part.valueData, start: cursor, end: cursor + part.value.length, visualLength: 1, @@ -81,7 +87,7 @@ export const UserInputComponent: React.FC = (props) => } cursor += textString.length return {} - }) as InputSyntaxSegment[] + }) as UserSyntaxSegment[] } return