mirror of
https://github.com/decaf-dev/obsidian-vault-explorer.git
synced 2026-07-22 10:10:31 +00:00
Add date filter dropdown (#90)
* feat: change settings to support more filter rules * feat: add data options * chore: bump version * feat: handle optional types * style: move code * feat: delete old variable names * fix: handle valueData change * feat: add DatePropertyFilterType enum * feat: increase property filter select size to 160px * feat: add custom date * fix: use valueData for date input * fix: clear custom date on date value switch * refactor: rename to "select a property" * fix: don't accept number on input * feat: add placeholder for input * fix: fix updating of value input * feat: add assertion for date * feat: add new date filtering * feat: add other options
This commit is contained in:
parent
b84bccf379
commit
afdddc655c
25 changed files with 571 additions and 200 deletions
|
|
@ -27,7 +27,32 @@ export const moment = jest.fn((date: string, _formats: string[], _strict?: boole
|
|||
parsedDate.setUTCHours(hour, minute, second);
|
||||
return mockMoment;
|
||||
}),
|
||||
valueOf: jest.fn(() => parsedDate.getTime())
|
||||
valueOf: jest.fn(() => parsedDate.getTime()),
|
||||
isSame: jest.fn((other, unit) => {
|
||||
if (unit === 'day') {
|
||||
const otherDate = new Date(other);
|
||||
return (
|
||||
parsedDate.getUTCFullYear() === otherDate.getUTCFullYear() &&
|
||||
parsedDate.getUTCMonth() === otherDate.getUTCMonth() &&
|
||||
parsedDate.getUTCDate() === otherDate.getUTCDate()
|
||||
);
|
||||
}
|
||||
return parsedDate.getTime() === new Date(other).getTime();
|
||||
}),
|
||||
isBefore: jest.fn((other, unit) => {
|
||||
if (unit === 'day') {
|
||||
const otherDate = new Date(other);
|
||||
return parsedDate < otherDate && parsedDate.getUTCDate() !== otherDate.getUTCDate();
|
||||
}
|
||||
return parsedDate.getTime() < new Date(other).getTime();
|
||||
}),
|
||||
isAfter: jest.fn((other, unit) => {
|
||||
if (unit === 'day') {
|
||||
const otherDate = new Date(other);
|
||||
return parsedDate > otherDate && parsedDate.getUTCDate() !== otherDate.getUTCDate();
|
||||
}
|
||||
return parsedDate.getTime() > new Date(other).getTime();
|
||||
}),
|
||||
};
|
||||
return mockMoment;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "vault-explorer",
|
||||
"name": "Vault Explorer",
|
||||
"version": "1.8.1",
|
||||
"version": "1.9.0",
|
||||
"minAppVersion": "1.4.13",
|
||||
"description": "Explore your vault in visual format",
|
||||
"author": "DecafDev",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-vault-explorer",
|
||||
"version": "1.8.1",
|
||||
"version": "1.9.0",
|
||||
"description": "Explore your vault in visual format",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@ export const DEFAULT_SETTINGS: VaultExplorerPluginSettings = {
|
|||
onlyFavorites: false,
|
||||
timestamp: "all",
|
||||
sort: "file-name-asc",
|
||||
properties: {
|
||||
custom: {
|
||||
selectedGroupId: randomGroupId,
|
||||
groups:
|
||||
[
|
||||
{
|
||||
id: randomGroupId,
|
||||
name: "Group 1",
|
||||
filters: [],
|
||||
rules: [],
|
||||
isEnabled: true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
43
src/main.ts
43
src/main.ts
|
|
@ -3,7 +3,7 @@ import { Plugin, TAbstractFile, TFile, TFolder } from 'obsidian';
|
|||
import VaultExplorerView from './obsidian/vault-explorer-view';
|
||||
import VaultExplorerSettingsTab from './obsidian/vault-explorer-settings-tab';
|
||||
|
||||
import { PropertyFilter, PropertyFilterGroup, VaultExplorerPluginSettings, ViewType } from './types';
|
||||
import { VaultExplorerPluginSettings, ViewType } from './types';
|
||||
import { DEFAULT_SETTINGS, HOVER_LINK_SOURCE_ID, VAULT_EXPLORER_VIEW } from './constants';
|
||||
import _ from 'lodash';
|
||||
import EventManager from './event/event-manager';
|
||||
|
|
@ -17,10 +17,11 @@ import { VaultExplorerPluginSettings_1_0_1 } from './types/types-1.0.1';
|
|||
import { moveFocus } from './focus-utils';
|
||||
import { VaultExplorerPluginSettings_1_2_0 } from './types/types-1.2.0';
|
||||
import { VaultExplorerPluginSettings_1_2_1 } from './types/types-1.2.1';
|
||||
import { VaultExplorerPluginSettings_1_5_0 } from './types/types-1.5.0';
|
||||
import { PropertyFilterGroup_1_5_0, PropertyFilter_1_5_0, VaultExplorerPluginSettings_1_5_0 } from './types/types-1.5.0';
|
||||
import { VaultExplorerPluginSettings_1_6_0 } from './types/types-1.6.0';
|
||||
import { loadDeviceId } from './svelte/shared/services/device-id-utils';
|
||||
import License from './svelte/shared/services/license';
|
||||
import { VaultExplorerPluginSettings_1_8_1 } from './types/types-1.8.1';
|
||||
|
||||
export default class VaultExplorerPlugin extends Plugin {
|
||||
settings: VaultExplorerPluginSettings = DEFAULT_SETTINGS;
|
||||
|
|
@ -199,8 +200,8 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
const typedData = (data as unknown) as VaultExplorerPluginSettings_1_2_1;
|
||||
const groups = typedData.filters.properties.groups;
|
||||
|
||||
const updatedGroups: PropertyFilterGroup[] = groups.map(group => {
|
||||
const updatedFilters: PropertyFilter[] = group.filters.map(filter => {
|
||||
const updatedGroups: PropertyFilterGroup_1_5_0[] = groups.map(group => {
|
||||
const updatedFilters: PropertyFilter_1_5_0[] = group.filters.map(filter => {
|
||||
return {
|
||||
...filter,
|
||||
type: filter.type as any,
|
||||
|
|
@ -243,7 +244,7 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
if (isVersionLessThan(settingsVersion, "1.6.1")) {
|
||||
console.log("Upgrading settings from version 1.6.0 to 1.6.1");
|
||||
const typedData = (data as unknown) as VaultExplorerPluginSettings_1_6_0;
|
||||
const newData: VaultExplorerPluginSettings = {
|
||||
const newData: VaultExplorerPluginSettings_1_8_1 = {
|
||||
...typedData,
|
||||
properties: {
|
||||
...typedData.properties,
|
||||
|
|
@ -253,6 +254,38 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
}
|
||||
data = newData as unknown as Record<string, unknown>;
|
||||
}
|
||||
|
||||
if (isVersionLessThan(settingsVersion, "1.9.0")) {
|
||||
console.log("Upgrading settings from version 1.8.1 to 1.9.0");
|
||||
const typedData = (data as unknown) as VaultExplorerPluginSettings_1_8_1;
|
||||
const newData: VaultExplorerPluginSettings = {
|
||||
...typedData,
|
||||
filters: {
|
||||
...typedData.filters,
|
||||
custom: {
|
||||
selectedGroupId: typedData.filters.properties.selectedGroupId,
|
||||
groups: typedData.filters.properties.groups.map(group => {
|
||||
const rules = group.filters.map(filter => {
|
||||
return {
|
||||
...filter,
|
||||
valueData: "",
|
||||
type: filter.type as any
|
||||
}
|
||||
});
|
||||
return {
|
||||
...group,
|
||||
rules
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
delete (newData.filters as any).properties;
|
||||
for (const group of newData.filters.custom.groups as any) {
|
||||
delete group.filters;
|
||||
}
|
||||
data = newData as unknown as Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts">
|
||||
import { PropertyFilterGroup } from "src/types";
|
||||
import { FilterGroup } from "src/types";
|
||||
import GroupTag from "./group-tag.svelte";
|
||||
import Stack from "src/svelte/shared/components/stack.svelte";
|
||||
|
||||
export let groups: PropertyFilterGroup[] = [];
|
||||
export let groups: FilterGroup[] = [];
|
||||
</script>
|
||||
|
||||
<div class="vault-explorer-group-tag-list">
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import { FrontMatterCache, Menu, TFile, TFolder } from "obsidian";
|
||||
import PropertiesFilterModal from "src/obsidian/properties-filter-modal";
|
||||
import {
|
||||
PropertyFilterGroup,
|
||||
FilterGroup,
|
||||
SortFilter,
|
||||
TimestampFilter,
|
||||
ViewType,
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
let onlyFavorites: boolean = false;
|
||||
let viewOrder: ViewType[] = [];
|
||||
let currentView: ViewType = ViewType.GRID;
|
||||
let propertyFilterGroups: PropertyFilterGroup[] = [];
|
||||
let propertyFilterGroups: FilterGroup[] = [];
|
||||
let selectedPropertyFilterGroupId: string = "";
|
||||
|
||||
let frontmatterCache: Record<string, FrontMatterCache | undefined> = {};
|
||||
|
|
@ -112,16 +112,16 @@
|
|||
onlyFavorites = plugin.settings.filters.onlyFavorites;
|
||||
currentView = plugin.settings.views.currentView;
|
||||
viewOrder = plugin.settings.views.order;
|
||||
propertyFilterGroups = plugin.settings.filters.properties.groups;
|
||||
propertyFilterGroups = plugin.settings.filters.custom.groups;
|
||||
selectedPropertyFilterGroupId =
|
||||
plugin.settings.filters.properties.selectedGroupId;
|
||||
plugin.settings.filters.custom.selectedGroupId;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
function handlePropertiesFilterUpdate() {
|
||||
propertyFilterGroups = plugin.settings.filters.properties.groups;
|
||||
propertyFilterGroups = plugin.settings.filters.custom.groups;
|
||||
selectedPropertyFilterGroupId =
|
||||
plugin.settings.filters.properties.selectedGroupId;
|
||||
plugin.settings.filters.custom.selectedGroupId;
|
||||
}
|
||||
|
||||
EventManager.getInstance().on(
|
||||
|
|
@ -387,8 +387,8 @@
|
|||
plugin.settings.filters.onlyFavorites = onlyFavorites;
|
||||
plugin.settings.views.order = viewOrder;
|
||||
plugin.settings.views.currentView = currentView;
|
||||
plugin.settings.filters.properties.groups = propertyFilterGroups;
|
||||
plugin.settings.filters.properties.selectedGroupId =
|
||||
plugin.settings.filters.custom.groups = propertyFilterGroups;
|
||||
plugin.settings.filters.custom.selectedGroupId =
|
||||
selectedPropertyFilterGroupId;
|
||||
await plugin.saveSettings();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
import { FrontMatterCache } from "obsidian";
|
||||
import { PropertyFilter, PropertyFilterGroup } from "src/types";
|
||||
import { FilterRule, FilterGroup, DatePropertyFilterValue } from "src/types";
|
||||
import { loadPropertyValue } from "src/svelte/shared/services/load-property-value";
|
||||
import { matchTextFilter } from "./match-text-filter";
|
||||
import { matchCheckboxFilter } from "./match-checkbox-filter";
|
||||
import { matchListFilter } from "./match-list-filter";
|
||||
import { matchDateFilter } from "./match-date-filter";
|
||||
import { matchNumberFilter } from "./match-number-filter";
|
||||
import { getDateDaysAgo, getDateDaysAhead } from "src/svelte/shared/services/time-utils";
|
||||
|
||||
export const filterByGroups = (frontmatter: FrontMatterCache | undefined, groups: PropertyFilterGroup[]) => {
|
||||
export const filterByGroups = (frontmatter: FrontMatterCache | undefined, groups: FilterGroup[]) => {
|
||||
return groups.every((group) => {
|
||||
if (!group.isEnabled) return true;
|
||||
return filterByGroup(frontmatter, group);
|
||||
});
|
||||
}
|
||||
|
||||
const filterByGroup = (frontmatter: FrontMatterCache | undefined, group: PropertyFilterGroup) => {
|
||||
const filterByGroup = (frontmatter: FrontMatterCache | undefined, group: FilterGroup) => {
|
||||
let result: boolean | null = null;
|
||||
|
||||
group.filters.forEach((filter, i) => {
|
||||
group.rules.forEach((filter, i) => {
|
||||
if (!filter.isEnabled) return;
|
||||
|
||||
const doesMatch = filterByRule(frontmatter, filter);
|
||||
|
|
@ -35,11 +36,11 @@ const filterByGroup = (frontmatter: FrontMatterCache | undefined, group: Propert
|
|||
return result ?? true;
|
||||
}
|
||||
|
||||
const filterByRule = (frontmatter: FrontMatterCache | undefined, filter: PropertyFilter) => {
|
||||
const { propertyName, condition, value, type, matchWhenPropertyDNE } = filter;
|
||||
if (propertyName === "") return true;
|
||||
const filterByRule = (frontmatter: FrontMatterCache | undefined, filter: FilterRule) => {
|
||||
const { condition, value, type, matchWhenPropertyDNE } = filter;
|
||||
|
||||
if (type === "text") {
|
||||
const { propertyName } = filter;
|
||||
let propertyValue = loadPropertyValue<string>(frontmatter, propertyName, type);
|
||||
if (propertyValue) {
|
||||
propertyValue = propertyValue.toLowerCase().trim();
|
||||
|
|
@ -49,12 +50,14 @@ const filterByRule = (frontmatter: FrontMatterCache | undefined, filter: Propert
|
|||
const doesMatch = matchTextFilter(propertyValue, compare, condition, matchWhenPropertyDNE);
|
||||
return doesMatch;
|
||||
} else if (type === "number") {
|
||||
const { propertyName } = filter;
|
||||
const propertyValue = loadPropertyValue<number>(frontmatter, propertyName, type);
|
||||
const compare = parseFloat(value.trim());
|
||||
|
||||
const doesMatch = matchNumberFilter(propertyValue, compare, condition, matchWhenPropertyDNE);
|
||||
return doesMatch;
|
||||
} else if (type === "checkbox") {
|
||||
const { propertyName } = filter;
|
||||
const propertyValue = loadPropertyValue<boolean>(frontmatter, propertyName, type);
|
||||
|
||||
let compare = null;
|
||||
|
|
@ -67,11 +70,30 @@ const filterByRule = (frontmatter: FrontMatterCache | undefined, filter: Propert
|
|||
const doesMatch = matchCheckboxFilter(propertyValue, compare, condition, matchWhenPropertyDNE);
|
||||
return doesMatch;
|
||||
} else if (type === "date" || type === "datetime") {
|
||||
const { propertyName, valueData } = filter;
|
||||
const propertyValue = loadPropertyValue<string>(frontmatter, propertyName, type);
|
||||
|
||||
const doesMatch = matchDateFilter(propertyValue, value, condition, matchWhenPropertyDNE);
|
||||
let compare = valueData;
|
||||
if (value === DatePropertyFilterValue.TODAY) {
|
||||
compare = getDateDaysAgo(0);
|
||||
} else if (value === DatePropertyFilterValue.YESTERDAY) {
|
||||
compare = getDateDaysAgo(1);
|
||||
} else if (value === DatePropertyFilterValue.TOMORROW) {
|
||||
compare = getDateDaysAhead(1);
|
||||
} else if (value === DatePropertyFilterValue.ONE_WEEK_AGO) {
|
||||
compare = getDateDaysAgo(7);
|
||||
} else if (value === DatePropertyFilterValue.ONE_WEEK_FROM_NOW) {
|
||||
compare = getDateDaysAhead(7);
|
||||
} else if (value === DatePropertyFilterValue.ONE_MONTH_AGO) {
|
||||
compare = getDateDaysAgo(30);
|
||||
} else if (value === DatePropertyFilterValue.ONE_MONTH_FROM_NOW) {
|
||||
compare = getDateDaysAhead(30);
|
||||
}
|
||||
|
||||
const doesMatch = matchDateFilter(propertyValue, compare, condition, matchWhenPropertyDNE);
|
||||
return doesMatch;
|
||||
} else if (type === "list") {
|
||||
const { propertyName } = filter;
|
||||
let propertyValue = loadPropertyValue<string[]>(frontmatter, propertyName, type);
|
||||
if (propertyValue) {
|
||||
propertyValue = propertyValue.map((v) => v.toLowerCase().trim());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getEndOfDayMillis, getStartOfDayMillis, getTimeMillis, isDateSupported } from "src/svelte/shared/services/time-utils";
|
||||
import { getMomentDate, isDateSupported } from "src/svelte/shared/services/time-utils";
|
||||
import { DateFilterCondition } from "src/types";
|
||||
|
||||
export const matchDateFilter = (
|
||||
|
|
@ -8,40 +8,50 @@ export const matchDateFilter = (
|
|||
matchIfNull: boolean
|
||||
) => {
|
||||
if (propertyValue) {
|
||||
console.assert(isDateSupported(propertyValue), `Date filter propertyValue ${propertyValue} must be supported date format`);
|
||||
console.assert(isDateSupported(propertyValue), `DateFilter propertyValue "${propertyValue}" must be supported date format`);
|
||||
}
|
||||
console.assert(isDateSupported(compare), `DateFilter compare "${compare}" must be supported date format`);
|
||||
|
||||
switch (condition) {
|
||||
case DateFilterCondition.IS: {
|
||||
if (propertyValue === null) return matchIfNull;
|
||||
if (!isDateSupported(propertyValue)) return true;
|
||||
|
||||
const propertyValueTime = getTimeMillis(propertyValue);
|
||||
const dayStartTime = getStartOfDayMillis(compare);
|
||||
const dayEndTime = getEndOfDayMillis(compare);
|
||||
|
||||
return (
|
||||
propertyValueTime >= dayStartTime &&
|
||||
propertyValueTime <= dayEndTime
|
||||
);
|
||||
const propertyValueDate = getMomentDate(propertyValue);
|
||||
const compareDate = getMomentDate(compare);
|
||||
return propertyValueDate.isSame(compareDate, "day");
|
||||
}
|
||||
|
||||
case DateFilterCondition.IS_AFTER: {
|
||||
if (propertyValue === null) return matchIfNull;
|
||||
if (!isDateSupported(propertyValue)) return true;
|
||||
|
||||
const propertyValueTime = getTimeMillis(propertyValue);
|
||||
const dayEndTime = getEndOfDayMillis(compare);
|
||||
return propertyValueTime > dayEndTime;
|
||||
const propertyValueDate = getMomentDate(propertyValue);
|
||||
const compareDate = getMomentDate(compare);
|
||||
return propertyValueDate.isAfter(compareDate, "day");
|
||||
}
|
||||
|
||||
case DateFilterCondition.IS_ON_OR_AFTER: {
|
||||
if (propertyValue === null) return matchIfNull;
|
||||
|
||||
const propertyValueDate = getMomentDate(propertyValue);
|
||||
const compareDate = getMomentDate(compare);
|
||||
return propertyValueDate.isAfter(compareDate, "day") || propertyValueDate.isSame(compareDate, "day");
|
||||
}
|
||||
|
||||
|
||||
case DateFilterCondition.IS_BEFORE: {
|
||||
if (propertyValue === null) return matchIfNull;
|
||||
if (!isDateSupported(propertyValue)) return true;
|
||||
|
||||
const propertyValueTime = getTimeMillis(propertyValue);
|
||||
const dayStartTime = getStartOfDayMillis(compare);
|
||||
return propertyValueTime < dayStartTime;
|
||||
const propertyValueDate = getMomentDate(propertyValue);
|
||||
const compareDate = getMomentDate(compare);
|
||||
return propertyValueDate.isBefore(compareDate, "day");
|
||||
}
|
||||
|
||||
case DateFilterCondition.IS_ON_OR_BEFORE: {
|
||||
if (propertyValue === null) return matchIfNull;
|
||||
|
||||
const propertyValueDate = getMomentDate(propertyValue);
|
||||
const compareDate = getMomentDate(compare);
|
||||
return propertyValueDate.isBefore(compareDate, "day") || propertyValueDate.isSame(compareDate, "day");
|
||||
}
|
||||
|
||||
case DateFilterCondition.EXISTS:
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { FrontMatterCache, TFile } from "obsidian";
|
||||
import { PropertyType, VaultExplorerPluginSettings } from "src/types";
|
||||
import { FilterRuleType, VaultExplorerPluginSettings } from "src/types";
|
||||
import { MarkdownFileRenderData } from "../types";
|
||||
import { getTimeMillis, isDateSupported } from "../../shared/services/time-utils";
|
||||
import Logger from "js-logger";
|
||||
import { loadPropertyValue } from "src/svelte/shared/services/load-property-value";
|
||||
|
||||
export const formatFileDataForRender = (settings: VaultExplorerPluginSettings, file: TFile, frontmatter: FrontMatterCache | undefined,): MarkdownFileRenderData => {
|
||||
const tags: string[] | null = loadPropertyValue<string[]>(frontmatter, "tags", PropertyType.LIST);
|
||||
const tags: string[] | null = loadPropertyValue<string[]>(frontmatter, "tags", FilterRuleType.LIST);
|
||||
|
||||
const {
|
||||
createdDate: createdDateProp,
|
||||
|
|
@ -18,14 +18,14 @@ export const formatFileDataForRender = (settings: VaultExplorerPluginSettings, f
|
|||
custom3: custom3Prop,
|
||||
} = settings.properties;
|
||||
|
||||
const url: string | null = loadPropertyValue<string>(frontmatter, urlProp, PropertyType.TEXT);
|
||||
const favorite: boolean | null = loadPropertyValue<boolean>(frontmatter, favoriteProp, PropertyType.CHECKBOX);
|
||||
const creationDate: string | null = loadPropertyValue<string>(frontmatter, createdDateProp, PropertyType.DATE || PropertyType.DATETIME);
|
||||
const modifiedDate: string | null = loadPropertyValue<string>(frontmatter, modifiedDateProp, PropertyType.DATE || PropertyType.DATETIME);
|
||||
const url: string | null = loadPropertyValue<string>(frontmatter, urlProp, FilterRuleType.TEXT);
|
||||
const favorite: boolean | null = loadPropertyValue<boolean>(frontmatter, favoriteProp, FilterRuleType.CHECKBOX);
|
||||
const creationDate: string | null = loadPropertyValue<string>(frontmatter, createdDateProp, FilterRuleType.DATE || FilterRuleType.DATETIME);
|
||||
const modifiedDate: string | null = loadPropertyValue<string>(frontmatter, modifiedDateProp, FilterRuleType.DATE || FilterRuleType.DATETIME);
|
||||
|
||||
const custom1: string | null = loadPropertyValue<string>(frontmatter, custom1Prop, PropertyType.TEXT);
|
||||
const custom2: string | null = loadPropertyValue<string>(frontmatter, custom2Prop, PropertyType.TEXT);
|
||||
const custom3: string | null = loadPropertyValue<string>(frontmatter, custom3Prop, PropertyType.TEXT);
|
||||
const custom1: string | null = loadPropertyValue<string>(frontmatter, custom1Prop, FilterRuleType.TEXT);
|
||||
const custom2: string | null = loadPropertyValue<string>(frontmatter, custom2Prop, FilterRuleType.TEXT);
|
||||
const custom3: string | null = loadPropertyValue<string>(frontmatter, custom3Prop, FilterRuleType.TEXT);
|
||||
|
||||
let createdMillis = file.stat.ctime;
|
||||
if (creationDate != null) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,28 @@
|
|||
import { CheckboxFilterCondition, DateFilterCondition, FilterCondition, ListFilterCondition, NumberFilterCondition, TextFilterCondition } from "src/types";
|
||||
import { CheckboxFilterCondition, DateFilterCondition, DatePropertyFilterValue, FilterCondition, ListFilterCondition, NumberFilterCondition, TextFilterCondition } from "src/types";
|
||||
|
||||
export const getDisplayNameForDatePropertyFilterValue = (value: DatePropertyFilterValue) => {
|
||||
switch (value) {
|
||||
case DatePropertyFilterValue.TODAY:
|
||||
return "today";
|
||||
case DatePropertyFilterValue.TOMORROW:
|
||||
return "tomorrow";
|
||||
case DatePropertyFilterValue.YESTERDAY:
|
||||
return "yesterday";
|
||||
case DatePropertyFilterValue.ONE_WEEK_AGO:
|
||||
return "one week ago";
|
||||
case DatePropertyFilterValue.ONE_WEEK_FROM_NOW:
|
||||
return "one week from now";
|
||||
case DatePropertyFilterValue.ONE_MONTH_AGO:
|
||||
return "one month ago";
|
||||
case DatePropertyFilterValue.ONE_MONTH_FROM_NOW:
|
||||
return "one month from now";
|
||||
case DatePropertyFilterValue.CUSTOM:
|
||||
return "custom";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const getDisplayNameForFilterCondition = (type: FilterCondition) => {
|
||||
switch (type) {
|
||||
|
|
@ -47,6 +71,10 @@ export const getDisplayNameForFilterCondition = (type: FilterCondition) => {
|
|||
return "is after";
|
||||
case DateFilterCondition.IS_BEFORE:
|
||||
return "is before";
|
||||
case DateFilterCondition.IS_ON_OR_AFTER:
|
||||
return "is on or after";
|
||||
case DateFilterCondition.IS_ON_OR_BEFORE:
|
||||
return "is on or before";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
import IconButton from "src/svelte/shared/components/icon-button.svelte";
|
||||
import Stack from "src/svelte/shared/components/stack.svelte";
|
||||
|
||||
import { PropertyFilterGroup } from "src/types";
|
||||
import { FilterGroup } from "src/types";
|
||||
import PropertyFilterList from "./property-filter-list.svelte";
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
import Spacer from "src/svelte/shared/components/spacer.svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let selectedGroup: PropertyFilterGroup;
|
||||
export let selectedGroup: FilterGroup;
|
||||
|
||||
function handleAddFilterClick() {
|
||||
const newFilter = createPropertyFilter();
|
||||
|
|
@ -34,14 +34,15 @@
|
|||
</div>
|
||||
<Divider borderWidth="1px" />
|
||||
<div class="vault-explorer-group-edit-view__body">
|
||||
{#if selectedGroup.filters.length > 0}
|
||||
{#if selectedGroup.rules.length > 0}
|
||||
<PropertyFilterList
|
||||
filters={selectedGroup.filters}
|
||||
filters={selectedGroup.rules}
|
||||
on:filterConditionChange
|
||||
on:filterTypeChange
|
||||
on:filterPropertyNameChange
|
||||
on:filterOperatorChange
|
||||
on:filterValueChange
|
||||
on:filterValueDataChange
|
||||
on:filterToggle
|
||||
on:filterDeleteClick
|
||||
on:filterMatchWhenPropertyDNEChange
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script lang="ts">
|
||||
import IconButton from "src/svelte/shared/components/icon-button.svelte";
|
||||
import Stack from "src/svelte/shared/components/stack.svelte";
|
||||
import { PropertyFilterGroup } from "src/types";
|
||||
import { FilterGroup } from "src/types";
|
||||
|
||||
export let groups: PropertyFilterGroup[];
|
||||
export let selectedGroup: PropertyFilterGroup | undefined;
|
||||
export let groups: FilterGroup[];
|
||||
export let selectedGroup: FilterGroup | undefined;
|
||||
|
||||
let listContainerRef: HTMLDivElement | null;
|
||||
let previousLength = 0;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts">
|
||||
import Stack from "src/svelte/shared/components/stack.svelte";
|
||||
import PropertyFilter from "./property-filter.svelte";
|
||||
import { PropertyFilter as PropertyFilterType } from "src/types";
|
||||
import { FilterRule, FilterRuleType } from "src/types";
|
||||
|
||||
export let filters: PropertyFilterType[] = [];
|
||||
export let filters: FilterRule[] = [];
|
||||
</script>
|
||||
|
||||
<Stack direction="column" spacing="md" width="100%">
|
||||
|
|
@ -11,12 +11,22 @@
|
|||
<PropertyFilter
|
||||
{index}
|
||||
id={filter.id}
|
||||
{...filter.type === FilterRuleType.TEXT ||
|
||||
filter.type === FilterRuleType.NUMBER ||
|
||||
filter.type === FilterRuleType.LIST ||
|
||||
filter.type === FilterRuleType.CHECKBOX ||
|
||||
filter.type === FilterRuleType.DATE ||
|
||||
filter.type === FilterRuleType.DATETIME
|
||||
? { propertyName: filter.propertyName }
|
||||
: { propertyName: null }}
|
||||
operator={filter.operator}
|
||||
value={filter.value}
|
||||
{...filter.type === FilterRuleType.DATE
|
||||
? { valueData: filter.valueData }
|
||||
: { valueData: null }}
|
||||
condition={filter.condition}
|
||||
matchWhenPropertyDNE={filter.matchWhenPropertyDNE}
|
||||
type={filter.type}
|
||||
propertyName={filter.propertyName}
|
||||
isEnabled={filter.isEnabled}
|
||||
on:groupChange
|
||||
on:filterConditionChange
|
||||
|
|
@ -24,6 +34,7 @@
|
|||
on:filterOperatorChange
|
||||
on:filterPropertyNameChange
|
||||
on:filterValueChange
|
||||
on:filterValueDataChange
|
||||
on:filterToggle
|
||||
on:filterDeleteClick
|
||||
on:filterMatchWhenPropertyDNEChange
|
||||
|
|
|
|||
|
|
@ -9,18 +9,23 @@
|
|||
FilterOperator,
|
||||
ListFilterCondition,
|
||||
NumberFilterCondition,
|
||||
PropertyType,
|
||||
FilterRuleType,
|
||||
TextFilterCondition,
|
||||
DatePropertyFilterValue,
|
||||
} from "src/types";
|
||||
import { getDisplayNameForFilterCondition } from "./utils";
|
||||
import {
|
||||
getDisplayNameForDatePropertyFilterValue,
|
||||
getDisplayNameForFilterCondition,
|
||||
} from "./display-name-utils";
|
||||
import { getAllObsidianProperties } from "src/obsidian/utils";
|
||||
|
||||
export let index: number;
|
||||
export let id: string;
|
||||
export let propertyName: string;
|
||||
export let type: PropertyType;
|
||||
export let propertyName: string | null;
|
||||
export let type: FilterRuleType;
|
||||
export let operator: FilterOperator;
|
||||
export let value: string;
|
||||
export let valueData: string | null;
|
||||
export let condition: FilterCondition;
|
||||
export let isEnabled: boolean;
|
||||
export let matchWhenPropertyDNE: boolean;
|
||||
|
|
@ -65,6 +70,11 @@
|
|||
dispatch("filterValueChange", { id, value });
|
||||
}
|
||||
|
||||
function handleValueDataChange(e: Event) {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
dispatch("filterValueDataChange", { id, value });
|
||||
}
|
||||
|
||||
function handleOperatorChange(e: Event) {
|
||||
const value = (e.target as HTMLSelectElement).value;
|
||||
dispatch("filterOperatorChange", { id, operator: value });
|
||||
|
|
@ -95,7 +105,7 @@
|
|||
return prop.type === type;
|
||||
});
|
||||
|
||||
function findFilterConditions(type: PropertyType): FilterCondition[] {
|
||||
function findFilterConditions(type: FilterRuleType): FilterCondition[] {
|
||||
if (type === "text") {
|
||||
return Object.values(TextFilterCondition);
|
||||
} else if (type === "number") {
|
||||
|
|
@ -125,16 +135,18 @@
|
|||
</select>
|
||||
{/if}
|
||||
<select value={type} on:change={handleTypeChange}>
|
||||
{#each Object.values(PropertyType) as type}
|
||||
{#each Object.values(FilterRuleType) as type}
|
||||
<option value={type}>{type}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<select value={propertyName} on:change={handlePropertyNameChange}>
|
||||
<option value="">Select a property</option>
|
||||
{#each filteredObsidianProperties as prop (prop.name)}
|
||||
<option value={prop.name}>{prop.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if propertyName != null}
|
||||
<select value={propertyName} on:change={handlePropertyNameChange}>
|
||||
<option value="">select a property</option>
|
||||
{#each filteredObsidianProperties as prop (prop.name)}
|
||||
<option value={prop.name}>{prop.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
<select value={condition} on:change={handleConditionChange}>
|
||||
{#each filterConditions as condition}
|
||||
<option value={condition}>
|
||||
|
|
@ -142,14 +154,37 @@
|
|||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if type == PropertyType.CHECKBOX && condition !== TextFilterCondition.EXISTS && condition !== TextFilterCondition.DOES_NOT_EXIST}
|
||||
{#if type === FilterRuleType.CHECKBOX && condition !== CheckboxFilterCondition.EXISTS && condition !== CheckboxFilterCondition.DOES_NOT_EXIST}
|
||||
<select {value} on:change={handleValueChange}>
|
||||
<option value="true">true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
{/if}
|
||||
{#if type !== PropertyType.CHECKBOX && condition !== TextFilterCondition.EXISTS && condition !== TextFilterCondition.DOES_NOT_EXIST}
|
||||
<input type="text" {value} on:change={handleValueChange} />
|
||||
{#if (type === FilterRuleType.DATE || type === FilterRuleType.DATETIME) && condition !== DateFilterCondition.EXISTS && condition !== DateFilterCondition.DOES_NOT_EXIST}
|
||||
<select {value} on:change={handleValueChange}>
|
||||
{#each Object.values(DatePropertyFilterValue) as value}
|
||||
<option {value}>
|
||||
{getDisplayNameForDatePropertyFilterValue(value)}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
{#if type !== FilterRuleType.CHECKBOX && type !== FilterRuleType.DATE && type !== FilterRuleType.DATETIME && condition !== TextFilterCondition.EXISTS && condition !== TextFilterCondition.DOES_NOT_EXIST}
|
||||
<input
|
||||
type={type === FilterRuleType.NUMBER ? "number" : "text"}
|
||||
placeholder={type === FilterRuleType.LIST
|
||||
? "item1,item2,item3"
|
||||
: "Enter a value"}
|
||||
{value}
|
||||
on:change={handleValueChange}
|
||||
/>
|
||||
{/if}
|
||||
{#if (type === FilterRuleType.DATE || type === FilterRuleType.DATETIME) && value == DatePropertyFilterValue.CUSTOM && condition !== TextFilterCondition.EXISTS && condition !== TextFilterCondition.DOES_NOT_EXIST}
|
||||
<input
|
||||
type="date"
|
||||
value={valueData}
|
||||
on:change={handleValueDataChange}
|
||||
/>
|
||||
{/if}
|
||||
{#if condition !== TextFilterCondition.EXISTS && condition !== TextFilterCondition.DOES_NOT_EXIST}
|
||||
<input
|
||||
|
|
@ -180,6 +215,6 @@
|
|||
}
|
||||
|
||||
.vault-explorer-property-filter select {
|
||||
max-width: 150px;
|
||||
max-width: 160px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
import {
|
||||
CheckboxFilterCondition,
|
||||
DateFilterCondition,
|
||||
FilterCondition,
|
||||
ListFilterCondition,
|
||||
NumberFilterCondition,
|
||||
PropertyFilterGroup,
|
||||
FilterGroup,
|
||||
TextFilterCondition,
|
||||
FilterRuleType,
|
||||
DatePropertyFilterValue,
|
||||
} from "src/types";
|
||||
import { generateRandomId } from "../shared/services/random";
|
||||
import GroupEditView from "./components/group-edit-view.svelte";
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
import Divider from "../shared/components/divider.svelte";
|
||||
|
||||
let selectedGroupId: string = "";
|
||||
let groups: PropertyFilterGroup[] = [];
|
||||
let groups: FilterGroup[] = [];
|
||||
let plugin: VaultExplorerPlugin;
|
||||
|
||||
$: selectedGroup = groups.find((group) => group.id === selectedGroupId);
|
||||
|
|
@ -28,16 +29,16 @@
|
|||
$: groups, selectedGroupId, saveSettings();
|
||||
|
||||
async function saveSettings() {
|
||||
plugin.settings.filters.properties.groups = groups;
|
||||
plugin.settings.filters.properties.selectedGroupId = selectedGroupId;
|
||||
plugin.settings.filters.custom.groups = groups;
|
||||
plugin.settings.filters.custom.selectedGroupId = selectedGroupId;
|
||||
await plugin.saveSettings();
|
||||
}
|
||||
|
||||
store.plugin.subscribe((p) => {
|
||||
plugin = p;
|
||||
|
||||
groups = plugin.settings.filters.properties.groups;
|
||||
selectedGroupId = plugin.settings.filters.properties.selectedGroupId;
|
||||
groups = plugin.settings.filters.custom.groups;
|
||||
selectedGroupId = plugin.settings.filters.custom.selectedGroupId;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
|
|
@ -52,10 +53,10 @@
|
|||
}
|
||||
|
||||
function handleAddGroupClick() {
|
||||
const newGroup: PropertyFilterGroup = {
|
||||
const newGroup: FilterGroup = {
|
||||
id: generateRandomId(),
|
||||
name: `Group ${groups.length + 1}`,
|
||||
filters: [createPropertyFilter()],
|
||||
rules: [createPropertyFilter()],
|
||||
isEnabled: groups.length === 0,
|
||||
};
|
||||
|
||||
|
|
@ -88,7 +89,7 @@
|
|||
|
||||
const newGroups = groups.map((group) =>
|
||||
group.id === selectedGroupId
|
||||
? { ...group, filters: [...group.filters, filter] }
|
||||
? { ...group, rules: [...group.rules, filter] }
|
||||
: group,
|
||||
);
|
||||
|
||||
|
|
@ -112,10 +113,8 @@
|
|||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id
|
||||
? { ...filter, condition }
|
||||
: filter,
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id ? { ...rule, condition } : rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -167,9 +166,7 @@
|
|||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.filter(
|
||||
(filter) => filter.id !== id,
|
||||
),
|
||||
rules: group.rules.filter((rule) => rule.id !== id),
|
||||
}
|
||||
: group,
|
||||
);
|
||||
|
|
@ -184,10 +181,10 @@
|
|||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id
|
||||
? { ...filter, propertyName: name }
|
||||
: filter,
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id
|
||||
? { ...rule, propertyName: name }
|
||||
: rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -203,10 +200,10 @@
|
|||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id
|
||||
? { ...filter, isEnabled: !filter.isEnabled }
|
||||
: filter,
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id
|
||||
? { ...rule, isEnabled: !rule.isEnabled }
|
||||
: rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -222,8 +219,8 @@
|
|||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id ? { ...filter, operator } : filter,
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id ? { ...rule, operator } : rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -235,7 +232,7 @@
|
|||
function handleFilterTypeChange(e: CustomEvent) {
|
||||
const { id, type } = e.detail;
|
||||
|
||||
let newCondition: FilterCondition;
|
||||
let newCondition: any;
|
||||
let newValue = "";
|
||||
if (type === "text") {
|
||||
newCondition = TextFilterCondition.IS;
|
||||
|
|
@ -247,25 +244,37 @@
|
|||
} else if (type === "list") {
|
||||
newCondition = ListFilterCondition.CONTAINS;
|
||||
} else if (type === "date" || type === "datetime") {
|
||||
newValue = DatePropertyFilterValue.TODAY;
|
||||
newCondition = DateFilterCondition.IS;
|
||||
} else {
|
||||
throw new Error(`Unhandled filter type: ${type}`);
|
||||
}
|
||||
|
||||
const newGroups: PropertyFilterGroup[] = groups.map((group) =>
|
||||
const newGroups: FilterGroup[] = groups.map((group) =>
|
||||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id
|
||||
? {
|
||||
...filter,
|
||||
...rule,
|
||||
type,
|
||||
name: "",
|
||||
...(type === FilterRuleType.TEXT ||
|
||||
type === FilterRuleType.NUMBER ||
|
||||
type === FilterRuleType.LIST ||
|
||||
type === FilterRuleType.CHECKBOX ||
|
||||
type === FilterRuleType.DATE ||
|
||||
type === FilterRuleType.DATETIME
|
||||
? { propertyName: "" }
|
||||
: {}),
|
||||
condition: newCondition,
|
||||
value: newValue,
|
||||
...(type === FilterRuleType.DATE ||
|
||||
type === FilterRuleType.DATETIME
|
||||
? { valueData: "" }
|
||||
: {}),
|
||||
}
|
||||
: filter,
|
||||
: rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -277,12 +286,44 @@
|
|||
function handleFilterValueChange(e: CustomEvent) {
|
||||
const { id, value } = e.detail;
|
||||
|
||||
const newGroups: FilterGroup[] = groups.map((group) => {
|
||||
const { rules } = group;
|
||||
if (group.id === selectedGroupId) {
|
||||
const newRules = rules.map((rule) => {
|
||||
if (rule.id === id) {
|
||||
return {
|
||||
...rule,
|
||||
value,
|
||||
...(rule.type === FilterRuleType.DATE ||
|
||||
rule.type === FilterRuleType.DATETIME
|
||||
? { valueData: "" }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
return rule;
|
||||
});
|
||||
return {
|
||||
...group,
|
||||
rules: newRules,
|
||||
};
|
||||
}
|
||||
return group;
|
||||
});
|
||||
|
||||
groups = newGroups;
|
||||
}
|
||||
|
||||
function handleFilterValueDataChange(e: CustomEvent) {
|
||||
const { id, value } = e.detail;
|
||||
|
||||
const newGroups = groups.map((group) =>
|
||||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id ? { ...filter, value } : filter,
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id
|
||||
? { ...rule, valueData: value }
|
||||
: rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -294,17 +335,17 @@
|
|||
function handleFilterMatchWhenPropertyDNEChange(e: CustomEvent) {
|
||||
const { id, matchWhenDNE } = e.detail;
|
||||
|
||||
const newGroups = groups.map((group) =>
|
||||
const newGroups: FilterGroup[] = groups.map((group) =>
|
||||
group.id === selectedGroupId
|
||||
? {
|
||||
...group,
|
||||
filters: group.filters.map((filter) =>
|
||||
filter.id === id
|
||||
rules: group.rules.map((rule) =>
|
||||
rule.id === id
|
||||
? {
|
||||
...filter,
|
||||
...rule,
|
||||
matchWhenPropertyDNE: matchWhenDNE,
|
||||
}
|
||||
: filter,
|
||||
: rule,
|
||||
),
|
||||
}
|
||||
: group,
|
||||
|
|
@ -339,6 +380,7 @@
|
|||
on:filterToggle={handleFilterToggle}
|
||||
on:filterOperatorChange={handleFilterOperatorChange}
|
||||
on:filterValueChange={handleFilterValueChange}
|
||||
on:filterValueDataChange={handleFilterValueDataChange}
|
||||
on:filterMatchWhenPropertyDNEChange={handleFilterMatchWhenPropertyDNEChange}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { PropertyType, TextFilterCondition, TextPropertyFilter } from "src/types";
|
||||
import { FilterRuleType, TextFilterCondition, TextPropertyFilter } from "src/types";
|
||||
import { generateRandomId } from "../shared/services/random";
|
||||
|
||||
export const createPropertyFilter = (): TextPropertyFilter => {
|
||||
return {
|
||||
id: generateRandomId(),
|
||||
type: PropertyType.TEXT,
|
||||
type: FilterRuleType.TEXT,
|
||||
propertyName: "",
|
||||
operator: "and",
|
||||
isEnabled: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Logger from "js-logger";
|
||||
import { FrontMatterCache } from "obsidian";
|
||||
import { PropertyType } from "src/types";
|
||||
import { FilterRuleType } from "src/types";
|
||||
import { isDateSupported } from "./time-utils";
|
||||
|
||||
/**
|
||||
|
|
@ -10,7 +10,7 @@ import { isDateSupported } from "./time-utils";
|
|||
* @param expectedType - The expected type of the property
|
||||
* @returns - The property value or null if the property isn't valid
|
||||
*/
|
||||
export const loadPropertyValue = <T>(frontmatter: FrontMatterCache | undefined, propertyName: string, expectedType: PropertyType): T | null => {
|
||||
export const loadPropertyValue = <T>(frontmatter: FrontMatterCache | undefined, propertyName: string, expectedType: FilterRuleType): T | null => {
|
||||
//If the file has no frontmatter, return null
|
||||
if (!frontmatter) {
|
||||
return null;
|
||||
|
|
@ -29,32 +29,32 @@ export const loadPropertyValue = <T>(frontmatter: FrontMatterCache | undefined,
|
|||
}
|
||||
|
||||
//Validate the property value for the expected type
|
||||
if (expectedType === PropertyType.TEXT) {
|
||||
if (expectedType === FilterRuleType.TEXT) {
|
||||
if (typeof propertyValue !== "string") {
|
||||
Logger.warn(`Property value of type 'text' is not a string: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
} else if (expectedType === PropertyType.NUMBER) {
|
||||
} else if (expectedType === FilterRuleType.NUMBER) {
|
||||
if (typeof propertyValue !== "number") {
|
||||
Logger.warn(`Property value of type 'number' is not a number: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
} else if (expectedType === PropertyType.DATE) {
|
||||
} else if (expectedType === FilterRuleType.DATE) {
|
||||
if (typeof propertyValue !== "string") {
|
||||
Logger.warn(`Property value of type 'date' is not a string: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
} else if (expectedType === PropertyType.DATETIME) {
|
||||
} else if (expectedType === FilterRuleType.DATETIME) {
|
||||
if (typeof propertyValue !== "string") {
|
||||
Logger.warn(`Property value of type 'datetime' is not a string: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
} else if (expectedType === PropertyType.CHECKBOX) {
|
||||
} else if (expectedType === FilterRuleType.CHECKBOX) {
|
||||
if (typeof propertyValue !== "boolean") {
|
||||
Logger.warn(`Property value of type 'checkbox' is not a boolean: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
} else if (expectedType === PropertyType.LIST) {
|
||||
} else if (expectedType === FilterRuleType.LIST) {
|
||||
if (!Array.isArray(propertyValue)) {
|
||||
Logger.warn(`Property value of type 'list' is not an array: ${propertyValue}`);
|
||||
//Don't return null here, because the property value can be converted to an array
|
||||
|
|
@ -63,19 +63,19 @@ export const loadPropertyValue = <T>(frontmatter: FrontMatterCache | undefined,
|
|||
|
||||
//In older versions of Obsidian, the date can be stored in the frontmatter
|
||||
//in a format other than YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS
|
||||
if (expectedType === PropertyType.DATE) {
|
||||
if (expectedType === FilterRuleType.DATE) {
|
||||
if (!isDateSupported(propertyValue)) {
|
||||
Logger.warn(`Property value of type 'date' has unsupported date format: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
} else if (expectedType === PropertyType.DATETIME) {
|
||||
} else if (expectedType === FilterRuleType.DATETIME) {
|
||||
if (!isDateSupported(propertyValue)) {
|
||||
Logger.warn(`Property value of type 'datetime' has unsupported date format: ${propertyValue}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (expectedType === PropertyType.LIST) {
|
||||
if (expectedType === FilterRuleType.LIST) {
|
||||
//If the property is not an array, return it as an array
|
||||
//This is a bug in Obsidian?
|
||||
if (!Array.isArray(propertyValue)) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,18 @@ export const getStartOfThisWeekMillis = () => {
|
|||
return moment().startOf("week").valueOf();
|
||||
};
|
||||
|
||||
export const getMomentDate = (date: string) => {
|
||||
return moment(date, DATE_FORMATS, true);
|
||||
}
|
||||
|
||||
export const getDateDaysAgo = (daysAgo: number) => {
|
||||
return moment().subtract(daysAgo, "days").format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
export const getDateDaysAhead = (daysAgo: number) => {
|
||||
return moment().add(daysAgo, "days").format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets 12:00 AM of the previous week in milliseconds. The week starts on Sunday.
|
||||
* @returns - The start of the previous week in milliseconds
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ export interface VaultExplorerPluginSettings {
|
|||
onlyFavorites: boolean;
|
||||
sort: SortFilter;
|
||||
timestamp: TimestampFilter;
|
||||
properties: {
|
||||
custom: {
|
||||
selectedGroupId: string;
|
||||
groups: PropertyFilterGroup[];
|
||||
groups: FilterGroup[];
|
||||
}
|
||||
},
|
||||
views: {
|
||||
|
|
@ -74,29 +74,20 @@ export enum CheckboxFilterCondition {
|
|||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
//TODO: add more types
|
||||
//TODO: add is between
|
||||
export enum DateFilterCondition {
|
||||
IS = "is",
|
||||
IS_BEFORE = "is-before",
|
||||
IS_AFTER = "is-after",
|
||||
IS_ON_OR_BEFORE = "is-on-or-before",
|
||||
IS_ON_OR_AFTER = "is-on-or-after",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
export type FilterCondition = TextFilterCondition | NumberFilterCondition | DateFilterCondition | CheckboxFilterCondition | ListFilterCondition;
|
||||
|
||||
interface BasePropertyFilter {
|
||||
id: string;
|
||||
propertyName: string;
|
||||
operator: FilterOperator;
|
||||
type: PropertyType;
|
||||
isEnabled: boolean;
|
||||
value: string;
|
||||
matchWhenPropertyDNE: boolean;
|
||||
}
|
||||
|
||||
//Matches Obsidian property types
|
||||
export enum PropertyType {
|
||||
export enum FilterRuleType {
|
||||
TEXT = "text",
|
||||
NUMBER = "number",
|
||||
LIST = "list",
|
||||
|
|
@ -105,37 +96,63 @@ export enum PropertyType {
|
|||
DATETIME = "datetime",
|
||||
}
|
||||
|
||||
export interface TextPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.TEXT;
|
||||
export enum DatePropertyFilterValue {
|
||||
TODAY = "today",
|
||||
TOMORROW = "tomorrow",
|
||||
YESTERDAY = "yesterday",
|
||||
ONE_WEEK_FROM_NOW = "one-week-from-now",
|
||||
ONE_WEEK_AGO = "one-week-ago",
|
||||
ONE_MONTH_FROM_NOW = "one-month-from-now",
|
||||
ONE_MONTH_AGO = "one-month-ago",
|
||||
CUSTOM = "custom"
|
||||
}
|
||||
|
||||
interface BaseFilterRule {
|
||||
id: string;
|
||||
operator: FilterOperator;
|
||||
type: FilterRuleType;
|
||||
isEnabled: boolean;
|
||||
value: string;
|
||||
matchWhenPropertyDNE: boolean;
|
||||
}
|
||||
|
||||
export interface TextPropertyFilter extends BaseFilterRule {
|
||||
type: FilterRuleType.TEXT;
|
||||
propertyName: string;
|
||||
condition: TextFilterCondition;
|
||||
}
|
||||
|
||||
export interface NumberPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.NUMBER;
|
||||
export interface NumberPropertyFilter extends BaseFilterRule {
|
||||
type: FilterRuleType.NUMBER;
|
||||
propertyName: string;
|
||||
condition: NumberFilterCondition;
|
||||
}
|
||||
|
||||
export interface ListPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.LIST
|
||||
export interface ListPropertyFilter extends BaseFilterRule {
|
||||
type: FilterRuleType.LIST
|
||||
propertyName: string;
|
||||
condition: ListFilterCondition;
|
||||
}
|
||||
|
||||
export interface CheckboxPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.CHECKBOX
|
||||
export interface CheckboxPropertyFilter extends BaseFilterRule {
|
||||
type: FilterRuleType.CHECKBOX;
|
||||
propertyName: string;
|
||||
condition: CheckboxFilterCondition;
|
||||
}
|
||||
|
||||
export interface DatePropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.DATE | PropertyType.DATETIME;
|
||||
export interface DatePropertyFilter extends BaseFilterRule {
|
||||
type: FilterRuleType.DATE | FilterRuleType.DATETIME;
|
||||
propertyName: string;
|
||||
condition: DateFilterCondition;
|
||||
valueData: string;
|
||||
}
|
||||
|
||||
export type PropertyFilter = TextPropertyFilter | NumberPropertyFilter | ListPropertyFilter | CheckboxPropertyFilter | DatePropertyFilter;
|
||||
export type FilterRule = TextPropertyFilter | NumberPropertyFilter | ListPropertyFilter | CheckboxPropertyFilter | DatePropertyFilter;
|
||||
|
||||
export interface PropertyFilterGroup {
|
||||
export interface FilterGroup {
|
||||
id: string;
|
||||
name: string;
|
||||
filters: PropertyFilter[];
|
||||
rules: FilterRule[];
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ export interface VaultExplorerPluginSettings_1_5_0 {
|
|||
pluginVersion: string | null;
|
||||
}
|
||||
|
||||
export type PropertyFilterGroup_1_5_0 = PropertyFilterGroup;
|
||||
|
||||
export type PropertyFilter_1_5_0 = PropertyFilter;
|
||||
|
||||
type WordBreak = "normal" | "break-word";
|
||||
|
||||
enum ViewType {
|
||||
|
|
|
|||
144
src/types/types-1.8.1.ts
Normal file
144
src/types/types-1.8.1.ts
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
export interface VaultExplorerPluginSettings_1_8_1 {
|
||||
logLevel: string;
|
||||
properties: {
|
||||
favorite: string;
|
||||
url: string;
|
||||
createdDate: string;
|
||||
modifiedDate: string;
|
||||
custom1: string;
|
||||
custom2: string;
|
||||
custom3: string;
|
||||
},
|
||||
filters: {
|
||||
folder: string;
|
||||
search: string;
|
||||
onlyFavorites: boolean;
|
||||
sort: SortFilter;
|
||||
timestamp: TimestampFilter;
|
||||
properties: {
|
||||
selectedGroupId: string;
|
||||
groups: PropertyFilterGroup[];
|
||||
}
|
||||
},
|
||||
views: {
|
||||
currentView: ViewType;
|
||||
order: ViewType[];
|
||||
titleWrapping: WordBreak;
|
||||
}
|
||||
pageSize: number;
|
||||
pluginVersion: string | null;
|
||||
}
|
||||
|
||||
type WordBreak = "normal" | "break-word";
|
||||
|
||||
enum ViewType {
|
||||
GRID = "grid",
|
||||
LIST = "list",
|
||||
}
|
||||
|
||||
type FilterOperator = "and" | "or";
|
||||
|
||||
enum TextFilterCondition {
|
||||
IS = "is",
|
||||
IS_NOT = "is-not",
|
||||
CONTAINS = "contains",
|
||||
DOES_NOT_CONTAIN = "does-not-contain",
|
||||
STARTS_WITH = "starts-with",
|
||||
ENDS_WITH = "ends-with",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum ListFilterCondition {
|
||||
CONTAINS = "contains",
|
||||
DOES_NOT_CONTAIN = "does-not-contain",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum NumberFilterCondition {
|
||||
IS_EQUAL = "is-equal",
|
||||
IS_NOT_EQUAL = "is-not-equal",
|
||||
IS_GREATER = "is-greater",
|
||||
IS_LESS = "is-less",
|
||||
IS_GREATER_OR_EQUAL = "is-greater-or-equal",
|
||||
IS_LESS_OR_EQUAL = "is-less-or-equal",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum CheckboxFilterCondition {
|
||||
IS = "is",
|
||||
IS_NOT = "is-not",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
//TODO: add more types
|
||||
enum DateFilterCondition {
|
||||
IS = "is",
|
||||
IS_BEFORE = "is-before",
|
||||
IS_AFTER = "is-after",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
type FilterCondition = TextFilterCondition | NumberFilterCondition | DateFilterCondition | CheckboxFilterCondition | ListFilterCondition;
|
||||
|
||||
interface BasePropertyFilter {
|
||||
id: string;
|
||||
propertyName: string;
|
||||
operator: FilterOperator;
|
||||
type: PropertyType;
|
||||
isEnabled: boolean;
|
||||
value: string;
|
||||
matchWhenPropertyDNE: boolean;
|
||||
}
|
||||
|
||||
//Matches Obsidian property types
|
||||
enum PropertyType {
|
||||
TEXT = "text",
|
||||
NUMBER = "number",
|
||||
LIST = "list",
|
||||
CHECKBOX = "checkbox",
|
||||
DATE = "date",
|
||||
DATETIME = "datetime",
|
||||
}
|
||||
|
||||
interface TextPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.TEXT;
|
||||
condition: TextFilterCondition;
|
||||
}
|
||||
|
||||
interface NumberPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.NUMBER;
|
||||
condition: NumberFilterCondition;
|
||||
}
|
||||
|
||||
interface ListPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.LIST
|
||||
condition: ListFilterCondition;
|
||||
}
|
||||
|
||||
interface CheckboxPropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.CHECKBOX
|
||||
condition: CheckboxFilterCondition;
|
||||
}
|
||||
|
||||
interface DatePropertyFilter extends BasePropertyFilter {
|
||||
type: PropertyType.DATE | PropertyType.DATETIME;
|
||||
condition: DateFilterCondition;
|
||||
}
|
||||
|
||||
type PropertyFilter = TextPropertyFilter | NumberPropertyFilter | ListPropertyFilter | CheckboxPropertyFilter | DatePropertyFilter;
|
||||
|
||||
interface PropertyFilterGroup {
|
||||
id: string;
|
||||
name: string;
|
||||
filters: PropertyFilter[];
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
type SortFilter = "file-name-asc" | "file-name-desc" | "modified-asc" | "modified-desc";
|
||||
|
||||
type TimestampFilter = "created-today" | "modified-today" | "created-this-week" | "modified-this-week" | "created-2-weeks" | "modified-2-weeks" | "all";
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
import { FrontMatterCache } from "obsidian";
|
||||
import { PropertyType } from "src/types";
|
||||
import { FilterRuleType } from "src/types";
|
||||
import { loadPropertyValue } from "src/svelte/shared/services/load-property-value";
|
||||
|
||||
describe("loadPropertyValue", () => {
|
||||
|
|
@ -9,7 +9,7 @@ describe("loadPropertyValue", () => {
|
|||
const frontmatter: FrontMatterCache | undefined = undefined;
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, "test", PropertyType.TEXT);
|
||||
const result = loadPropertyValue<string>(frontmatter, "test", FilterRuleType.TEXT);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -21,7 +21,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.TEXT);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.TEXT);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -33,7 +33,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.TEXT);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.TEXT);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -45,7 +45,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.TEXT);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.TEXT);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -57,7 +57,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.TEXT);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.TEXT);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -69,7 +69,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.TEXT);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.TEXT);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe("test");
|
||||
|
|
@ -81,7 +81,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<number>(frontmatter, propertyName, PropertyType.NUMBER);
|
||||
const result = loadPropertyValue<number>(frontmatter, propertyName, FilterRuleType.NUMBER);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -93,7 +93,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<number>(frontmatter, propertyName, PropertyType.NUMBER);
|
||||
const result = loadPropertyValue<number>(frontmatter, propertyName, FilterRuleType.NUMBER);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(1);
|
||||
|
|
@ -105,7 +105,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<boolean>(frontmatter, propertyName, PropertyType.CHECKBOX);
|
||||
const result = loadPropertyValue<boolean>(frontmatter, propertyName, FilterRuleType.CHECKBOX);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -117,7 +117,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<boolean>(frontmatter, propertyName, PropertyType.CHECKBOX);
|
||||
const result = loadPropertyValue<boolean>(frontmatter, propertyName, FilterRuleType.CHECKBOX);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
|
@ -129,7 +129,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string[]>(frontmatter, propertyName, PropertyType.LIST);
|
||||
const result = loadPropertyValue<string[]>(frontmatter, propertyName, FilterRuleType.LIST);
|
||||
|
||||
//Assert
|
||||
expect(result).toEqual(["test"]);
|
||||
|
|
@ -141,7 +141,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string[]>(frontmatter, propertyName, PropertyType.LIST);
|
||||
const result = loadPropertyValue<string[]>(frontmatter, propertyName, FilterRuleType.LIST);
|
||||
|
||||
//Assert
|
||||
expect(result).toEqual(["test"]);
|
||||
|
|
@ -154,7 +154,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string[]>(frontmatter, propertyName, PropertyType.LIST);
|
||||
const result = loadPropertyValue<string[]>(frontmatter, propertyName, FilterRuleType.LIST);
|
||||
|
||||
//Assert
|
||||
expect(result).toEqual(["test"]);
|
||||
|
|
@ -166,7 +166,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.DATE);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.DATE);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -178,7 +178,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.DATETIME);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.DATETIME);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -191,7 +191,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.DATE);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.DATE);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe("2021-01-01");
|
||||
|
|
@ -203,7 +203,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.DATETIME);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.DATETIME);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -215,7 +215,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.DATETIME);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.DATETIME);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeNull();
|
||||
|
|
@ -227,7 +227,7 @@ describe("loadPropertyValue", () => {
|
|||
const propertyName = "test";
|
||||
|
||||
//Act
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, PropertyType.DATETIME);
|
||||
const result = loadPropertyValue<string>(frontmatter, propertyName, FilterRuleType.DATETIME);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe("2021-01-01T00:00:00");
|
||||
|
|
|
|||
|
|
@ -189,20 +189,6 @@ describe("matchDateFilter", () => {
|
|||
// Assert
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return false for matchDateFilter(YYYY-MM-DDTHH:mm:ss, invalid-date, IS, false)", () => {
|
||||
// Arrange
|
||||
const propertyValue = "2020-01-01T12:00:00";
|
||||
const compare = "invalid-date";
|
||||
const condition = DateFilterCondition.IS;
|
||||
const matchIfNull = false;
|
||||
|
||||
// Act
|
||||
const result = matchDateFilter(propertyValue, compare, condition, matchIfNull);
|
||||
|
||||
// Assert
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Error Cases", () => {
|
||||
|
|
|
|||
|
|
@ -59,5 +59,6 @@
|
|||
"1.7.2": "1.4.13",
|
||||
"1.7.3": "1.4.13",
|
||||
"1.8.0": "1.4.13",
|
||||
"1.8.1": "1.4.13"
|
||||
"1.8.1": "1.4.13",
|
||||
"1.9.0": "1.4.13"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue