Skip to content

Commit 6ddeadf

Browse files
committed
feat: allow setting show to none to hide all metadata
1 parent 2a66fd8 commit 6ddeadf

File tree

4 files changed

+60
-13
lines changed

4 files changed

+60
-13
lines changed

plugin/src/query/parser.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ describe("parseQuery - rejections", () => {
9999
show: ["foo", "bar"],
100100
},
101101
},
102+
{
103+
description: "show must be 'none' literal",
104+
input: {
105+
name: "foo",
106+
filter: "bar",
107+
show: "nonee",
108+
},
109+
},
102110
];
103111

104112
for (const tc of testcases) {
@@ -200,6 +208,17 @@ describe("parseQuery", () => {
200208
show: new Set([ShowMetadataVariant.Due, ShowMetadataVariant.Project]),
201209
}),
202210
},
211+
{
212+
description: "with show = none",
213+
input: {
214+
filter: "bar",
215+
show: "none",
216+
},
217+
expectedOutput: makeQuery({
218+
filter: "bar",
219+
show: new Set(),
220+
}),
221+
},
203222
];
204223

205224
for (const tc of testcases) {

plugin/src/query/parser.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { GroupVariant, type Query, ShowMetadataVariant, SortingVariant } from "@
33
import YAML from "yaml";
44
import { z } from "zod";
55

6+
type ErrorTree = string | { msg: string; children: ErrorTree[] };
7+
68
export class ParsingError extends Error {
7-
messages: string[];
9+
messages: ErrorTree[];
810
inner: unknown | undefined;
911

10-
constructor(msgs: string[], inner: unknown | undefined = undefined) {
12+
constructor(msgs: ErrorTree[], inner: unknown | undefined = undefined) {
1113
super(msgs.join("\n"));
1214
this.inner = inner;
1315
this.messages = msgs;
@@ -123,7 +125,7 @@ const querySchema = z.object({
123125
.optional()
124126
.transform((val) => val ?? defaults.sorting),
125127
show: z
126-
.array(showSchema)
128+
.union([z.array(showSchema), z.literal("none").transform(() => [])])
127129
.optional()
128130
.transform((val) => val ?? defaults.show),
129131
groupBy: groupBySchema.optional().transform((val) => val ?? defaults.groupBy),
@@ -159,16 +161,27 @@ function parseObjectZod(query: Record<string, unknown>): [Query, QueryWarning[]]
159161
];
160162
}
161163

162-
function formatZodError(error: z.ZodError): string[] {
164+
function formatZodError(error: z.ZodError): ErrorTree[] {
163165
return error.errors.map((err) => {
164-
const field = err.path[0];
166+
const field = formatPath(err.path);
165167
switch (err.code) {
166168
case "invalid_type":
167169
return `Field '${field}' is ${err.received === "undefined" ? "required" : `must be a ${err.expected}`}`;
168170
case "invalid_enum_value":
169171
return `Field '${field}' has invalid value '${err.received}'. Valid options are: ${err.options?.join(", ")}`;
172+
case "invalid_union":
173+
return {
174+
msg: "One of the following rules must be met:",
175+
children: err.unionErrors.flatMap(formatZodError),
176+
};
177+
case "invalid_literal":
178+
return `Field '${field}' has invalid value '${err.received}', must be exactly '${err.expected}'`;
170179
default:
171180
return `Field '${field}': ${err.message}`;
172181
}
173182
});
174183
}
184+
185+
function formatPath(path: (string | number)[]): string {
186+
return path.map((p) => (typeof p === "number" ? `[${p}]` : p)).join(".");
187+
}

plugin/src/ui/components/callout/index.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,28 @@ import classNames from "classnames";
33
import type React from "react";
44
import "./styles.scss";
55

6+
export type Contents = string | { msg: string; children: Contents[] };
7+
68
type Props = {
79
title: string;
810
className: string;
911
iconId: string;
10-
contents?: string[];
12+
contents?: Contents[];
13+
};
14+
15+
const renderContents = (content: Contents): React.ReactNode => {
16+
if (typeof content === "string") {
17+
return <li key={content}>{content}</li>;
18+
}
19+
20+
return (
21+
<li key={content.msg}>
22+
{content.msg}
23+
{content.children && content.children.length > 0 && (
24+
<ul>{content.children.map((child) => renderContents(child))}</ul>
25+
)}
26+
</li>
27+
);
1128
};
1229

1330
export const Callout: React.FC<Props> = ({ title, contents, iconId, className }) => {
@@ -18,11 +35,7 @@ export const Callout: React.FC<Props> = ({ title, contents, iconId, className })
1835
<span>{title}</span>
1936
</div>
2037
{contents && (
21-
<ul className="callout-contents">
22-
{contents.map((content) => (
23-
<li key={content}>{content}</li>
24-
))}
25-
</ul>
38+
<ul className="callout-contents">{contents.map((content) => renderContents(content))}</ul>
2639
)}
2740
</div>
2841
);

plugin/src/ui/query/QueryError.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { t } from "@/i18n";
22
import { ParsingError } from "@/query/parser";
3-
import { Callout } from "@/ui/components/callout";
3+
import { Callout, type Contents } from "@/ui/components/callout";
44
import type React from "react";
55

6+
type ErrorTree = string | { msg: string; children: ErrorTree[] };
7+
68
type Props = {
79
error: unknown;
810
};
@@ -20,7 +22,7 @@ export const QueryError: React.FC<Props> = ({ error }) => {
2022
);
2123
};
2224

23-
const getErrorMessages = (error: unknown): string[] | undefined => {
25+
const getErrorMessages = (error: unknown): Contents[] | undefined => {
2426
if (error instanceof ParsingError) {
2527
return error.messages;
2628
}

0 commit comments

Comments
 (0)