Skip to content

Commit

Permalink
#405 - Implement custom grouping option
Browse files Browse the repository at this point in the history
  • Loading branch information
estruyf committed Nov 27, 2024
1 parent d7282b1 commit 2f76de2
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### 🎨 Enhancements

- [#405](https://github.com/estruyf/vscode-front-matter/issues/405): Added new `frontMatter.content.grouping` setting which allows you to define custom "group by" options
- [#705](https://github.com/estruyf/vscode-front-matter/issues/705): UX improvements for the panel view
- [#887](https://github.com/estruyf/vscode-front-matter/issues/887): Added new `frontMatter.global.timezone` setting, by default it is set to `UTC` for date formatting
- [#888](https://github.com/estruyf/vscode-front-matter/issues/888): Added the ability to prompt GitHub Copilot from a custom script/action
Expand Down
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,34 @@
"additionalProperties": false
}
},
"frontMatter.content.grouping": {
"type": "array",
"default": [],
"markdownDescription": "%setting.frontMatter.content.grouping.markdownDescription%",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "%setting.frontMatter.content.grouping.items.properties.id.description%"
},
"title": {
"type": "string",
"description": "%setting.frontMatter.content.grouping.items.properties.title.description%"
},
"name": {
"type": "string",
"description": "%setting.frontMatter.content.grouping.items.properties.name.description%"
}
},
"additionalProperties": false,
"required": [
"title",
"name"
]
},
"scope": "Content"
},
"frontMatter.content.sorting": {
"type": "array",
"default": [],
Expand Down
4 changes: 4 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
"setting.frontMatter.content.publicFolder.properties.relative.description": "Defines if the path to your media files be relative to the content file?",
"setting.frontMatter.snippets.wrapper.enabled.markdownDescription": "Specify if you want to wrap the snippets. [Docs](https://frontmatter.codes/docs/settings/overview#frontMatter.snippets.wrapper.enabled) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontMatter.snippets.wrapper.enabled%22%5D)",
"setting.frontMatter.content.snippets.markdownDescription": "Define the snippets you want to use in your content. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.content.snippets) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.content.snippets%22%5D)",
"setting.frontMatter.content.grouping.markdownDescription": "Specify the grouping options for your dashboard content. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.content.grouping) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.content.grouping%22%5D)",
"setting.frontMatter.content.grouping.items.properties.id.description": "The ID of the grouping option.",
"setting.frontMatter.content.grouping.items.properties.title.description": "Title of the grouping which will be shown in the UI.",
"setting.frontMatter.content.grouping.items.properties.name.description": "Name of the content-type field to group by.",
"setting.frontMatter.content.sorting.markdownDescription": "Define the sorting options for your dashboard content. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.content.sorting) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.content.sorting%22%5D)",
"setting.frontMatter.content.sorting.items.properties.id.description": "The ID of the sorting option. This will be used for the storing the last used sorting option or the default option.",
"setting.frontMatter.content.sorting.items.properties.title.description": "Name of the sorting label",
Expand Down
1 change: 1 addition & 0 deletions src/constants/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const SETTING_CONTENT_STATIC_FOLDER = 'content.publicFolder';
export const SETTING_CONTENT_FRONTMATTER_HIGHLIGHT = 'content.fmHighlight';
export const SETTING_CONTENT_DRAFT_FIELD = 'content.draftField';
export const SETTING_CONTENT_SORTING = 'content.sorting';
export const SETTING_CONTENT_GROUPING = 'content.grouping';
export const SETTING_CONTENT_FILTERS = 'content.filters';
export const SETTING_CONTENT_WYSIWYG = 'content.wysiwyg';
export const SETTING_CONTENT_PLACEHOLDERS = 'content.placeholders';
Expand Down
38 changes: 29 additions & 9 deletions src/dashboardWebView/components/Contents/Overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import { GroupingSelector, PageAtom, PagedItems, ViewSelector } from '../../stat
import { Item } from './Item';
import { List } from './List';
import usePagination from '../../hooks/usePagination';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { LocalizationKey, localize } from '../../../localization';
import { PinnedItemsAtom } from '../../state/atom/PinnedItems';
import { messageHandler } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
Expand Down Expand Up @@ -54,21 +53,37 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({

const groupName = useCallback(
(groupId, groupedPages) => {
const count = groupedPages[groupId].length;
if (grouping === GroupOption.Draft) {
return `${groupId} (${groupedPages[groupId].length})`;
return `${groupId} (${count})`;
} else if (typeof grouping === 'string') {
const group = settings?.grouping?.find((g) => g.name === grouping);
const prefix = group?.title ? `${group.title}: ` : '';
return `${prefix}${groupId} (${count})`;
}

return `${GroupOption[grouping]}: ${groupId} (${groupedPages[groupId].length})`;
return `${GroupOption[grouping]}: ${groupId} (${count})`;
},
[grouping]
[grouping, settings?.grouping]
);

const { groupKeys, groupedPages } = useMemo(() => {
if (grouping === GroupOption.none) {
return { groupKeys: [], groupedPages: {} };
}

let groupedPages = groupBy(pages, grouping === GroupOption.Year ? 'fmYear' : 'fmDraft');
let groupName: string | undefined;
if (grouping === GroupOption.Year) {
groupName = 'fmYear';
} else if (grouping === GroupOption.Draft) {
groupName = 'fmDraft';
} else if (typeof grouping === 'string') {
groupName = grouping;
} else {
return { groupKeys: [], groupedPages: {} };
}

let groupedPages = groupBy(pages, groupName);
let groupKeys = Object.keys(groupedPages);

if (grouping === GroupOption.Year) {
Expand Down Expand Up @@ -96,6 +111,8 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
...groupedPages,
}
}
} else {
groupKeys = groupKeys.sort();
}

return { groupKeys, groupedPages };
Expand Down Expand Up @@ -127,9 +144,11 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
className={`h-32 mx-auto opacity-90 mb-8 text-[var(--vscode-editor-foreground)]`}
/>
{settings && settings?.contentFolders?.length > 0 ? (
<p className={`text-xl font-medium`}>{l10n.t(LocalizationKey.dashboardContentsOverviewNoMarkdown)}</p>
<p className={`text-xl font-medium`}>{localize(LocalizationKey.dashboardContentsOverviewNoMarkdown)}</p>

) : (
<p className={`text-lg font-medium`}>{l10n.t(LocalizationKey.dashboardContentsOverviewNoFolders)}</p>
<p className={`text-lg font-medium`}>{localize(LocalizationKey.dashboardContentsOverviewNoFolders)}</p>

)}
</div>
</div>
Expand Down Expand Up @@ -176,7 +195,8 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
<div className='mb-8'>
<h1 className='text-xl flex space-x-2 items-center mb-4'>
<PinIcon className={`-rotate-45`} />
<span>{l10n.t(LocalizationKey.dashboardContentsOverviewPinned)}</span>
<span>{localize(LocalizationKey.dashboardContentsOverviewPinned)}</span>

</h1>
<List>
{pinnedPages.map((page, idx) => (
Expand Down
23 changes: 14 additions & 9 deletions src/dashboardWebView/components/Header/Grouping.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,44 @@
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { GroupOption } from '../../constants/GroupOption';
import { AllPagesAtom, GroupingAtom } from '../../state';
import { AllPagesAtom, GroupingAtom, SettingsAtom } from '../../state';
import { MenuButton, MenuItem } from '../Menu';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { LocalizationKey, localize } from '../../../localization';
import { DropdownMenu, DropdownMenuContent } from '../../../components/shadcn/Dropdown';

export interface IGroupingProps { }

export const Grouping: React.FunctionComponent<
IGroupingProps
> = () => {
const settings = useRecoilValue(SettingsAtom);
const [group, setGroup] = useRecoilState(GroupingAtom);
const pages = useRecoilValue(AllPagesAtom);

const GROUP_OPTIONS = React.useMemo(() => {
const options: { name: string, id: GroupOption }[] = [];
const options: { name: string, id?: GroupOption | string }[] = [];

if (pages.length > 0) {
if (settings?.grouping) {
const groups = settings.grouping.map((g) => ({ name: g.title, id: g.name }));
options.push(...groups);
}

if (pages.some((x) => x.fmYear)) {
options.push({ name: l10n.t(LocalizationKey.dashboardHeaderGroupingOptionYear), id: GroupOption.Year })
options.push({ name: localize(LocalizationKey.dashboardHeaderGroupingOptionYear), id: GroupOption.Year })
}

if (pages.some((x) => x.fmDraft)) {
options.push({ name: l10n.t(LocalizationKey.dashboardHeaderGroupingOptionDraft), id: GroupOption.Draft })
options.push({ name: localize(LocalizationKey.dashboardHeaderGroupingOptionDraft), id: GroupOption.Draft })
}
}

if (options.length > 0) {
options.unshift({ name: l10n.t(LocalizationKey.dashboardHeaderGroupingOptionNone), id: GroupOption.none })
options.unshift({ name: localize(LocalizationKey.dashboardHeaderGroupingOptionNone), id: GroupOption.none })
}

return options;
}, [pages])
}, [pages, settings?.grouping])

const crntGroup = GROUP_OPTIONS.find((x) => x.id === group);

Expand All @@ -43,7 +48,7 @@ export const Grouping: React.FunctionComponent<

return (
<DropdownMenu>
<MenuButton label={l10n.t(LocalizationKey.dashboardHeaderGroupingMenuButtonLabel)} title={crntGroup?.name || ''} />
<MenuButton label={localize(LocalizationKey.dashboardHeaderGroupingMenuButtonLabel)} title={crntGroup?.name || ''} />

<DropdownMenuContent>
{GROUP_OPTIONS.map((option) => (
Expand Down
1 change: 1 addition & 0 deletions src/dashboardWebView/models/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface Settings {
draftField: DraftField | null | undefined;
customSorting: SortingSetting[] | undefined;
filters: (FilterType | { title: string; name: string })[] | undefined;
grouping: { title: string; name: string }[] | undefined;
dashboardState: DashboardState;
scripts: CustomScript[];
dataFiles: DataFile[] | undefined;
Expand Down
3 changes: 3 additions & 0 deletions src/helpers/DashboardSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ExtensionState,
SETTING_CONTENT_DRAFT_FIELD,
SETTING_CONTENT_FILTERS,
SETTING_CONTENT_GROUPING,
SETTING_CONTENT_SORTING,
SETTING_CONTENT_SORTING_DEFAULT,
SETTING_DASHBOARD_OPENONSTART,
Expand Down Expand Up @@ -118,6 +119,8 @@ export class DashboardSettings {
contentFolders: await Folders.get(),
filters:
Settings.get<(FilterType | { title: string; name: string })[]>(SETTING_CONTENT_FILTERS),
grouping:
Settings.get<{ title: string; name: string }[]>(SETTING_CONTENT_GROUPING),
crntFramework: Settings.get<string>(SETTING_FRAMEWORK_ID),
framework: !isInitialized && wsFolder ? await FrameworkDetector.get(wsFolder.fsPath) : null,
scripts: Settings.get<CustomScript[]>(SETTING_CUSTOM_SCRIPTS) || [],
Expand Down
6 changes: 4 additions & 2 deletions src/helpers/SettingsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ import {
SETTING_TAXONOMY_TAGS,
SETTING_TAXONOMY_CATEGORIES,
SETTING_CONTENT_FILTERS,
SETTING_CONTENT_I18N
SETTING_CONTENT_I18N,
SETTING_CONTENT_GROUPING
} from '../constants';
import { Folders } from '../commands/Folders';
import { join, basename, dirname, parse } from 'path';
Expand Down Expand Up @@ -867,7 +868,8 @@ ${JSON.stringify(value, null, 2)}`,
settingName === SETTING_GLOBAL_NOTIFICATIONS_DISABLED ||
settingName === SETTING_MEDIA_SUPPORTED_MIMETYPES ||
settingName === SETTING_COMMA_SEPARATED_FIELDS ||
settingName === SETTING_CONTENT_FILTERS
settingName === SETTING_CONTENT_FILTERS ||
settingName === SETTING_CONTENT_GROUPING
) {
if (typeof originalConfig[key] === 'undefined') {
Settings.globalConfig[key] = value;
Expand Down

0 comments on commit 2f76de2

Please sign in to comment.