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

Commit 919ae14

Browse files
decaf-dev42ama
andauthored
Merge pull request #945 from trey-wallis/dev
* #937 Mulit-Tag sorting feature (#944) * #937 Mulit-Tag sorting feature + Added new Column property - contentsSortDir, it stores information about sorting the content in the cells of the column. At the moment the only type that can store several items in a cell is MultiTag, so the processing logic was added only for it. + Added a options submenu for columns with MultiTag type, where you can select the sorting type for the cell contents. * Renamed `contentsSortDir` to `multiTagSortDir` and `Contents sorting` to `Sort` * feat: add display name for sort direction * fix: don't close menu on sort select * build: fix build errors * chore: bump to 8.16.0 --------- Co-authored-by: Maxim <[email protected]>
2 parents c31d679 + c32320f commit 919ae14

21 files changed

+626
-16
lines changed

manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
"fundingUrl": {
1010
"Buymeacoffee": "https://www.buymeacoffee.com/treywallis"
1111
},
12-
"version": "8.15.12"
12+
"version": "8.16.0"
1313
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-dataloom",
3-
"version": "8.15.12",
3+
"version": "8.16.0",
44
"description": "Weave together data from diverse sources into different views. Inspired by Excel Spreadsheets and Notion.so.",
55
"main": "main.js",
66
"scripts": {

src/data/serialize-state.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
LoomState18,
2727
LoomState19,
2828
LoomState20,
29+
LoomState21,
2930
} from "src/shared/loom-state/types";
3031

