Skip to content

Commit

Permalink
Feature/blank note explorer view (#493)
Browse files Browse the repository at this point in the history
* Create Blank Note Explorer View

Creates a new "Blank Note" explorer view which displays all notes that
contain only a title. When note.source.text.trim().split('\n').length
is equal to 1, a note is considered blank. This should mean that the
note contains only a title.

The UX experience is identical to that of the Orphan view. A user can
toggle between both the flat view and a nested view grouped by
directory.

* Cleaned up views and made them much more dynamic.

Instead of just copy and pasting the orphans view into blank notes,
I created a filtered notes provider, which behaves identically to the
old orphan/blank notes providers, but allows the caller to pass in the
"filter function" which will narrow down the list of notes in the view.

This also allows us to more easily unit test the filtering logic, and
only test the flatten / nested logic in one place. It also makes it so
that when we refactor the way one of these views works (e.g. adding the
markdown preview), we don't have to make changes to the other view.

* Fixed unit test that was failing in Windows.

* Combined placeholders and blank notes.

* Removed workspacesFsPaths and replaced with workspacesURIs

Co-authored-by: J.T. James <joel.james@myfuelmaster.com>
  • Loading branch information
joeltjames and J.T. James committed Mar 2, 2021
1 parent 596d96e commit f48c74c
Show file tree
Hide file tree
Showing 13 changed files with 828 additions and 288 deletions.
6 changes: 6 additions & 0 deletions packages/foam-core/src/index.ts
Expand Up @@ -6,6 +6,9 @@ import {
NoteLink,
isNote,
NoteLinkDefinition,
isPlaceholder,
isAttachment,
getTitle,
} from './model/note';
import { URI } from './common/uri';
import { FoamConfig } from './config';
Expand Down Expand Up @@ -52,6 +55,9 @@ export {
FoamWorkspace,
NoteLinkDefinition,
isNote,
isPlaceholder,
isAttachment,
getTitle,
};

export interface Services {
Expand Down
8 changes: 8 additions & 0 deletions packages/foam-core/src/model/note.ts
Expand Up @@ -74,3 +74,11 @@ export const getTitle = (resource: Resource): string => {
export const isNote = (resource: Resource): resource is Note => {
return resource.type === 'note';
};

export const isPlaceholder = (resource: Resource): resource is Placeholder => {
return resource.type === 'placeholder';
};

export const isAttachment = (resource: Resource): resource is Attachment => {
return resource.type === 'attachment';
};
66 changes: 66 additions & 0 deletions packages/foam-vscode/package.json
Expand Up @@ -45,6 +45,12 @@
"name": "Orphans",
"icon": "media/dep.svg",
"contextualTitle": "Orphans"
},
{
"id": "foam-vscode.placeholders",
"name": "Placeholders",
"icon": "media/dep.svg",
"contextualTitle": "Placeholders"
}
]
},
Expand All @@ -56,6 +62,10 @@
{
"view": "foam-vscode.orphans",
"contents": "No orphans found. Notes that have no backlinks nor links will show up here."
},
{
"view": "foam-vscode.placeholders",
"contents": "No placeholders found. Pending links and notes without content will show up here."
}
],
"menus": {
Expand All @@ -69,6 +79,16 @@
"command": "foam-vscode.group-orphans-off",
"when": "view == foam-vscode.orphans && foam-vscode.orphans-grouped-by-folder == true",
"group": "navigation"
},
{
"command": "foam-vscode.group-placeholders-by-folder",
"when": "view == foam-vscode.placeholders && foam-vscode.placeholders-grouped-by-folder == false",
"group": "navigation"
},
{
"command": "foam-vscode.group-placeholders-off",
"when": "view == foam-vscode.placeholders && foam-vscode.placeholders-grouped-by-folder == true",
"group": "navigation"
}
],
"commandPalette": [
Expand All @@ -79,6 +99,14 @@
{
"command": "foam-vscode.group-orphans-off",
"when": "false"
},
{
"command": "foam-vscode.group-placeholders-by-folder",
"when": "false"
},
{
"command": "foam-vscode.group-placeholders-off",
"when": "false"
}
]
},
Expand Down Expand Up @@ -115,6 +143,10 @@
"command": "foam-vscode.create-note-from-template",
"title": "Foam: Create New Note From Template"
},
{
"command": "foam-vscode.open-placeholder-note",
"title": "Foam: Open Placeholder Note"
},
{
"command": "foam-vscode.group-orphans-by-folder",
"title": "Foam: Group Orphans By Folder",
Expand All @@ -125,6 +157,16 @@
"title": "Foam: Don't Group Orphans",
"icon": "$(list-flat)"
},
{
"command": "foam-vscode.group-placeholders-by-folder",
"title": "Foam: Group Placeholders By Folder",
"icon": "$(list-tree)"
},
{
"command": "foam-vscode.group-placeholders-off",
"title": "Foam: Don't Group Placeholders",
"icon": "$(list-flat)"
},
{
"command": "foam-vscode.create-new-template",
"title": "Foam: Create New Template"
Expand Down Expand Up @@ -222,6 +264,30 @@
"markdownDescription": "Group orphans report entries by.",
"scope": "resource"
},
"foam.placeholders.exclude": {
"type": [
"array"
],
"default": [],
"markdownDescription": "Specifies the list of glob patterns that will be excluded from the placeholders report. To ignore the all the content of a given folder, use `**<folderName>/**/*`",
"scope": "resource"
},
"foam.placeholders.groupBy": {
"type": [
"string"
],
"enum": [
"off",
"folder"
],
"enumDescriptions": [
"Disable grouping",
"Group by folder"
],
"default": "folder",
"markdownDescription": "Group blank note report entries by.",
"scope": "resource"
},
"foam.dateSnippets.afterCompletion": {
"type": "string",
"default": "createNote",
Expand Down
4 changes: 4 additions & 0 deletions packages/foam-vscode/src/features/index.ts
Expand Up @@ -8,6 +8,8 @@ import tagsExplorer from './tags-tree-view';
import createFromTemplate from './create-from-template';
import openRandomNote from './open-random-note';
import orphans from './orphans';
import placeholders from './placeholders';
import utilityCommands from './utility-commands';
import { FoamFeature } from '../types';

export const features: FoamFeature[] = [
Expand All @@ -21,4 +23,6 @@ export const features: FoamFeature[] = [
openDatedNote,
createFromTemplate,
orphans,
placeholders,
utilityCommands,
];
122 changes: 22 additions & 100 deletions packages/foam-vscode/src/features/orphans.test.ts
@@ -1,110 +1,32 @@
import { OrphansProvider, Directory, OrphansProviderConfig } from './orphans';
import { OrphansConfigGroupBy } from '../settings';
import { FoamWorkspace } from 'foam-core';
import { createTestNote } from '../test/test-utils';
import { isOrphan } from './orphans';

describe('orphans', () => {
const orphanA = createTestNote({
uri: '/path/orphan-a.md',
title: 'Orphan A',
});
const orphanB = createTestNote({
uri: '/path-bis/orphan-b.md',
title: 'Orphan B',
});
const orphanC = createTestNote({
uri: '/path-exclude/orphan-c.md',
title: 'Orphan C',
});

const workspace = new FoamWorkspace()
.set(orphanA)
.set(orphanB)
.set(orphanC)
.set(createTestNote({ uri: '/path/non-orphan-1.md' }))
.set(
createTestNote({
uri: '/path/non-orphan-2.md',
links: [{ slug: 'non-orphan-1' }],
})
)
.resolveLinks();

const dataStore = { read: () => '' } as any;
const orphanA = createTestNote({
uri: '/path/orphan-a.md',
title: 'Orphan A',
});

// Mock config
const config: OrphansProviderConfig = {
exclude: ['path-exclude/**/*'],
groupBy: OrphansConfigGroupBy.Folder,
workspacesFsPaths: [''],
};
const nonOrphan1 = createTestNote({
uri: '/path/non-orphan-1.md',
});

it('should return the orphans as a folder tree', async () => {
const provider = new OrphansProvider(workspace, dataStore, config);
const result = await provider.getChildren();
expect(result).toMatchObject([
{
collapsibleState: 1,
label: '/path',
description: '1 orphan',
notes: [{ title: 'Orphan A' }],
},
{
collapsibleState: 1,
label: '/path-bis',
description: '1 orphan',
notes: [{ title: 'Orphan B' }],
},
]);
});
const nonOrphan2 = createTestNote({
uri: '/path/non-orphan-2.md',
links: [{ slug: 'non-orphan-1' }],
});

it('should return the orphans in a directory', async () => {
const provider = new OrphansProvider(workspace, dataStore, config);
const directory = new Directory('/path', [orphanA as any]);
const result = await provider.getChildren(directory);
expect(result).toMatchObject([
{
collapsibleState: 0,
label: 'Orphan A',
description: '/path/orphan-a.md',
command: { command: 'vscode.open' },
},
]);
});
const workspace = new FoamWorkspace()
.set(orphanA)
.set(nonOrphan1)
.set(nonOrphan2)
.resolveLinks();

it('should return the flattened orphans', async () => {
const mockConfig = { ...config, groupBy: OrphansConfigGroupBy.Off };
const provider = new OrphansProvider(workspace, dataStore, mockConfig);
const result = await provider.getChildren();
expect(result).toMatchObject([
{
collapsibleState: 0,
label: 'Orphan A',
description: '/path/orphan-a.md',
command: { command: 'vscode.open' },
},
{
collapsibleState: 0,
label: 'Orphan B',
description: '/path-bis/orphan-b.md',
command: { command: 'vscode.open' },
},
]);
describe('isOrphan', () => {
it('should return true when a note with no connections is provided', () => {
expect(isOrphan(workspace, orphanA)).toBeTruthy();
});

it('should return the orphans without exclusion', async () => {
const mockConfig = { ...config, exclude: [] };
const provider = new OrphansProvider(workspace, dataStore, mockConfig);
const result = await provider.getChildren();
expect(result).toMatchObject([
expect.anything(),
expect.anything(),
{
collapsibleState: 1,
label: '/path-exclude',
description: '1 orphan',
notes: [{ title: 'Orphan C' }],
},
]);
it('should return false when a note with connections is provided', () => {
expect(isOrphan(workspace, nonOrphan1)).toBeFalsy();
});
});

0 comments on commit f48c74c

Please sign in to comment.