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

Commit 46f1f73

Browse files
committed
Merge branch 'resilience-formulas'
2 parents 757f41a + 89cab4f commit 46f1f73

File tree

11 files changed

+66
-42
lines changed

11 files changed

+66
-42
lines changed

docs/docs/features/Formulas.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## Formulas on dbfolder
2+
You can use formulas to create dynamic values in your database.
3+
The formula is a javascript code that will be executed when the row is loaded.
4+
5+
## How to use
6+
The code can be written in the column settings or in the note's metadata.
7+
8+
### Exposed variables
9+
- `row` : the row object
10+
- `db` : the database object with predefined functions that can be used in the formula
11+
- `config` : the table's config information
12+
13+
To use an exposed variable, use the `${}` syntax. For example, to get the value of the `Name` column, you can use `${row.Name}`.
14+
15+
### Exposed functions
16+
The root object `db` has the following functions:
17+
- `js` : execute a javascript function that you previously defined in the `js` folder of your table. (I.E.: `db.js.myFunction( arg1, arg2)`)
18+

docs/docs/features/Properties.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
- **Time**: this property accepts time with the format `YYYY-MM-DD hh:mm AM/PM` ;
88
- **Select**: this property accepts from a list of options you define. Colors are attributed automatically, though you can change them in the column setting. Furthermore, when removing the select option in the setting, it is also removed from the note's metadata ;
99
- **Tags**: similar to the previous property, but instead of only selecting one option, you can select multiples options per cell ;
10+
- **Formulas**: property that accepts js code to return dynamic values in function of your code. See the [Formulas](/docs/features/Formulas) section for more details.
1011
- **Image**: you can embed images in the `text` property in this format `![[image]]`. Make sure to enable `media links` in the column setting and adjust the dimensions too ;
1112
- **Created time**: this column can be added only once from the database settings and will display the created time of the row ;
1213
- **Modified time**: this column can be added only once from the database settings and will display the last modified time of the row ;
1314
- **Tasks**: this column can be added only once from the database settings and will display the task of the given file. You can also choose to hide the completed tasks in the column settings ;
1415
- **Inlinks**: this column can be added only once from the database settings and will display the files that have links to the select file ;
1516
- **Outlinks**: this column can be added only once from the database settings and will display the files that have links from the select file.
16-
1717
> You can change from one property type to another, and if the format is right, it will be recognized by the plugin.
1818
1919
## YAML & Dataview Inline Fields

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ nav:
99
- Properties: "features/Properties.md"
1010
- Notes: "features/Notes.md"
1111
- Viewing data: "features/Viewing data.md"
12+
- Formulas: "features/Formulas.md"
1213
- About: "about.md"
1314
- FAQ: "faq.md"
1415
- Media:
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
import { FormulaFunctions } from "automations/formula_functions/FormulaFunctions";
22
import { IGenerateObject } from "automations/IGenerateObject";
33
import { LocalSettings } from "cdm/SettingsModel";
4-
import { RowDataType } from "cdm/FolderModel";
5-
import { Literal } from "obsidian-dataview";
64
export class FormulaGenerator implements IGenerateObject {
7-
public formula_functions: FormulaFunctions;
5+
public js_functions: FormulaFunctions;
86

97
constructor(private config: LocalSettings) {
10-
this.formula_functions = new FormulaFunctions(config);
8+
this.js_functions = new FormulaFunctions(config);
119
}
1210

13-
private async generate_formula_functions(): Promise<Record<string, unknown>> {
11+
private async generate_js_functions(): Promise<Record<string, unknown>> {
1412

15-
return await this.formula_functions.generate_object(this.config);
13+
return await this.js_functions.generate_object(this.config);
1614
}
1715

1816
async generate_object(): Promise<Record<string, unknown>> {
1917
const final_object: Record<string, any> = {};
2018
Object.assign(final_object, {
21-
js: await this.generate_formula_functions(),
19+
js: await this.generate_js_functions(),
2220
});
23-
console.log("sasdinal_object");
2421
return final_object;
2522
}
2623
}

src/automations/formula_functions/ScriptFunctions.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,12 @@ export class UserScriptFunctions implements IGenerateObject {
5050
if (!formula_function) {
5151
const msg = `Failed to load user script ${file.path}. No exports detected.`;
5252
LOGGER.error(msg);
53-
new Notice(
54-
msg
55-
, 3000);
56-
throw new Error(msg);
53+
return;
5754
}
5855
if (!(formula_function instanceof Function)) {
5956
const msg = `Failed to load user script ${file.path}. Default export is not a function.`
6057
LOGGER.error(msg);
61-
new Notice(
62-
msg
63-
, 3000);
64-
throw new Error(msg);
58+
return;
6559
}
6660
user_script_functions.set(`${file.basename}`, formula_function);
6761
}

src/components/cellTypes/FormulaCell.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
11
import { CellComponentProps } from "cdm/ComponentsModel";
22
import { TableColumn } from "cdm/FolderModel";
3+
import { renderMarkdown } from "components/obsidianArq/MarkdownRenderer";
34
import { c } from "helpers/StylesHelper";
4-
import React from "react";
5+
import React, { useEffect, useRef } from "react";
56

67
const FormulaCell = (mdProps: CellComponentProps) => {
78
const { defaultCell } = mdProps;
89
const { cell, table, row, column } = defaultCell;
910
const { tableState } = table.options.meta;
1011
const tableColumn = column.columnDef as TableColumn;
12+
const formulaRef = useRef<HTMLDivElement>();
1113
const formulaRow = tableState.data((state) => state.rows[row.index]);
1214
const configInfo = tableState.configState((state) => state.info);
1315
const formulaInfo = tableState.automations((state) => state.info);
14-
return (
15-
<div className={`${c("md_cell")}`} key={`formula_${cell.id}`}>
16-
{formulaInfo
16+
17+
useEffect(() => {
18+
if (formulaRef.current !== null) {
19+
formulaRef.current.innerHTML = "";
20+
const formulaResponse = formulaInfo
1721
.runFormula(
1822
tableColumn.config.formula_query,
1923
formulaRow,
2024
configInfo.getLocalSettings()
2125
)
22-
.toString()}
23-
</div>
26+
.toString();
27+
renderMarkdown(defaultCell, formulaResponse, formulaRef.current, 5);
28+
}
29+
}, [row]);
30+
return (
31+
<span
32+
ref={formulaRef}
33+
className={`${c("md_cell")}`}
34+
key={`formula_${cell.id}`}
35+
/>
2436
);
2537
};
2638

src/helpers/QueryHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { LOGGER } from "services/Logger";
55
export function generateDataviewTableQuery(columns: TableColumn[], fromQuery: string): string {
66
return `TABLE ${columns
77
.filter((col) => !col.isMetadata)
8-
.map((col) => col.key)
8+
.map((col) => `"${col.key}"`)
99
.join(",")},${DatabaseCore.DATAVIEW_FILE},${DatabaseCore.FRONTMATTER_KEY} ${fromQuery}`
1010
}
1111

src/parsers/RowDatabaseFieldsToFile.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,8 @@ function parseLiteralToString(literal: Literal, level: number, localSettings: Lo
4040
literalBlock.push(`${" ".repeat(level)}- ${DataviewService.parseLiteral(literal, InputType.MARKDOWN, localSettings)}`);
4141
}
4242
return literalBlock;
43+
}
44+
45+
export function parseValuetoSanitizeYamlValue(value: string, localSettings: LocalSettings): string {
46+
return DataviewService.parseLiteral(value, InputType.MARKDOWN, localSettings).toString();
4347
}

src/parsers/handlers/unmarshall/UnmarshallColumnsHandler.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { DatabaseColumn } from "cdm/DatabaseModel";
22
import { DiskHandlerResponse } from "cdm/MashallModel";
33
import { InputType, YAML_INDENT } from "helpers/Constants";
44
import { AbstractDiskHandler } from "parsers/handlers/unmarshall/AbstractDiskPropertyHandler";
5+
import { parseValuetoSanitizeYamlValue } from "parsers/RowDatabaseFieldsToFile";
56

67
export class UnmarshallColumnsHandler extends AbstractDiskHandler {
78
handlerName: string = 'columns';
89

910
public handle(handlerResponse: DiskHandlerResponse): DiskHandlerResponse {
10-
const { columns } = handlerResponse.yaml;
11+
const { columns, config } = handlerResponse.yaml;
1112
// Lvl1: columns field group
1213
this.localDisk.push(`${this.handlerName}:`);
1314
for (const columnKey in columns) {
@@ -21,10 +22,7 @@ export class UnmarshallColumnsHandler extends AbstractDiskHandler {
2122
.filter(key => typeof column[key] !== 'object')
2223
.forEach(key => {
2324
// Lvl3: literal column properties
24-
let value = column[key];
25-
if (typeof value === 'string') {
26-
value = `"${value}"`;
27-
}
25+
const value = parseValuetoSanitizeYamlValue(column[key]?.toString(), config);
2826
this.localDisk.push(`${YAML_INDENT.repeat(2)}${key}: ${value}`);
2927
});
3028

@@ -33,7 +31,8 @@ export class UnmarshallColumnsHandler extends AbstractDiskHandler {
3331

3432
// Lvl4: column config
3533
Object.keys(column.config).forEach(key => {
36-
this.localDisk.push(`${YAML_INDENT.repeat(3)}${key}: ${column.config[key]}`);
34+
const connfValue = parseValuetoSanitizeYamlValue(column.config[key]?.toString(), config);
35+
this.localDisk.push(`${YAML_INDENT.repeat(3)}${key}: ${connfValue}`);
3736
});
3837
};
3938
return this.goNext(handlerResponse);
@@ -55,4 +54,4 @@ function unmarshallParticularInputInfo(column: DatabaseColumn): string[] {
5554
}
5655
}
5756
return particularInputString;
58-
}
57+
}
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { DiskHandlerResponse } from "cdm/MashallModel";
2-
import { LocalSettings } from "cdm/SettingsModel";
3-
import { InputType, YAML_INDENT } from "helpers/Constants";
2+
import { YAML_INDENT } from "helpers/Constants";
43
import { escapeSpecialCharacters } from "parsers/EscapeHelper";
54
import { AbstractDiskHandler } from "parsers/handlers/unmarshall/AbstractDiskPropertyHandler";
6-
import { DataviewService } from "services/DataviewService";
5+
import { parseValuetoSanitizeYamlValue } from "parsers/RowDatabaseFieldsToFile";
76

87
export class UnmarshallConfigHandler extends AbstractDiskHandler {
98
handlerName: string = 'config';
@@ -17,19 +16,15 @@ export class UnmarshallConfigHandler extends AbstractDiskHandler {
1716
this.localDisk.push(`${YAML_INDENT.repeat(1)}${key}:`);
1817
Object.entries(valueConfig).forEach(([key, valueInternal]) => {
1918
// Lvl3: config properties
20-
this.localDisk.push(`${YAML_INDENT.repeat(2)}${key}: ${parseValue(valueInternal as string, config)}`);
19+
this.localDisk.push(`${YAML_INDENT.repeat(2)}${key}: ${parseValuetoSanitizeYamlValue(valueInternal as string, config)}`);
2120
});
2221
} else if (typeof valueConfig == "string") {
23-
this.localDisk.push(`${YAML_INDENT.repeat(1)}${key}: ${parseValue(escapeSpecialCharacters(valueConfig), config)}`);
22+
this.localDisk.push(`${YAML_INDENT.repeat(1)}${key}: ${parseValuetoSanitizeYamlValue(escapeSpecialCharacters(valueConfig), config)}`);
2423
} else {
2524
// Lvl2: config properties
26-
this.localDisk.push(`${YAML_INDENT.repeat(1)}${key}: ${parseValue(valueConfig, config)}`);
25+
this.localDisk.push(`${YAML_INDENT.repeat(1)}${key}: ${parseValuetoSanitizeYamlValue(valueConfig, config)}`);
2726
}
2827
});
2928
return this.goNext(handlerResponse);
3029
}
31-
}
32-
33-
function parseValue(value: string, localSettings: LocalSettings): string {
34-
return DataviewService.parseLiteral(value, InputType.MARKDOWN, localSettings).toString();
3530
}

0 commit comments

Comments
 (0)