feat: add list filter to board view (#241)
* feat: add list filter to board view * feat: implement API-driven list filtering * refactor: remove unnecessary list join from card filtering queries * feat: enable list filter options for public boards * refactor(perf): move to main query --------- Co-authored-by: Henry <henry_ball@hotmail.co.uk>
This commit is contained in:
@@ -12,6 +12,7 @@ interface QueryParams {
|
||||
boardPublicId: string;
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
}
|
||||
|
||||
export function DeleteListConfirmation({
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useRouter } from "next/router";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import {
|
||||
HiMiniXMark,
|
||||
HiOutlineSquare3Stack3D,
|
||||
HiOutlineTag,
|
||||
HiOutlineUserCircle,
|
||||
} from "react-icons/hi2";
|
||||
@@ -32,15 +33,22 @@ interface Label {
|
||||
colourCode: string | null;
|
||||
}
|
||||
|
||||
interface List {
|
||||
publicId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const Filters = ({
|
||||
position = "right",
|
||||
labels,
|
||||
members,
|
||||
lists,
|
||||
isLoading,
|
||||
}: {
|
||||
position?: "left" | "right";
|
||||
labels: Label[];
|
||||
members: Member[];
|
||||
lists: List[];
|
||||
isLoading: boolean;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
@@ -52,7 +60,7 @@ const Filters = ({
|
||||
try {
|
||||
await router.push({
|
||||
pathname: router.pathname,
|
||||
query: { ...router.query, members: [], labels: [] },
|
||||
query: { ...router.query, members: [], labels: [], lists: [] },
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -85,6 +93,12 @@ const Filters = ({
|
||||
leftIcon: <LabelIcon colourCode={label.colourCode} />,
|
||||
}));
|
||||
|
||||
const formattedLists = lists.map((list) => ({
|
||||
key: list.publicId,
|
||||
value: list.name,
|
||||
selected: !!router.query.lists?.includes(list.publicId),
|
||||
}));
|
||||
|
||||
const groups = [
|
||||
...(formattedMembers.length
|
||||
? [
|
||||
@@ -102,6 +116,16 @@ const Filters = ({
|
||||
icon: <HiOutlineTag size={16} />,
|
||||
items: formattedLabels,
|
||||
},
|
||||
...(formattedLists.length
|
||||
? [
|
||||
{
|
||||
key: "lists",
|
||||
label: t`Lists`,
|
||||
icon: <HiOutlineSquare3Stack3D size={16} />,
|
||||
items: formattedLists,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -131,6 +155,7 @@ const Filters = ({
|
||||
const numOfFilters = [
|
||||
...formatToArray(router.query.members),
|
||||
...formatToArray(router.query.labels),
|
||||
...formatToArray(router.query.lists),
|
||||
].length;
|
||||
|
||||
return (
|
||||
|
||||
@@ -33,6 +33,7 @@ interface QueryParams {
|
||||
boardPublicId: string;
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
}
|
||||
|
||||
interface NewCardFormProps {
|
||||
|
||||
@@ -21,6 +21,7 @@ interface QueryParams {
|
||||
boardPublicId: string;
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
}
|
||||
|
||||
export function NewListForm({
|
||||
|
||||
@@ -17,6 +17,7 @@ interface QueryParams {
|
||||
boardPublicId: string;
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
}
|
||||
|
||||
export function UpdateBoardSlugForm({
|
||||
|
||||
@@ -11,6 +11,7 @@ interface QueryParams {
|
||||
boardPublicId: string;
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
}
|
||||
|
||||
const VisibilityButton = ({
|
||||
|
||||
@@ -80,11 +80,13 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
boardPublicId: string;
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
type: "regular" | "template";
|
||||
} = {
|
||||
boardPublicId: boardId ?? "",
|
||||
members: formatToArray(router.query.members),
|
||||
labels: formatToArray(router.query.labels),
|
||||
lists: formatToArray(router.query.lists),
|
||||
type: isTemplate ? "template" : "regular",
|
||||
};
|
||||
|
||||
@@ -418,6 +420,7 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
members={boardData.workspace.members.filter(
|
||||
(member) => member.user !== null,
|
||||
)}
|
||||
lists={boardData.allLists}
|
||||
position="left"
|
||||
isLoading={!boardData}
|
||||
/>
|
||||
|
||||
@@ -44,6 +44,7 @@ export default function PublicBoardView() {
|
||||
workspaceSlug: workspaceSlug ?? "",
|
||||
members: formatToArray(router.query.members),
|
||||
labels: formatToArray(router.query.labels),
|
||||
lists: formatToArray(router.query.lists),
|
||||
},
|
||||
{
|
||||
enabled: router.isReady && !!boardSlug,
|
||||
@@ -130,6 +131,7 @@ export default function PublicBoardView() {
|
||||
<Filters
|
||||
labels={data.labels ?? []}
|
||||
members={[]}
|
||||
lists={data.allLists ?? []}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -78,6 +78,7 @@ export const boardRouter = createTRPCRouter({
|
||||
boardPublicId: z.string().min(12),
|
||||
members: z.array(z.string().min(12)).optional(),
|
||||
labels: z.array(z.string().min(12)).optional(),
|
||||
lists: z.array(z.string().min(12)).optional(),
|
||||
type: z.enum(["regular", "template"]).optional(),
|
||||
}),
|
||||
)
|
||||
@@ -110,6 +111,7 @@ export const boardRouter = createTRPCRouter({
|
||||
{
|
||||
members: input.members ?? [],
|
||||
labels: input.labels ?? [],
|
||||
lists: input.lists ?? [],
|
||||
type: input.type,
|
||||
},
|
||||
);
|
||||
@@ -142,6 +144,7 @@ export const boardRouter = createTRPCRouter({
|
||||
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/),
|
||||
members: z.array(z.string().min(12)).optional(),
|
||||
labels: z.array(z.string().min(12)).optional(),
|
||||
lists: z.array(z.string().min(12)).optional(),
|
||||
}),
|
||||
)
|
||||
.output(z.custom<Awaited<ReturnType<typeof boardRepo.getBySlug>>>())
|
||||
@@ -164,6 +167,7 @@ export const boardRouter = createTRPCRouter({
|
||||
{
|
||||
members: input.members ?? [],
|
||||
labels: input.labels ?? [],
|
||||
lists: input.lists ?? [],
|
||||
},
|
||||
);
|
||||
|
||||
@@ -234,6 +238,7 @@ export const boardRouter = createTRPCRouter({
|
||||
{
|
||||
members: [],
|
||||
labels: [],
|
||||
lists: [],
|
||||
type: sourceBoardInfo.type,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -70,6 +70,7 @@ export const getByPublicId = async (
|
||||
filters: {
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
type: "regular" | "template" | undefined;
|
||||
},
|
||||
) => {
|
||||
@@ -231,6 +232,19 @@ export const getByPublicId = async (
|
||||
orderBy: [asc(cards.index)],
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
isNull(lists.deletedAt),
|
||||
filters.lists.length > 0
|
||||
? inArray(lists.publicId, filters.lists)
|
||||
: undefined,
|
||||
),
|
||||
orderBy: [asc(lists.index)],
|
||||
},
|
||||
allLists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
},
|
||||
where: isNull(lists.deletedAt),
|
||||
orderBy: [asc(lists.index)],
|
||||
},
|
||||
@@ -268,6 +282,7 @@ export const getBySlug = async (
|
||||
filters: {
|
||||
members: string[];
|
||||
labels: string[];
|
||||
lists: string[];
|
||||
},
|
||||
) => {
|
||||
let cardIds: string[] = [];
|
||||
@@ -379,6 +394,19 @@ export const getBySlug = async (
|
||||
orderBy: [asc(cards.index)],
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
isNull(lists.deletedAt),
|
||||
filters.lists.length > 0
|
||||
? inArray(lists.publicId, filters.lists)
|
||||
: undefined,
|
||||
),
|
||||
orderBy: [asc(lists.index)],
|
||||
},
|
||||
allLists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
},
|
||||
where: isNull(lists.deletedAt),
|
||||
orderBy: [asc(lists.index)],
|
||||
},
|
||||
|
||||
@@ -73,6 +73,7 @@ export const boardsRelations = relations(boards, ({ one, many }) => ({
|
||||
relationName: "boardCreatedByUser",
|
||||
}),
|
||||
lists: many(lists),
|
||||
allLists: many(lists),
|
||||
labels: many(labels),
|
||||
deletedBy: one(users, {
|
||||
fields: [boards.deletedBy],
|
||||
|
||||
Reference in New Issue
Block a user