@@ -203,11 +312,134 @@ export function TelegramGroupsPage({ loadedGroups }: { loadedGroups: TgGroup[] }
count={filteredCount}
total={groups.length}
searchPlaceholder="Search by group name or tag…"
- onSearch={(value) => {
- table.setGlobalFilter(value)
- table.setPageIndex(0)
- }}
- />
+ onSearch={(value) => updateFilter({ text: value })}
+ >
+
+
+
+ Labels
+ {activeLabelFilterCount > 0 && (
+
+ {activeLabelFilterCount}
+
+ )}
+
+ }
+ />
+
+
+ Filter by label
+ Show groups that must, or must not, have specific labels.
+
+ {loadedGroupLabels.length ? (
+ <>
+
+
Must have
+
!filter.excludedLabels.some((excluded) => isSameGroupLabel(excluded, label))
+ )}
+ multiple
+ value={filter.requiredLabels}
+ onValueChange={(labels) => updateFilter({ requiredLabels: labels })}
+ itemToStringLabel={(label) => label.label}
+ isItemEqualToValue={isSameGroupLabel}
+ >
+
+
+
+ {(value: TgGroupLabel[]) =>
+ value.map((label) => (
+
+
+ {label.label}
+
+
+ ))
+ }
+
+
+
+
+
+ No matching labels
+
+ {(label: TgGroupLabel) => (
+
+
+ {label.label}
+
+ )}
+
+
+
+
+
+
Must not have
+
!filter.requiredLabels.some((required) => isSameGroupLabel(required, label))
+ )}
+ multiple
+ value={filter.excludedLabels}
+ onValueChange={(labels) => updateFilter({ excludedLabels: labels })}
+ itemToStringLabel={(label) => label.label}
+ isItemEqualToValue={isSameGroupLabel}
+ >
+
+
+
+ {(value: TgGroupLabel[]) =>
+ value.map((label) => (
+
+
+ {label.label}
+
+
+ ))
+ }
+
+
+
+
+
+ No matching labels
+
+ {(label: TgGroupLabel) => (
+
+
+ {label.label}
+
+ )}
+
+
+
+
+ {activeLabelFilterCount > 0 && (
+
+ )}
+ >
+ ) : (
+ No labels have been created yet.
+ )}
+
+
+
{mutationError && (
{mutationError}
@@ -244,7 +476,19 @@ export function TelegramGroupsPage({ loadedGroups }: { loadedGroups: TgGroup[] }
{table.getRowModel().rows.map((row) => (
-
+ setEditingGroup(row.original)}
+ onKeyDown={(event) => {
+ if (event.key === "Enter" || event.key === " ") {
+ event.preventDefault()
+ setEditingGroup(row.original)
+ }
+ }}
+ >
{row.getAllCells().map((cell) => (
@@ -267,12 +511,24 @@ export function TelegramGroupsPage({ loadedGroups }: { loadedGroups: TgGroup[] }
) : (
)}
+ setEditingGroup(null)}
+ onSaved={async () => {
+ try {
+ await router.invalidate({ sync: true })
+ } catch (error) {
+ console.error(error)
+ toast.warning("The labels were saved, but the group list could not be refreshed.")
+ }
+ }}
+ />
)
}
diff --git a/src/features/telegram/groups.functions.ts b/src/features/telegram/groups.functions.ts
index c32a6b6..79046a0 100644
--- a/src/features/telegram/groups.functions.ts
+++ b/src/features/telegram/groups.functions.ts
@@ -7,6 +7,14 @@ export const getTelegramGroups = createServerFn()
.middleware([adminMiddleware])
.handler(({ context }) => context.backend.tg.groups.getAll.query())
+export const getGroupLabels = createServerFn()
+ .middleware([adminMiddleware])
+ .handler(({ context }) => context.backend.tg.groupLabels.getAll.query())
+
+export const getGroupLabelRelations = createServerFn()
+ .middleware([adminMiddleware])
+ .handler(({ context }) => context.backend.tg.groupLabels.getAllRelations.query())
+
export const setGroupVisibility = createServerFn({ method: "POST" })
.middleware([writeAdminMiddleware])
.validator(z.object({ telegramId: z.number().int(), hide: z.boolean() }))
@@ -22,3 +30,15 @@ export const leaveTelegramGroup = createServerFn({ method: "POST" })
.handler(({ data, context }) =>
context.backend.tg.groups.leaveChat.mutate({ chatId: data.chatId, performerId: context.telegramId })
)
+
+const groupLabelTagInput = z.object({ groupId: z.number().int(), label: z.string().min(1).max(128) })
+
+export const tagTelegramGroup = createServerFn({ method: "POST" })
+ .middleware([writeAdminMiddleware])
+ .validator(groupLabelTagInput)
+ .handler(({ data, context }) => context.backend.tg.groupLabels.tagGroup.mutate(data))
+
+export const untagTelegramGroup = createServerFn({ method: "POST" })
+ .middleware([writeAdminMiddleware])
+ .validator(groupLabelTagInput)
+ .handler(({ data, context }) => context.backend.tg.groupLabels.untagGroup.mutate(data))
diff --git a/src/lib/api/types.ts b/src/lib/api/types.ts
index 5769fc2..0af7a75 100644
--- a/src/lib/api/types.ts
+++ b/src/lib/api/types.ts
@@ -8,6 +8,8 @@ export type ApiError = inferRouterError