Skip to content

Commit e305196

Browse files
authored
Merge pull request #3318 from obsidian-tasks-group/update-types.json
feat: Teach File Properties to recognise Tasks properties
2 parents 5a4b8c1 + 506a8b3 commit e305196

File tree

7 files changed

+153
-38
lines changed

7 files changed

+153
-38
lines changed

docs/Queries/Query File Defaults.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ To try this out:
3232
- Run the `Properties view: Show file properties` command.
3333
2. Add one or more `TQ_*` properties to the file
3434
- Click on `Add property`.
35-
- Start typing `TQ_`.
36-
- Or you can paste in property names from the [[#Supported Query File Defaults property values]] section below.
35+
- Start typing `TQ_`, or any part of the property names list in [[#Supported Query File Defaults property values]] below.
3736
- Press `<Return>` or `<Enter>` to add the property.
38-
3. Now you can modify these `TQ_*` properties to change the behaviour of Tasks searches in this file.
37+
3. Now you can modify these `TQ_*` properties to change the behaviour of all the Tasks searches in this file.
3938

4039
> [!tip]
41-
> Use the command **Tasks: Add all Query File Defaults properties** to add all the available `TQ_*` properties to the active note.
40+
> Use the command **Tasks: Add all Query File Defaults properties** to add all the available `TQ_*` properties to the active note in one simple step.
4241
4342
#### Widening property names in Obsidian
4443

@@ -118,35 +117,34 @@ These are all the types of properties currently supported by Tasks, as Query
118117
File Defaults.
119118

120119
> [!tip]
121-
> We plan to make Tasks add these types to the Obsidian vault automatically in
122-
> future.
120+
> The Tasks plugin automatically adds these properties to the Obsidian vault.
123121
122+
<!-- snippet: DocsSamplesForDefaults.test.DocsSamplesForDefaults_fake-types.json.approved.json -->
124123
```json
125124
{
126125
"types": {
127126
"TQ_explain": "checkbox",
127+
"TQ_extra_instructions": "text",
128128
"TQ_short_mode": "checkbox",
129-
"TQ_show_tree": "checkbox",
130-
"TQ_show_tags": "checkbox",
131-
"TQ_show_id": "checkbox",
132-
"TQ_show_depends_on": "checkbox",
133-
"TQ_show_priority": "checkbox",
134-
"TQ_show_recurrence_rule": "checkbox",
135-
"TQ_show_on_completion": "checkbox",
136-
"TQ_show_created_date": "checkbox",
137-
"TQ_show_start_date": "checkbox",
138-
"TQ_show_scheduled_date": "checkbox",
139-
"TQ_show_due_date": "checkbox",
129+
"TQ_show_backlink": "checkbox",
140130
"TQ_show_cancelled_date": "checkbox",
131+
"TQ_show_created_date": "checkbox",
132+
"TQ_show_depends_on": "checkbox",
141133
"TQ_show_done_date": "checkbox",
142-
"TQ_show_urgency": "checkbox",
143-
"TQ_show_backlink": "checkbox",
134+
"TQ_show_due_date": "checkbox",
144135
"TQ_show_edit_button": "checkbox",
136+
"TQ_show_id": "checkbox",
137+
"TQ_show_on_completion": "checkbox",
145138
"TQ_show_postpone_button": "checkbox",
139+
"TQ_show_priority": "checkbox",
140+
"TQ_show_recurrence_rule": "checkbox",
141+
"TQ_show_scheduled_date": "checkbox",
142+
"TQ_show_start_date": "checkbox",
143+
"TQ_show_tags": "checkbox",
146144
"TQ_show_task_count": "checkbox",
147-
"TQ_sort_by": "multitext",
148-
"TQ_group_by": "multitext",
149-
"TQ_extra_instructions": "text"
145+
"TQ_show_tree": "checkbox",
146+
"TQ_show_urgency": "checkbox"
150147
}
151148
}
152149
```
150+
<!-- endSnippet -->

resources/sample_vaults/Tasks-Demo/.obsidian/types.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,28 @@
1616
"creation date": "datetime",
1717
"project": "text",
1818
"sample_text_multiline_property": "text",
19+
"TQ_group_by": "multitext",
20+
"TQ_sort_by": "multitext",
1921
"TQ_explain": "checkbox",
22+
"TQ_extra_instructions": "text",
2023
"TQ_short_mode": "checkbox",
21-
"TQ_show_tree": "checkbox",
22-
"TQ_show_tags": "checkbox",
23-
"TQ_show_id": "checkbox",
24-
"TQ_show_depends_on": "checkbox",
25-
"TQ_show_priority": "checkbox",
26-
"TQ_show_recurrence_rule": "checkbox",
27-
"TQ_show_on_completion": "checkbox",
28-
"TQ_show_created_date": "checkbox",
29-
"TQ_show_start_date": "checkbox",
30-
"TQ_show_scheduled_date": "checkbox",
31-
"TQ_show_due_date": "checkbox",
24+
"TQ_show_backlink": "checkbox",
3225
"TQ_show_cancelled_date": "checkbox",
26+
"TQ_show_created_date": "checkbox",
27+
"TQ_show_depends_on": "checkbox",
3328
"TQ_show_done_date": "checkbox",
34-
"TQ_show_urgency": "checkbox",
35-
"TQ_show_backlink": "checkbox",
29+
"TQ_show_due_date": "checkbox",
3630
"TQ_show_edit_button": "checkbox",
31+
"TQ_show_id": "checkbox",
32+
"TQ_show_on_completion": "checkbox",
3733
"TQ_show_postpone_button": "checkbox",
34+
"TQ_show_priority": "checkbox",
35+
"TQ_show_recurrence_rule": "checkbox",
36+
"TQ_show_scheduled_date": "checkbox",
37+
"TQ_show_start_date": "checkbox",
38+
"TQ_show_tags": "checkbox",
3839
"TQ_show_task_count": "checkbox",
39-
"TQ_sort_by": "multitext",
40-
"TQ_group_by": "multitext",
41-
"TQ_extra_instructions": "text"
40+
"TQ_show_tree": "checkbox",
41+
"TQ_show_urgency": "checkbox"
4242
}
4343
}

src/Query/QueryFileDefaults.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,116 +14,137 @@ enum Handler {
1414
const queryProperties = [
1515
{
1616
name: 'TQ_explain',
17+
type: 'checkbox',
1718
display: 'explain',
1819
handler: Handler.Instruction,
1920
trueValue: 'explain',
2021
falseValue: '',
2122
},
2223
{
2324
name: 'TQ_short_mode',
25+
type: 'checkbox',
2426
display: 'short mode',
2527
handler: Handler.Instruction,
2628
trueValue: 'short mode',
2729
falseValue: 'full mode',
2830
},
2931
{
3032
name: 'TQ_show_tree',
33+
type: 'checkbox',
3134
display: 'tree',
3235
handler: Handler.ShowAndHide,
3336
},
3437

3538
// Fields that appear before date values:
3639
{
3740
name: 'TQ_show_tags',
41+
type: 'checkbox',
3842
display: 'tags',
3943
handler: Handler.ShowAndHide,
4044
},
4145
{
4246
name: 'TQ_show_id',
47+
type: 'checkbox',
4348
display: 'id',
4449
handler: Handler.ShowAndHide,
4550
},
4651
{
4752
name: 'TQ_show_depends_on',
53+
type: 'checkbox',
4854
display: 'depends on',
4955
handler: Handler.ShowAndHide,
5056
},
5157
{
5258
name: 'TQ_show_priority',
59+
type: 'checkbox',
5360
display: 'priority',
5461
handler: Handler.ShowAndHide,
5562
},
5663
{
5764
name: 'TQ_show_recurrence_rule',
65+
type: 'checkbox',
5866
display: 'recurrence rule',
5967
handler: Handler.ShowAndHide,
6068
},
6169
{
6270
name: 'TQ_show_on_completion',
71+
type: 'checkbox',
6372
display: 'on completion',
6473
handler: Handler.ShowAndHide,
6574
},
6675

6776
// Date fields:
6877
{
6978
name: 'TQ_show_created_date',
79+
type: 'checkbox',
7080
display: 'created date',
7181
handler: Handler.ShowAndHide,
7282
},
7383
{
7484
name: 'TQ_show_start_date',
85+
type: 'checkbox',
7586
display: 'start date',
7687
handler: Handler.ShowAndHide,
7788
},
7889
{
7990
name: 'TQ_show_scheduled_date',
91+
type: 'checkbox',
8092
display: 'scheduled date',
8193
handler: Handler.ShowAndHide,
8294
},
8395
{
8496
name: 'TQ_show_due_date',
97+
type: 'checkbox',
8598
display: 'due date',
8699
handler: Handler.ShowAndHide,
87100
},
88101
{
89102
name: 'TQ_show_cancelled_date',
103+
type: 'checkbox',
90104
display: 'cancelled date',
91105
handler: Handler.ShowAndHide,
92106
},
93107
{
94108
name: 'TQ_show_done_date',
109+
type: 'checkbox',
95110
display: 'done date',
96111
handler: Handler.ShowAndHide,
97112
},
98113

99114
// Elements of query results:
100115
{
101116
name: 'TQ_show_urgency',
117+
type: 'checkbox',
102118
display: 'urgency',
103119
handler: Handler.ShowAndHide,
104120
},
105121
{
106122
name: 'TQ_show_backlink',
123+
type: 'checkbox',
107124
display: 'backlink',
108125
handler: Handler.ShowAndHide,
109126
},
110127
{
111128
name: 'TQ_show_edit_button',
129+
type: 'checkbox',
112130
display: 'edit button',
113131
handler: Handler.ShowAndHide,
114132
},
115133
{
116134
name: 'TQ_show_postpone_button',
135+
type: 'checkbox',
117136
display: 'postpone button',
118137
handler: Handler.ShowAndHide,
119138
},
120139
{
121140
name: 'TQ_show_task_count',
141+
type: 'checkbox',
122142
display: 'task count',
123143
handler: Handler.ShowAndHide,
124144
},
125145
{
126146
name: 'TQ_extra_instructions',
147+
type: 'text',
127148
handler: Handler.AddValue,
128149
},
129150
];
@@ -168,6 +189,16 @@ export class QueryFileDefaults {
168189
return this.allPropertyNames().sort((a, b) => a.localeCompare(b));
169190
}
170191

192+
/**
193+
* Return the type of the property with the specified name.
194+
*
195+
* @param {string} propertyName - The name of the property to retrieve the type for.
196+
* @return {string | undefined} The type of the property if found, or undefined if the property is not found.
197+
*/
198+
public propertyType(propertyName: string): string | undefined {
199+
return queryProperties.find((prop) => prop.name === propertyName)?.type ?? undefined;
200+
}
201+
171202
/**
172203
* Return text that creates MetaBind widgets for users to edit query file defaults.
173204
*/

src/main.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { EditorSuggestor } from './Suggestor/EditorSuggestorPopup';
1818
import { StatusSettings } from './Config/StatusSettings';
1919
import { tasksApiV1 } from './Api';
2020
import { GlobalFilter } from './Config/GlobalFilter';
21+
import { QueryFileDefaults } from './Query/QueryFileDefaults';
2122

2223
export default class TasksPlugin extends Plugin {
2324
private cache: Cache | undefined;
@@ -61,6 +62,9 @@ export default class TasksPlugin extends Plugin {
6162
this.inlineRenderer = new InlineRenderer({ plugin: this });
6263
this.queryRenderer = new QueryRenderer({ plugin: this, events });
6364

65+
// Update types.json.
66+
this.setObsidianPropertiesTypes();
67+
6468
this.registerEditorExtension(newLivePreviewExtension());
6569
this.registerEditorSuggest(new EditorSuggestor(this.app, getSettings(), this));
6670
new Commands({ plugin: this });
@@ -101,4 +105,32 @@ export default class TasksPlugin extends Plugin {
101105
return this.cache.getTasks();
102106
}
103107
}
108+
109+
/**
110+
* Add {@link QueryFileDefaults} properties to the Obsidian vault's types.json file,
111+
* so that they are available via auto-complete in the File Properties panel.
112+
*/
113+
private setObsidianPropertiesTypes() {
114+
// Credit: this code based on ideas...
115+
// by:
116+
// @SkepticMystic
117+
// in:
118+
// https://github.com/SkepticMystic/breadcrumbs/blob/d380407678ce64f5668550d270b1035bc1a767f8/src/main.ts#L47-L64
119+
try {
120+
// @ts-expect-error TS2339: Property metadataTypeManager does not exist on type App
121+
const metadataTypeManager = this.app.metadataTypeManager;
122+
const all_properties = metadataTypeManager.getAllProperties();
123+
124+
const defaults = new QueryFileDefaults();
125+
for (const field of defaults.allPropertyNamesSorted()) {
126+
const property_type = defaults.propertyType(field);
127+
if (all_properties[field]?.type === property_type) {
128+
continue;
129+
}
130+
metadataTypeManager.setType(field, property_type);
131+
}
132+
} catch (error) {
133+
console.error('setObsidianPropertiesTypes error', error);
134+
}
135+
}
104136
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"types": {
3+
"TQ_explain": "checkbox",
4+
"TQ_extra_instructions": "text",
5+
"TQ_short_mode": "checkbox",
6+
"TQ_show_backlink": "checkbox",
7+
"TQ_show_cancelled_date": "checkbox",
8+
"TQ_show_created_date": "checkbox",
9+
"TQ_show_depends_on": "checkbox",
10+
"TQ_show_done_date": "checkbox",
11+
"TQ_show_due_date": "checkbox",
12+
"TQ_show_edit_button": "checkbox",
13+
"TQ_show_id": "checkbox",
14+
"TQ_show_on_completion": "checkbox",
15+
"TQ_show_postpone_button": "checkbox",
16+
"TQ_show_priority": "checkbox",
17+
"TQ_show_recurrence_rule": "checkbox",
18+
"TQ_show_scheduled_date": "checkbox",
19+
"TQ_show_start_date": "checkbox",
20+
"TQ_show_tags": "checkbox",
21+
"TQ_show_task_count": "checkbox",
22+
"TQ_show_tree": "checkbox",
23+
"TQ_show_urgency": "checkbox"
24+
}
25+
}

tests/DocumentationSamples/DefaultsDocs/DocsSamplesForDefaults.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Pos } from 'obsidian';
22

3+
import { verifyAsJson } from 'approvals/lib/Providers/Jest/JestApprovals';
34
import { getTasksFileFromMockData } from '../../TestingTools/MockDataHelpers';
45
import query_file_defaults_all_options_null from '../../Obsidian/__test_data__/query_file_defaults_all_options_null.json';
56
import query_file_defaults_all_options_true from '../../Obsidian/__test_data__/query_file_defaults_all_options_true.json';
@@ -37,4 +38,24 @@ describe('DocsSamplesForDefaults', () => {
3738
it('meta-bind-widgets-snippet', () => {
3839
verifyMarkdown(new QueryFileDefaults().metaBindPluginWidgets());
3940
});
41+
42+
it('fake-types.json', () => {
43+
const queryFileDefaults = new QueryFileDefaults();
44+
const allPropertyNamesSorted = queryFileDefaults.allPropertyNamesSorted();
45+
46+
// Generate an object representing QueryFileDefaults in Obsidain's types.json.
47+
const types: { [key: string]: string } = allPropertyNamesSorted.reduce(
48+
(acc: { [key: string]: string }, propName) => {
49+
const propType = queryFileDefaults.propertyType(propName);
50+
if (propType !== undefined) {
51+
acc[propName] = propType;
52+
}
53+
return acc;
54+
},
55+
{},
56+
);
57+
const generatedObject = { types };
58+
59+
verifyAsJson(generatedObject);
60+
});
4061
});

tests/Query/QueryFileDefaults.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ describe('QueryFileDefaults', () => {
7777
`);
7878
});
7979

80+
it('should provide a known property type', () => {
81+
expect(new QueryFileDefaults().propertyType('TQ_show_tree')).toEqual('checkbox');
82+
});
83+
84+
it('should provide an unknown property type as undefined', () => {
85+
expect(new QueryFileDefaults().propertyType('TQ_any_old_property')).toBeUndefined();
86+
});
87+
8088
it('should generate instructions - all values false', () => {
8189
expect(generateQueryFileDefaultsSource(query_file_defaults_all_options_false)).toMatchInlineSnapshot(`
8290
"full mode

0 commit comments

Comments
 (0)