Skip to content

Commit

Permalink
Merge branch 'main' into filtering-dates
Browse files Browse the repository at this point in the history
  • Loading branch information
Acylation authored Oct 31, 2023
2 parents 3e33033 + 6f03e76 commit f1387ee
Show file tree
Hide file tree
Showing 24 changed files with 1,020 additions and 50 deletions.
31 changes: 27 additions & 4 deletions src/lib/datasources/folder/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ export class FolderDataSource extends FrontMatterDataSource {

if (!this.project.dataSource.config.recursive) {
return folderContainsPath(projectPath, normalizedPath);
} else {
return folderContainsDeepPath(projectPath, normalizedPath);
}

return true;
}
}

Expand All @@ -60,7 +60,30 @@ export class FolderDataSource extends FrontMatterDataSource {
*/
function folderContainsPath(folderPath: string, filePath: string): boolean {
const fileElements = filePath.split("/").slice(0, -1);
const folderElement = folderPath.split("/").filter((el) => el);
const folderElements = folderPath.split("/").filter((el) => el);

return fileElements.join("/") === folderElements.join("/");
}

/**
* Returns whether a root folder contains a file path under a subfolder.
*
* Assumes both folder path and file path have been normalized.
*
* @param folderPath path to the root folder, e.g. Work
* @param filePath path to the file to test, e.g. Work/Meetings/Untitled.md
* @returns
*/
function folderContainsDeepPath(folderPath: string, filePath: string): boolean {
const fileElements = filePath.split("/").filter((el) => el);
const folderElements = folderPath.split("/").filter((el) => el);

if (fileElements.length <= folderElements.length) {
return false;
}

return fileElements.join("/") === folderElement.join("/");
return (
fileElements.slice(0, folderElements.length).join("/") ===
folderElements.join("/")
);
}
11 changes: 7 additions & 4 deletions src/lib/stores/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"boolean": "Checkbox",
"date": "Date",
"unknown": "Unknown data type",
"repeated": "Repeated field"
"repeated": "Repeated field",
"list": "List",
"tags": "Tags",
"Aliases": "Aliases"
},
"datasources": {
"folder": "Folder",
Expand Down Expand Up @@ -305,10 +308,10 @@
},
"include-fields": "Include fields",
"settings": {
"name": "画册设置",
"name": "Gallery settings",
"card-width": {
"name": "卡片宽度",
"description": "调整每张卡片的像素宽度。"
"name": "Card width",
"description": "Width of each card in pixels."
}
},
"empty": "This view is empty."
Expand Down
5 changes: 4 additions & 1 deletion src/lib/stores/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"boolean": "复选框",
"date": "日期",
"unknown": "未知",
"repeated": "周期"
"repeated": "周期",
"list": "列表",
"tags": "标签",
"aliases": "别名"
},
"datasources": {
"folder": "文件夹",
Expand Down
9 changes: 1 addition & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import isoWeek from "dayjs/plugin/isoWeek";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { either, task, taskEither } from "fp-ts";
import { pipe } from "fp-ts/lib/function";
import { Plugin, TFile, TFolder, WorkspaceLeaf, addIcon } from "obsidian";
import { Plugin, TFile, TFolder, WorkspaceLeaf } from "obsidian";
import "obsidian-dataview";
import { createDataRecord, createProject } from "src/lib/dataApi";
import { api } from "src/lib/stores/api";
Expand Down Expand Up @@ -48,13 +48,6 @@ export default class ProjectsPlugin extends Plugin {
this.activateView();
});

// Add an icon for text fields. Remove once Obsidian has a decent
// alternative.
addIcon(
"text",
`<g transform="matrix(1,0,0,1,2,2)"><path d="M20,32L28,32L28,24L41.008,24L30.72,72L20,72L20,80L52,80L52,72L42.992,72L53.28,24L68,24L68,32L76,32L76,16L20,16L20,32Z" /></g>`
);

