Skip to content

Commit 7ad6724

Browse files
committed
plugin: add noTasksMessage support
1 parent 838766a commit 7ad6724

File tree

6 files changed

+78
-3
lines changed

6 files changed

+78
-3
lines changed

plugin/src/query/parser.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ describe("parseQuery - rejections", () => {
108108
show: "nonee",
109109
},
110110
},
111+
{
112+
description: "view.noTasksMessage must be string",
113+
input: {
114+
filter: "bar",
115+
view: { noTasksMessage: 123 },
116+
},
117+
},
111118
];
112119

113120
for (const tc of testcases) {
@@ -135,6 +142,7 @@ function makeQuery(opts?: Partial<Query>): Query {
135142
ShowMetadataVariant.Deadline,
136143
]),
137144
groupBy: opts?.groupBy ?? GroupVariant.None,
145+
view: opts?.view ?? {},
138146
};
139147
}
140148

@@ -291,6 +299,27 @@ describe("parseQuery", () => {
291299
show: new Set([ShowMetadataVariant.Section, ShowMetadataVariant.Project]),
292300
}),
293301
},
302+
{
303+
description: "with custom view.noTasksMessage",
304+
input: {
305+
filter: "bar",
306+
view: { noTasksMessage: "All caught up!" },
307+
},
308+
expectedOutput: makeQuery({
309+
filter: "bar",
310+
view: { noTasksMessage: "All caught up!" },
311+
}),
312+
},
313+
{
314+
description: "without view defaults to empty object",
315+
input: {
316+
filter: "bar",
317+
},
318+
expectedOutput: makeQuery({
319+
filter: "bar",
320+
view: {},
321+
}),
322+
},
294323
];
295324

296325
for (const tc of testcases) {
@@ -352,6 +381,17 @@ describe("parseQuery - warnings", () => {
352381
"Both 'project' and 'section' show options are set. The 'section' option will be ignored when 'project' is present.",
353382
],
354383
},
384+
{
385+
description: "Unknown nested key in view",
386+
input: {
387+
filter: "bar",
388+
view: { unknownProp: "value" },
389+
},
390+
expectedWarnings: [
391+
"This query is written using JSON. This is deprecated and will be removed in a future version. Please use YAML instead.",
392+
"Found unexpected query key 'view.unknownProp'. Is this a typo?",
393+
],
394+
},
355395
];
356396

357397
for (const tc of testcases) {

plugin/src/query/parser.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ const groupBySchema = lookupToEnum({
120120
labels: GroupVariant.Label,
121121
});
122122

123+
const viewSchema = z
124+
.object({
125+
noTasksMessage: z.string().optional(),
126+
})
127+
.optional()
128+
.default({});
129+
123130
const defaults = {
124131
name: "",
125132
autorefresh: 0,
@@ -132,6 +139,7 @@ const defaults = {
132139
ShowMetadataVariant.Deadline,
133140
],
134141
groupBy: GroupVariant.None,
142+
view: {},
135143
};
136144

137145
const querySchema = z.object({
@@ -147,16 +155,30 @@ const querySchema = z.object({
147155
.optional()
148156
.transform((val) => val ?? defaults.show),
149157
groupBy: groupBySchema.optional().transform((val) => val ?? defaults.groupBy),
158+
view: viewSchema,
150159
});
151160

152161
const validQueryKeys: string[] = querySchema.keyof().options;
162+
const validNestedKeys: Record<string, string[]> = {
163+
view: ["noTasksMessage"],
164+
};
153165

154166
function parseObjectZod(query: Record<string, unknown>): [Query, QueryWarning[]] {
155167
const warnings: QueryWarning[] = [];
156168

157169
for (const key of Object.keys(query)) {
158170
if (!validQueryKeys.includes(key)) {
159171
warnings.push(t().query.warning.unknownKey(key));
172+
} else if (validNestedKeys[key]) {
173+
// Validate nested keys
174+
const nestedObj = query[key];
175+
if (typeof nestedObj === "object" && nestedObj !== null) {
176+
for (const nestedKey of Object.keys(nestedObj)) {
177+
if (!validNestedKeys[key].includes(nestedKey)) {
178+
warnings.push(t().query.warning.unknownKey(`${key}.${nestedKey}`));
179+
}
180+
}
181+
}
160182
}
161183
}
162184

@@ -184,6 +206,7 @@ function parseObjectZod(query: Record<string, unknown>): [Query, QueryWarning[]]
184206
sorting: out.data.sorting,
185207
show,
186208
groupBy: out.data.groupBy,
209+
view: out.data.view,
187210
},
188211
warnings,
189212
];

plugin/src/query/query.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,16 @@ export enum GroupVariant {
2929
Label = 5,
3030
}
3131

32+
export type ViewOptions = {
33+
noTasksMessage?: string;
34+
};
35+
3236
export type Query = {
3337
name: string;
3438
filter: string;
3539
autorefresh: number;
3640
sorting: SortingVariant[];
3741
show: Set<ShowMetadataVariant>;
3842
groupBy: GroupVariant;
43+
view: ViewOptions;
3944
};

plugin/src/query/replacements.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe("applyReplacements", () => {
5858
groupBy: GroupVariant.None,
5959
sorting: [],
6060
show: new Set(),
61+
view: {},
6162
};
6263

6364
applyReplacements(query, new FakeContext(tc.filePath ?? ""));

plugin/src/ui/query/QueryRoot.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ const QueryResponseHandler: React.FC<{
151151

152152
const tasks = result.tasks;
153153
if (tasks.length === 0) {
154-
return <Displays.Empty />;
154+
return <Displays.Empty message={query.view.noTasksMessage} />;
155155
}
156156

157157
if (query.groupBy !== GroupVariant.None) {

plugin/src/ui/query/displays/EmptyDisplay.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import type React from "react";
33
import { t } from "@/i18n";
44
import { Callout } from "@/ui/components/callout";
55

6-
export const EmptyDisplay: React.FC = () => {
6+
type Props = {
7+
message?: string;
8+
};
9+
10+
export const EmptyDisplay: React.FC<Props> = ({ message }) => {
711
const i18n = t().query.displays.empty;
8-
return <Callout className="todoist-no-tasks" title={i18n.label} iconId="info" />;
12+
const displayMessage = message ?? i18n.label;
13+
14+
return <Callout className="todoist-no-tasks" title={displayMessage} iconId="info" />;
915
};

0 commit comments

Comments
 (0)