3132
import {
@@ -50,10 +51,11 @@ import {
5051
MigrateState18,
5152
MigrateState19,
5253
MigrateState20,
54+
MigrateState21,
55+
MigrateState22,
5356
} from "src/shared/loom-state/migrate";
5457
import { LoomStateObject } from "src/shared/loom-state/validate-state";
5558
import DeserializationError from "./deserialization-error";
56-
import MigrateState21 from "src/shared/loom-state/migrate/migrate-state-21";
5759

5860
export const serializeState = (state: LoomState): string => {
5961
//Filter out any source rows, as these are populated by the plugin
@@ -316,6 +318,16 @@ export const deserializeState = (
316318
failedMigration = null;
317319
}
318320

321+
const VERSION_8_16_0 = "8.16.0";
322+
if (isVersionLessThan(fileVersion, VERSION_8_16_0)) {
323+
failedMigration = VERSION_8_16_0;
324+
const nextState = new MigrateState22().migrate(
325+
currentState as LoomState21
326+
);
327+
currentState = nextState;
328+
failedMigration = null;
329+
}
330+
319331
//TODO handle previous versions?
320332
LoomStateObject.check(currentState);
321333

src/react/loom-app/body-cell-container/index.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ import { getFileCellContent } from "src/shared/cell-content/file-cell-content";
7171
import { getDateCellContent } from "src/shared/cell-content/date-cell-content";
7272
import DisabledCell from "../disabled-cell";
7373

74+
import { sortByText } from "src/shared/sort-utils";
75+
7476
interface BaseCellProps {
7577
frontmatterKey: string | null;
7678
aspectRatio: AspectRatio;
@@ -440,9 +442,11 @@ export default function BodyCellContainer(props: Props) {
440442
}
441443
};
442444
} else {
443-
const { tagIds } = props as MultiTagCellProps;
444-
cellTags = columnTags.filter((tag) => tagIds.includes(tag.id));
445+
const { tagIds, multiTagSortDir } = props as MultiTagCellProps;
445446

447+
cellTags = columnTags.filter((tag) => tagIds.includes(tag.id));
448+
cellTags.sort((a, b) => sortByText(a.content, b.content, multiTagSortDir, false));
449+
446450
handleMenuTriggerBackspaceDown = () => {
447451
onTagCellMultipleRemove(id, tagIds);
448452
};

src/react/loom-app/header-menu/base-submenu.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ export default function BaseSubmenu({
7070
columnType === CellType.EMBED ||
7171
columnType === CellType.NUMBER ||
7272
columnType === CellType.LAST_EDITED_TIME ||
73-
columnType === CellType.CREATION_TIME;
73+
columnType === CellType.CREATION_TIME||
74+
columnType === CellType.MULTI_TAG;
7475

7576
return (
7677
<Stack spacing="sm">

src/react/loom-app/header-menu/index.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import FrontmatterKeySubmenu from "./frontmatter-key-submenu";
1212
import BaseSubmenu from "./base-submenu";
1313
import DateFormatSeparatorSubmenu from "./date-format-separator-submenu";
1414
import TimeFormatSubmenu from "./time-format-submenu";
15+
import MultiTagSortDirSubmenu from "./multitag-sort-dir-submenu";
1516

1617
import {
1718
AspectRatio,
@@ -88,6 +89,7 @@ export default function HeaderMenu({
8889
numberSeparator,
8990
numberSuffix,
9091
frontmatterKey,
92+
multiTagSortDir,
9193
} = column;
9294
const [submenu, setSubmenu] = React.useState<SubmenuType | null>(null);
9395
const [localValue, setLocalValue] = React.useState(content);
@@ -241,6 +243,11 @@ export default function HeaderMenu({
241243
onClose();
242244
}
243245

246+
function handleMultiTagSortDirClick(value: SortDir) {
247+
onColumnChange(columnId, { multiTagSortDir: value });
248+
setSubmenu(SubmenuType.OPTIONS);
249+
}
250+
244251
return (
245252
<Menu isOpen={isOpen} id={id} position={position} width={190}>
246253
<div className="dataloom-header-menu">
@@ -280,6 +287,7 @@ export default function HeaderMenu({
280287
numberPrefix={numberPrefix}
281288
numberSuffix={numberSuffix}
282289
numberSeparator={numberSeparator}
290+
multiTagSortDir={multiTagSortDir}
283291
onBackClick={() => setSubmenu(null)}
284292
onSubmenuChange={setSubmenu}
285293
/>
@@ -390,6 +398,14 @@ export default function HeaderMenu({
390398
onBackClick={() => setSubmenu(null)}
391399
/>
392400
)}
401+
{submenu === SubmenuType.CONTENTS_SORT_DIR && (
402+
<MultiTagSortDirSubmenu
403+
title="Sort"
404+
value={multiTagSortDir}
405+
onValueClick={handleMultiTagSortDirClick}
406+
onBackClick={() => setSubmenu(null)}
407+
/>
408+
)}
393409
</div>
394410
</Menu>
395411
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import MenuItem from "src/react/shared/menu-item";
2+
import Submenu from "../../shared/submenu";
3+
import { SortDir } from "src/shared/loom-state/types/loom-state";
4+
5+
interface Props {
6+
title: string;
7+
value: SortDir;
8+
onValueClick: (value: SortDir) => void;
9+
onBackClick: () => void;
10+
}
11+
12+
export default function MultiTagSortDirSubmenu({
13+
title,
14+
value,
15+
onValueClick,
16+
onBackClick,
17+
}: Props) {
18+
return (
19+
<Submenu title={title} onBackClick={onBackClick}>
20+
<MenuItem
21+
key={SortDir.ASC}
22+
name="Ascending"
23+
onClick={() => onValueClick(SortDir.ASC)}
24+
isSelected={value === SortDir.ASC}
25+
/>
26+
<MenuItem
27+
key={SortDir.DESC}
28+
name="Descending"
29+
onClick={() => onValueClick(SortDir.DESC)}
30+
isSelected={value === SortDir.DESC}
31+
/>
32+
<MenuItem
33+
key={SortDir.NONE}
34+
name="Default"
35+
onClick={() => onValueClick(SortDir.NONE)}
36+
isSelected={value === SortDir.NONE}
37+
/>
38+
</Submenu>
39+
);
40+
}

src/react/loom-app/header-menu/option-submenu.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
DateFormatSeparator,
99
NumberFormat,
1010
PaddingSize,
11+
SortDir,
1112
} from "src/shared/loom-state/types/loom-state";
1213
import Stack from "src/react/shared/stack";
1314
import Padding from "src/react/shared/padding";
@@ -17,6 +18,7 @@ import {
1718
getDisplayNameForCurrencyType,
1819
getDisplayNameForDateFormat,
1920
getDisplayNameForDateFormatSeparator,
21+
getDisplayNameForSortDir,
2022
} from "src/shared/loom-state/type-display-names";
2123

2224
interface Props {
@@ -33,6 +35,7 @@ interface Props {
3335
verticalPadding: PaddingSize;
3436
horizontalPadding: PaddingSize;
3537
aspectRatio: AspectRatio;
38+
multiTagSortDir: SortDir;
3639
onBackClick: () => void;
3740
onSubmenuChange: (value: SubmenuType) => void;
3841
}
@@ -51,6 +54,7 @@ export default function OptionSubmenu({
5154
horizontalPadding,
5255
title,
5356
dateFormat,
57+
multiTagSortDir,
5458
onBackClick,
5559
onSubmenuChange,
5660
}: Props) {
@@ -165,6 +169,15 @@ export default function OptionSubmenu({
165169
/>
166170
</>
167171
)}
172+
{type === CellType.MULTI_TAG && (
173+
<MenuItem
174+
name="Sort"
175+
value={getDisplayNameForSortDir(multiTagSortDir)}
176+
onClick={() =>
177+
onSubmenuChange(SubmenuType.CONTENTS_SORT_DIR)
178+
}
179+
/>
180+
)}
168181
</Stack>
169182
</Padding>
170183
</Submenu>

src/react/loom-app/header-menu/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export enum SubmenuType {
1212
TEXT_INPUT_NUMBER_SUFFIX,
1313
TEXT_INPUT_NUMBER_SEPARATOR,
1414
FRONTMATTER_KEY,
15+
CONTENTS_SORT_DIR
1516
}

src/react/loom-app/table/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ const Table = React.forwardRef<VirtuosoHandle, Props>(function Table(
358358
horizontalPadding,
359359
aspectRatio,
360360
frontmatterKey,
361+
multiTagSortDir
361362
} = column;
362363

363364
const cell = row.cells.find(
@@ -457,6 +458,7 @@ const Table = React.forwardRef<VirtuosoHandle, Props>(function Table(
457458
{...commonProps}
458459
type={type}
459460
tagIds={tagIds}
461+
multiTagSortDir={multiTagSortDir}
460462
onCellChange={onCellChange}
461463
onTagAdd={onTagAdd}
462464
onTagCellAdd={onTagCellAdd}

src/shared/frontmatter/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ export const deserializeFrontmatterForCell = (
213213
return {
214214
newCell: createMultiTagCell(id, {
215215
hasValidFrontmatter: false,
216+
multiTagSortDir: column.multiTagSortDir
216217
}),
217218
};
218219
}
@@ -238,6 +239,7 @@ export const deserializeFrontmatterForCell = (
238239
const newCell = createMultiTagCell(id, {
239240
tagIds: cellTagIds,
240241
hasValidFrontmatter: true,
242+
multiTagSortDir: column.multiTagSortDir
241243
});
242244
const nextTags = [...column.tags, ...newTags];
243245
return {

src/shared/loom-state/loom-state-factory.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export const createColumn = (options?: {
152152
horizontalPadding: PaddingSize.UNSET,
153153
verticalPadding: PaddingSize.UNSET,
154154
frontmatterKey,
155+
multiTagSortDir: SortDir.NONE
155156
};
156157
};
157158

@@ -355,14 +356,16 @@ export const createMultiTagCell = (
355356
options?: {
356357
tagIds?: string[];
357358
hasValidFrontmatter?: boolean;
359+
multiTagSortDir?: SortDir;
358360
}
359361
): MultiTagCell => {
360-
const { tagIds = [], hasValidFrontmatter = null } = options || {};
362+
const { tagIds = [], hasValidFrontmatter = null, multiTagSortDir = SortDir.NONE } = options || {};
361363
return {
362364
id: generateUuid(),
363365
columnId,
364366
tagIds,
365367
hasValidFrontmatter,
368+
multiTagSortDir
366369
};
367370
};
368371

src/shared/loom-state/migrate/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ export { default as MigrateState17 } from "./migrate-state-17";
1919
export { default as MigrateState18 } from "./migrate-state-18";
2020
export { default as MigrateState19 } from "./migrate-state-19";
2121
export { default as MigrateState20 } from "./migrate-state-20";
22+
export { default as MigrateState21 } from "./migrate-state-21";
23+
export { default as MigrateState22 } from "./migrate-state-22";

src/shared/loom-state/migrate/migrate-state-21.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import MigrateState from "./migrate-state";
2-
import { LoomState20, LoomState } from "../types";
2+
import { LoomState20, LoomState21 } from "../types";
33
import { Row } from "../types/loom-state";
44

55
/**
66
* Migrates to 8.15.6
77
*/
88
export default class MigrateState21 implements MigrateState {
9-
public migrate(prevState: LoomState20): LoomState {
9+
public migrate(prevState: LoomState20): LoomState21 {
1010
const { rows } = prevState.model;
1111

1212
const nextRows: Row[] = rows.map((row) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import MigrateState from "./migrate-state";
2+
import { LoomState } from "../types";
3+
import { SortDir, Column } from "../types/loom-state";
4+
import { LoomState21 } from "../types/loom-state-21";
5+
6+
/**
7+
* Migrates to 8.16.0
8+
*/
9+
export default class MigrateState22 implements MigrateState {
10+
public migrate(prevState: LoomState21): LoomState {
11+
const { columns } = prevState.model;
12+
13+
const nextColumns: Column[] = columns.map((column) => {
14+
return {
15+
...column,
16+
multiTagSortDir: SortDir.NONE,
17+
};
18+
});
19+
20+
return {
21+
...prevState,
22+
model: {
23+
...prevState.model,
24+
columns: nextColumns,
25+
},
26+
};
27+
}
28+
}

src/shared/loom-state/type-display-names.ts

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
DateFilterOption,
1414
SourceType,
1515
DateFormatSeparator,
16+
SortDir,
1617
} from "./types/loom-state";
1718

1819
const getShortDisplayNameForCalculation = (value: GeneralCalculation) => {
@@ -169,6 +170,17 @@ export const getDisplayNameForDateFormatSeparator = (
169170
}
170171
};
171172

173+
export const getDisplayNameForSortDir = (dir: SortDir) => {
174+
switch (dir) {
175+
case SortDir.ASC:
176+
return "Ascending";
177+
case SortDir.DESC:
178+
return "Descending";
179+
default:
180+
return "Default";
181+
}
182+
}
183+
172184
export const getDisplayNameForCurrencyType = (type: CurrencyType) => {
173185
switch (type) {
174186
case CurrencyType.UNITED_STATES:

src/shared/loom-state/types/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export type { LoomState17 } from "./loom-state-17";
2020
export type { LoomState18 } from "./loom-state-18";
2121
export type { LoomState19 } from "./loom-state-19";
2222
export type { LoomState20 } from "./loom-state-20";
23+
export type { LoomState21 } from "./loom-state-21";

0 commit comments

Comments
 (0)