Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit a08f251

Browse files
committed
Merge branch '442-fr-edit-nested-metadata'
2 parents e6af88f + 14e9228 commit a08f251

File tree

12 files changed

+263
-195
lines changed

12 files changed

+263
-195
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@
5151
"dependencies": {
5252
"@emotion/styled": "11.10.4",
5353
"@mui/icons-material": "5.10.6",
54-
"@mui/material": "5.10.6",
54+
"@mui/material": "5.10.8",
5555
"@popperjs/core": "2.11.6",
56-
"@tanstack/match-sorter-utils": "8.1.1",
57-
"@tanstack/react-table": "8.5.13",
56+
"@tanstack/match-sorter-utils": "8.5.14",
57+
"@tanstack/react-table": "8.5.15",
5858
"eventemitter3": "4.0.7",
5959
"fuse.js": "6.6.2",
6060
"luxon": "3.0.4",

src/commands/addDatabaseHelper/databaseHelperCreationModal.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { resolve_tfolder } from "helpers/FileManagement";
55
import { generateDataviewTableQuery } from "helpers/QueryHelper";
66
import { Modal, Notice, Setting } from "obsidian";
77
import { DataviewService } from "services/DataviewService";
8+
import { ParseService } from "services/ParseService";
89
import { add_dropdown, add_setting_header } from "settings/SettingsComponents";
910
import { FileSuggest } from "settings/suggesters/FileSuggester";
1011
import { FolderSuggest } from "settings/suggesters/FolderSuggester";
@@ -246,7 +247,7 @@ export class DatabaseHelperCreationModalManager {
246247
}
247248

248249
parseValueToThuthyYaml(value: string): string {
249-
return DataviewService.parseLiteral(
250+
return ParseService.parseLiteral(
250251
value,
251252
InputType.MARKDOWN,
252253
this.databaseHelperCreationModal.local_settings

src/components/cellTypes/TextCell.tsx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { renderMarkdown } from "components/obsidianArq/MarkdownRenderer";
33
import React, { MouseEventHandler, useEffect, useRef } from "react";
44
import { useState } from "react";
55
import EditorCell from "components/cellTypes/EditorCell";
6-
import { TableColumn } from "cdm/FolderModel";
6+
import { RowDataType, TableColumn } from "cdm/FolderModel";
77
import { c, getAlignmentClassname } from "helpers/StylesHelper";
8+
import { Literal } from "obsidian-dataview";
89

910
const TextCell = (props: CellComponentProps) => {
1011
const { defaultCell } = props;
@@ -25,7 +26,7 @@ const TextCell = (props: CellComponentProps) => {
2526
(state) => state.actions
2627
);
2728

28-
const textCell = textRow[column.id]?.toString();
29+
const textCell = parseTextRowToString(textRow, column.id);
2930
/** Ref to cell container */
3031
const containerCellRef = useRef<HTMLDivElement>();
3132
const [dirtyCell, setDirtyCell] = useState(false);
@@ -51,10 +52,11 @@ const TextCell = (props: CellComponentProps) => {
5152

5253
const persistChange = (changedValue: string) => {
5354
if (changedValue !== undefined && changedValue !== textCell) {
55+
const newCell = parseStringToTextRow(textRow, column.id, changedValue);
5456
dataActions.updateCell(
5557
row.index,
5658
tableColumn,
57-
changedValue.trim(),
59+
newCell,
5860
columnsInfo.getAllColumns(),
5961
configInfo.getLocalSettings()
6062
);
@@ -80,4 +82,29 @@ const TextCell = (props: CellComponentProps) => {
8082
);
8183
};
8284

85+
function parseTextRowToString(row: RowDataType, columnId: string) {
86+
const cellRoot = row[columnId];
87+
let textCell = "";
88+
if (typeof cellRoot === "object") {
89+
textCell = JSON.stringify(cellRoot);
90+
} else {
91+
textCell = cellRoot?.toString();
92+
}
93+
return textCell;
94+
}
95+
96+
function parseStringToTextRow(
97+
row: RowDataType,
98+
columnId: string,
99+
newValue: string
100+
): Literal {
101+
const cellRoot = row[columnId];
102+
if (typeof cellRoot === "object") {
103+
// TODO control anidated values in function of columnId spliting by "."
104+
return JSON.parse(newValue);
105+
} else {
106+
return newValue.trim();
107+
}
108+
}
109+
83110
export default TextCell;

src/components/reducers/CustomSortingFn.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { RowDataType } from "cdm/FolderModel";
33
import { LocalSettings } from "cdm/SettingsModel";
44
import { InputType } from "helpers/Constants";
55
import { Literal } from "obsidian-dataview";
6-
import { DataviewService } from "services/DataviewService";
6+
import { ParseService } from "services/ParseService";
77

88
const dbfolderColumnSortingFn: (
99
ddbbConfig: LocalSettings
@@ -14,15 +14,15 @@ const dbfolderColumnSortingFn: (
1414
rowB: Row<RowDataType>,
1515
columnId: string
1616
): number => {
17-
const a = DataviewService.parseLiteral(
17+
const a = ParseService.parseLiteral(
1818
rowA.getValue<Literal>(columnId),
1919
InputType.MARKDOWN,
2020
ddbbConfig,
2121
true
2222
)
2323
.toString()
2424
.toLowerCase();
25-
const b = DataviewService.parseLiteral(
25+
const b = ParseService.parseLiteral(
2626
rowB.getValue<Literal>(columnId),
2727
InputType.MARKDOWN,
2828
ddbbConfig,

src/components/reducers/TableFilterFlavours.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { RowDataType } from "cdm/FolderModel"
33
import { LocalSettings } from "cdm/SettingsModel";
44
import { InputType } from "helpers/Constants";
55
import { Literal } from "obsidian-dataview";
6-
import { DataviewService } from "services/DataviewService";
6+
import { ParseService } from "services/ParseService";
77

88
export const globalDatabaseFilterFn: (ddbbConfig: LocalSettings) => FilterFn<RowDataType> = (ddbbConfig: LocalSettings) => (
99
row: Row<RowDataType>,
@@ -14,7 +14,7 @@ export const globalDatabaseFilterFn: (ddbbConfig: LocalSettings) => FilterFn<Row
1414
if (value === undefined) {
1515
return false;
1616
}
17-
const sanitized = DataviewService.parseLiteral(value, InputType.MARKDOWN, ddbbConfig, true).toString().toLowerCase();
17+
const sanitized = ParseService.parseLiteral(value, InputType.MARKDOWN, ddbbConfig, true).toString().toLowerCase();
1818
filterValue = filterValue.toLowerCase();
1919
return sanitized.includes(filterValue) || searchRegex(sanitized, filterValue);
2020
}

src/helpers/TableFiltersHelper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AtomicFilter, FilterGroup, FilterGroupCondition, LocalSettings } from "cdm/SettingsModel";
22
import { Literal } from "obsidian-dataview";
33
import { ConditionFiltersOptions, getOperatorFilterValue, InputType, OperatorFilter } from "helpers/Constants";
4-
import { DataviewService } from "services/DataviewService";
4+
import { ParseService } from "services/ParseService";
55

66
export default function tableFilter(dbFilters: FilterGroup[], p: Record<string, Literal>, ddbbConfig: LocalSettings): boolean {
77
if (!dbFilters || dbFilters.length === 0) return true;
@@ -34,7 +34,7 @@ function validateFilter(p: Record<string, Literal>, filter: FilterGroup, ddbbCon
3434
}
3535
return groupResult;
3636
}
37-
const filterableValue = DataviewService.parseLiteral(p[(filter as AtomicFilter).field], InputType.MARKDOWN, ddbbConfig);
37+
const filterableValue = ParseService.parseLiteral(p[(filter as AtomicFilter).field], InputType.MARKDOWN, ddbbConfig);
3838
// Atomic filter
3939
const operator = (filter as AtomicFilter).operator;
4040
const value = (filter as AtomicFilter).value;

src/parsers/RowDatabaseFieldsToFile.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { InputType } from "helpers/Constants";
44
import { Literal } from "obsidian-dataview";
55
import { DateTime } from "luxon";
66
import { DataviewService } from "services/DataviewService";
7+
import { ParseService } from "services/ParseService";
78
export const parseFrontmatterFieldsToString = (databaseFields: RowDatabaseFields, localSettings: LocalSettings, deletedColumn?: string): string => {
89
const frontmatterFields = databaseFields.frontmatter;
910
let array: string[] = [];
@@ -27,7 +28,7 @@ export const parseInlineFieldsToString = (inlineFields: RowDatabaseFields): stri
2728
}
2829

2930
export function parseValuetoSanitizeYamlValue(value: string, localSettings: LocalSettings): string {
30-
return DataviewService.parseLiteral(value, InputType.MARKDOWN, localSettings).toString();
31+
return ParseService.parseLiteral(value, InputType.MARKDOWN, localSettings).toString();
3132
}
3233

3334
function stringifyDbYaml(literal: Literal, level: number, localSettings: LocalSettings, key?: string): string[] {
@@ -42,7 +43,7 @@ function stringifyDbYaml(literal: Literal, level: number, localSettings: LocalSe
4243
}
4344
// Manage Dates
4445
else if (DateTime.isDateTime(literal)) {
45-
literalBlock.push(`${" ".repeat(level)}${key}: ${DataviewService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
46+
literalBlock.push(`${" ".repeat(level)}${key}: ${ParseService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
4647
}
4748
// Manage Objects
4849
else if (DataviewService.getDataviewAPI().value.isObject(literal)) {
@@ -55,9 +56,9 @@ function stringifyDbYaml(literal: Literal, level: number, localSettings: LocalSe
5556
}
5657
// Manage atomic values
5758
else if (key) {
58-
literalBlock.push(`${" ".repeat(level)}${key}: ${DataviewService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
59+
literalBlock.push(`${" ".repeat(level)}${key}: ${ParseService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
5960
} else {
60-
literalBlock.push(`${" ".repeat(level)}- ${DataviewService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
61+
literalBlock.push(`${" ".repeat(level)}- ${ParseService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
6162
}
6263
return literalBlock;
6364
}

src/services/DataviewService.ts

Lines changed: 0 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
import { InputType, MarkdownBreakerRules } from "helpers/Constants";
21
import { Notice } from "obsidian";
32
import { DataviewApi, getAPI, isPluginEnabled } from "obsidian-dataview";
43
import { Literal, WrappedLiteral } from "obsidian-dataview/lib/data-model/value";
5-
import { DateTime } from "luxon";
6-
import { LOGGER } from "services/Logger";
7-
import { LocalSettings } from "cdm/SettingsModel";
84
class DataviewProxy {
95

106
private static instance: DataviewProxy;
@@ -30,52 +26,6 @@ class DataviewProxy {
3026
return this.getDataviewAPI().value.isTruthy(literal?.toString());
3127
}
3228

33-
parseLiteral(literal: Literal, dataTypeDst: string, localSettings: LocalSettings, isInline?: boolean): Literal {
34-
let parsedLiteral: Literal = literal;
35-
if (!this.isTruthy(literal?.toString())) {
36-
return "";
37-
}
38-
literal = this.parseDataArray(literal);
39-
const wrapped = this.wrapLiteral(literal);
40-
LOGGER.debug(`=>parseLiteral: type ${wrapped
41-
.type} to ${dataTypeDst}`);
42-
// Check empty or undefined literals
43-
switch (dataTypeDst) {
44-
case InputType.TEXT:
45-
parsedLiteral = this.parseToString(wrapped);
46-
break;
47-
case InputType.MARKDOWN:
48-
parsedLiteral = this.parseToMarkdown(wrapped, localSettings, isInline);
49-
break;
50-
case InputType.TAGS:
51-
parsedLiteral = this.parseToOptionsArray(wrapped);
52-
break;
53-
case InputType.CALENDAR:
54-
parsedLiteral = this.parseToCalendar(wrapped, localSettings.date_format);
55-
break;
56-
case InputType.CALENDAR_TIME:
57-
parsedLiteral = this.parseToCalendar(wrapped, localSettings.datetime_format);
58-
break;
59-
case InputType.METATADA_TIME:
60-
parsedLiteral = this.parseToCalendar(wrapped);
61-
break;
62-
case InputType.NUMBER:
63-
parsedLiteral = this.parseToNumber(wrapped);
64-
break;
65-
case InputType.CHECKBOX:
66-
parsedLiteral = this.parseToBoolean(wrapped);
67-
break;
68-
case InputType.TASK:
69-
case InputType.FORMULA:
70-
// Do nothing
71-
break;
72-
default:
73-
parsedLiteral = parsedLiteral = this.parseToString(wrapped);
74-
75-
}
76-
LOGGER.debug(`<=parseLiteral`);
77-
return parsedLiteral;
78-
}
7929
/**
8030
* Check if literal is Proxy DataArray, if so, parse it. If not, return same literal
8131
* @param literal
@@ -97,124 +47,6 @@ class DataviewProxy {
9747
}
9848
return this.instance;
9949
}
100-
101-
private parseToCalendar(wrapped: WrappedLiteral, format?: string): DateTime {
102-
if (wrapped.type === 'string') {
103-
let calendarCandidate;
104-
if (format) {
105-
calendarCandidate = DateTime.fromFormat(wrapped.value, format);
106-
} else {
107-
calendarCandidate = DateTime.fromISO(wrapped.value);
108-
}
109-
110-
if (calendarCandidate.isValid) {
111-
return calendarCandidate;
112-
}
113-
return null;
114-
}
115-
116-
if (DateTime.isDateTime(wrapped.value)) {
117-
return wrapped.value;
118-
} else {
119-
return null;
120-
}
121-
}
122-
123-
private parseToString(wrapped: WrappedLiteral): string {
124-
if (DateTime.isDateTime(wrapped.value)) {
125-
LOGGER.debug("adapting DateTime to string...");
126-
// Values of dataview parse to md friendly strings
127-
return wrapped.value.toFormat("yyyy-MM-dd");
128-
} else {
129-
return this.getDataviewAPI().value.toString(wrapped.value);
130-
}
131-
}
132-
133-
private parseToNumber(wrapped: WrappedLiteral): number {
134-
if (wrapped.type === 'number') {
135-
return wrapped.value;
136-
} else {
137-
const adjustedValue = this.getDataviewAPI().value.toString(wrapped.value);
138-
return Number(adjustedValue);
139-
}
140-
}
141-
142-
private parseToBoolean(wrapped: WrappedLiteral): string {
143-
if (wrapped.type === 'boolean') {
144-
return wrapped.value ? 'true' : 'false';
145-
} else {
146-
const adjustedValue = this.getDataviewAPI().value.toString(wrapped.value);
147-
return adjustedValue === 'true' ? "true" : "false";
148-
}
149-
}
150-
151-
private parseToMarkdown(wrapped: WrappedLiteral, localSettings: LocalSettings, isInline: boolean): string {
152-
let auxMarkdown = '';
153-
switch (wrapped.type) {
154-
case 'boolean':
155-
case 'number':
156-
// Do nothing
157-
auxMarkdown = wrapped.value.toString();
158-
break;
159-
case 'array':
160-
auxMarkdown = wrapped.value
161-
.map(v => this.parseToMarkdown(this.getDataviewAPI().value.wrapValue(v), localSettings, isInline))
162-
.join(', ');
163-
break;
164-
165-
case 'date':
166-
if (wrapped.value.hour === 0 && wrapped.value.minute === 0 && wrapped.value.second === 0) {
167-
// Parse date
168-
auxMarkdown = wrapped.value.toFormat(localSettings.date_format);
169-
} else {
170-
// Parse datetime
171-
auxMarkdown = wrapped.value.toFormat(localSettings.datetime_format);
172-
auxMarkdown = this.handleMarkdownBreaker(auxMarkdown, localSettings, isInline);
173-
}
174-
break;
175-
case 'object':
176-
if (DateTime.isDateTime(wrapped.value)) {
177-
return this.parseToMarkdown({ type: 'date', value: wrapped.value }, localSettings, isInline);
178-
}
179-
// Else go to default
180-
default:
181-
auxMarkdown = this.parseToString(wrapped) as string;
182-
// Check possible markdown breakers
183-
auxMarkdown = this.handleMarkdownBreaker(auxMarkdown, localSettings, isInline);
184-
}
185-
return auxMarkdown;
186-
}
187-
188-
private parseToOptionsArray(wrapped: WrappedLiteral): Literal {
189-
if (wrapped.type !== 'array') {
190-
return wrapped.value.toString().split(",").map(s => s.trim());
191-
}
192-
return wrapped.value;
193-
}
194-
195-
private handleMarkdownBreaker(value: string, localSettings: LocalSettings, isInline?: boolean): string {
196-
// Do nothing if is inline
197-
if (isInline) {
198-
return value;
199-
}
200-
201-
// Remove a possible already existing quote wrapper
202-
if (value.startsWith('"') && value.endsWith('"')) {
203-
value = value.substring(1, value.length - 1);
204-
}
205-
206-
// Check possible markdown breakers of the yaml
207-
if (MarkdownBreakerRules.INIT_CHARS.some(c => value.startsWith(c)) ||
208-
MarkdownBreakerRules.BETWEEN_CHARS.some(rule => value.includes(rule)) ||
209-
MarkdownBreakerRules.UNIQUE_CHARS.some(c => value === c) ||
210-
localSettings.frontmatter_quote_wrap) {
211-
value = value.replaceAll(`\\`, ``);
212-
value = value.replaceAll(`"`, `\\"`);
213-
return `"${value}"`;
214-
}
215-
216-
return value;
217-
}
21850
}
21951

22052
export const DataviewService = DataviewProxy.getInstance();

0 commit comments

Comments
 (0)