Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/blank note explorer view #493

Merged
Merged
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 @@ -44,6 +44,12 @@
"name": "Orphans",
"icon": "media/dep.svg",
"contextualTitle": "Orphans"
},
{
"id": "foam-vscode.placeholders",
"name": "Placeholders",
"icon": "media/dep.svg",
"contextualTitle": "Placeholders"
}
]
},
Expand All @@ -55,6 +61,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 @@ -68,6 +78,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 @@ -78,6 +98,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 @@ -114,6 +142,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 @@ -124,6 +156,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 @@ -221,6 +263,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();
});
});