this.registerView(
VIEW_TYPE_PROJECTS,
(leaf) => new ProjectsView(leaf, this)
Expand Down
11 changes: 11 additions & 0 deletions src/settings/base/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ export function isDateFilterOperator(
"is-on-and-before",
"is-on-and-after",
].includes(op);

export type ListFilterOperator = "has-any-of" | "has-all-of" | "has-none-of";

export function isListFilterOperator(
op: FilterOperator
): op is ListFilterOperator {
return ["has-any-of", "has-all-of", "has-none-of"].includes(op);
}

export type FilterOperator =
Expand All @@ -95,6 +102,7 @@ export type FilterOperator =
| NumberFilterOperator
| BooleanFilterOperator
| DateFilterOperator;
| ListFilterOperator;

export type FilterOperatorType = "unary" | "binary";

Expand All @@ -119,6 +127,9 @@ export const filterOperatorTypes: Record<FilterOperator, FilterOperatorType> = {
"is-after": "binary",
"is-on-and-before": "binary",
"is-on-and-after": "binary",
"has-any-of": "binary",
"has-all-of": "binary",
"has-none-of": "binary",
};

export interface FilterCondition {
Expand Down
46 changes: 46 additions & 0 deletions src/ui/app/filterFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ import {
isOptionalBoolean,
isOptionalDate,
} from "src/lib/dataframe/dataframe";
import { isOptionalList } from "src/lib/dataframe/dataframe";
import {
isBooleanFilterOperator,
isNumberFilterOperator,
isStringFilterOperator,
isDateFilterOperator,
isListFilterOperator,
type BaseFilterOperator,
type BooleanFilterOperator,
type FilterCondition,
type FilterDefinition,
type NumberFilterOperator,
type StringFilterOperator,
type DateFilterOperator,
type ListFilterOperator,
} from "src/settings/settings";

export function matchesCondition(
Expand All @@ -36,6 +39,7 @@ export function matchesCondition(
return baseFns[operator](value);
}


if (isOptionalString(value) && isStringFilterOperator(operator)) {
return stringFns[operator](value, cond.value);
} else if (isOptionalNumber(value) && isNumberFilterOperator(operator)) {
Expand All @@ -50,6 +54,34 @@ export function matchesCondition(
value,
cond.value ? dayjs(cond.value ?? "").toDate() : undefined
);

if (isOptionalList(value)) {
if (isListFilterOperator(operator)) {
return listFns[operator](
value ?? [],
cond.value ? JSON.parse(cond.value ?? "[]") : undefined
);
}
}

switch (typeof value) {
case "string":
if (isStringFilterOperator(operator)) {
return stringFns[operator](value, cond.value);
}
break;
case "number":
if (isNumberFilterOperator(operator)) {
return numberFns[operator](
value,
cond.value ? parseFloat(cond.value) : undefined
);
}
break;
case "boolean":
if (isBooleanFilterOperator(operator)) {
return booleanFns[operator](value);
}
}

return false;
Expand Down Expand Up @@ -132,4 +164,18 @@ export const dateFns: Record<
left && right ? left.getTime() <= right.getTime() : false,
"is-on-and-after": (left, right) =>
left && right ? left.getTime() >= right.getTime() : false,

export const listFns: Record<
ListFilterOperator,
(left: Optional<DataValue>[], right?: Optional<DataValue>[]) => boolean
> = {
"has-any-of": (left, right) => {
return right ? right.some((value) => left.includes(value)) : false;
},
"has-all-of": (left, right) => {
return right ? right.every((value) => left.includes(value)) : false;
},
"has-none-of": (left, right) => {
return !(right ? right.some((value) => left.includes(value)) : false);
},
};
11 changes: 11 additions & 0 deletions src/ui/app/toolbar/viewOptions/color/ColorOptions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
Checkbox,
DateInput,
} from "obsidian-svelte";
import { TagsInput } from "src/ui/components/TagsInput";
import HorizontalGroup from "src/ui/components/HorizontalGroup/HorizontalGroup.svelte";
import type { DataField } from "src/lib/dataframe/dataframe";
import {
filterOperatorTypes,
isNumberFilterOperator,
isStringFilterOperator,
isDateFilterOperator,
isListFilterOperator,
type ColorFilterDefinition,
type FilterOperator,
} from "src/settings/settings";
Expand Down Expand Up @@ -159,6 +161,15 @@
<DateInput
value={dayjs(rule.condition.value ?? "").toDate()}
on:blur={handleValueChange(i)}
{:else if isListFilterOperator(rule.condition.operator)}
<TagsInput
strict={true}
unique={true}
value={JSON.parse(rule.condition.value ?? "[]")}
on:change={(event) => {
filter = setValue(filter, i, event.detail);
onFilterChange(filter);
}}
/>
{/if}
{/if}
Expand Down
7 changes: 6 additions & 1 deletion src/ui/app/toolbar/viewOptions/color/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,12 @@ export function getOperatorsByField(field: DataField): Array<{
];

if (field.repeated) {
return baseOperators;
return [
...baseOperators,
{ label: "has any of", value: "has-any-of" },
{ label: "has all of", value: "has-all-of" },
{ label: "has none of", value: "has-none-of" },
];
}

switch (field.type) {
Expand Down
11 changes: 11 additions & 0 deletions src/ui/app/toolbar/viewOptions/filter/FilterOptions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
Checkbox,
// DateInput, //use native date input temporarily,
} from "obsidian-svelte";
import { TagsInput } from "src/ui/components/TagsInput";
import HorizontalGroup from "src/ui/components/HorizontalGroup/HorizontalGroup.svelte";
import type { DataField } from "src/lib/dataframe/dataframe";
import {
filterOperatorTypes,
isNumberFilterOperator,
isStringFilterOperator,
isDateFilterOperator,
isListFilterOperator,
type FilterDefinition,
type FilterOperator,
} from "src/settings/settings";
Expand Down Expand Up @@ -118,6 +120,15 @@
value={condition.value ?? ""}
on:blur={handleValueChange(i)}
max="2999-12-31"
{:else if isListFilterOperator(condition.operator)}
<TagsInput
strict={true}
unique={true}
value={JSON.parse(condition.value ?? "[]")}
on:change={(event) => {
filter = setValue(filter, i, event.detail);
onFilterChange(filter);
}}
/>
{/if}
{/if}
Expand Down
7 changes: 6 additions & 1 deletion src/ui/app/toolbar/viewOptions/filter/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,12 @@ export function getOperatorsByField(field: DataField): Array<{
];

if (field.repeated) {
return baseOperators;
return [
...baseOperators,
{ label: "has any of", value: "has-any-of" },
{ label: "has all of", value: "has-all-of" },
{ label: "has none of", value: "has-none-of" },
];
}

switch (field.type) {
Expand Down
Loading

0 comments on commit f1387ee

Please sign in to comment.