mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-06-21 02:24:43 +02:00
Insert taxonomy mappings
This commit is contained in:
@@ -294,6 +294,7 @@
|
||||
"dashboard.taxonomyView.taxonomyManager.table.heading.action": "Action",
|
||||
"dashboard.taxonomyView.taxonomyManager.table.row.empty": "No {0} found",
|
||||
"dashboard.taxonomyView.taxonomyManager.table.unmapped.title": "Missing in your settings",
|
||||
"dashboard.taxonomyView.taxonomyManager.filterInput.placeholder": "Filter",
|
||||
|
||||
"dashboard.taxonomyView.taxonomyView.navigationBar.title": "Select the taxonomy",
|
||||
"dashboard.taxonomyView.taxonomyView.button.import": "Import taxonomy",
|
||||
@@ -661,9 +662,11 @@
|
||||
"helpers.taxonomyHelper.createNew.input.placeholder": "Enter the value you want to add",
|
||||
"helpers.taxonomyHelper.createNew.input.validate.noValue": "A value must be provided.",
|
||||
"helpers.taxonomyHelper.createNew.input.validate.exists": "The value already exists.",
|
||||
"helpers.taxonomyHelper.process.insert": "{0}: Renaming \"{1}\" from {2} to {3}.",
|
||||
"helpers.taxonomyHelper.process.edit": "{0}: Renaming \"{1}\" from {2} to {3}.",
|
||||
"helpers.taxonomyHelper.process.merge": "{0}: Merging \"{1}\" from {2} to {3}.",
|
||||
"helpers.taxonomyHelper.process.delete": "{0}: Deleting \"{1}\" from {2}.",
|
||||
"helpers.taxonomyHelper.process.insert.success": "Insert completed.",
|
||||
"helpers.taxonomyHelper.process.edit.success": "Edit completed.",
|
||||
"helpers.taxonomyHelper.process.merge.success": "Merge completed.",
|
||||
"helpers.taxonomyHelper.process.delete.success": "Deletion completed.",
|
||||
|
||||
@@ -64,6 +64,7 @@ export enum DashboardMessage {
|
||||
createTaxonomy = 'createTaxonomy',
|
||||
importTaxonomy = 'importTaxonomy',
|
||||
moveTaxonomy = 'moveTaxonomy',
|
||||
mapTaxonomy = 'mapTaxonomy',
|
||||
|
||||
// Other
|
||||
getTheme = 'getTheme',
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import useThemeColors from '../../hooks/useThemeColors';
|
||||
|
||||
export interface IButtonProps {
|
||||
secondary?: boolean;
|
||||
@@ -15,19 +14,14 @@ export const Button: React.FunctionComponent<IButtonProps> = ({
|
||||
secondary,
|
||||
children
|
||||
}: React.PropsWithChildren<IButtonProps>) => {
|
||||
const { getColors } = useThemeColors();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`${className || ''
|
||||
} inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium focus:outline-none rounded ${getColors(
|
||||
'text-white dark:text-vulcan-500 disabled:bg-gray-500',
|
||||
'disabled:opacity-50'
|
||||
)
|
||||
} ${secondary ?
|
||||
getColors(`bg-red-300 hover:bg-red-400`, `bg-[var(--vscode-button-secondaryBackground)] text-[--vscode-button-secondaryForeground] hover:bg-[var(--vscode-button-secondaryHoverBackground)]`) :
|
||||
getColors(`bg-teal-600 hover:bg-teal-700`, `bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)] hover:bg-[var(--frontmatter-button-hoverBackground)]`)
|
||||
} inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium focus:outline-none rounded disabled:opacity-50 ${secondary ?
|
||||
`bg-[var(--vscode-button-secondaryBackground)] text-[--vscode-button-secondaryForeground] hover:bg-[var(--vscode-button-secondaryHoverBackground)]` :
|
||||
`bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)] hover:bg-[var(--frontmatter-button-hoverBackground)]`
|
||||
}
|
||||
`}
|
||||
onClick={onClick}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import { useForm } from 'uniforms';
|
||||
import { SubmitField } from 'uniforms-unstyled';
|
||||
import useThemeColors from '../../hooks/useThemeColors';
|
||||
import { Button } from '../Common/Button';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { SubmitField } from '../../../components/uniforms-frontmatter';
|
||||
|
||||
export interface IDataFormControlsProps {
|
||||
model: any | null;
|
||||
@@ -16,10 +15,9 @@ export const DataFormControls: React.FunctionComponent<IDataFormControlsProps> =
|
||||
onClear
|
||||
}: React.PropsWithChildren<IDataFormControlsProps>) => {
|
||||
const { formRef } = useForm();
|
||||
const { getColors } = useThemeColors();
|
||||
|
||||
return (
|
||||
<div className={`text-right ${getColors(`border-gray-200 dark:border-vulcan-300`, `border-[var(--frontmatter-border)]`)}`}>
|
||||
<div className={`text-right border-[var(--frontmatter-border)]`}>
|
||||
<SubmitField value={model ? `Update` : `Add`} />
|
||||
|
||||
<Button
|
||||
|
||||
@@ -10,7 +10,6 @@ import { SettingsSelector } from '../../state';
|
||||
import { getTaxonomyField } from '../../../helpers/getTaxonomyField';
|
||||
import { TaxonomyActions } from './TaxonomyActions';
|
||||
import { TaxonomyLookup } from './TaxonomyLookup';
|
||||
import useThemeColors from '../../hooks/useThemeColors';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { FilterInput } from './FilterInput';
|
||||
@@ -31,7 +30,6 @@ export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = (
|
||||
onContentTagging
|
||||
}: React.PropsWithChildren<ITaxonomyManagerProps>) => {
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const { getColors } = useThemeColors();
|
||||
const [filterValue, setFilterValue] = React.useState('');
|
||||
const debounceFilterValue = useDebounce<string>(filterValue, 500);
|
||||
const prevTaxonomy = usePrevious<string | null>(taxonomy);
|
||||
@@ -143,35 +141,23 @@ export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = (
|
||||
<div className={`py-6 px-4 flex flex-col h-full overflow-hidden`}>
|
||||
<div className={`flex w-full justify-between flex-shrink-0`}>
|
||||
<div>
|
||||
<h2 className={`text-lg first-letter:uppercase ${getColors(
|
||||
'text-gray-500 dark:text-whisper-900',
|
||||
'text-[var(--frontmatter-text)]'
|
||||
)
|
||||
}`}>
|
||||
<h2 className={`text-lg first-letter:uppercase text-[var(--frontmatter-text)]`}>
|
||||
{taxonomy}
|
||||
</h2>
|
||||
<p className={`mt-2 text-sm first-letter:uppercase ${getColors(
|
||||
'text-gray-500 dark:text-whisper-900',
|
||||
'text-[var(--frontmatter-secondary-text)]'
|
||||
)
|
||||
}`}>
|
||||
<p className={`mt-2 text-sm first-letter:uppercase text-[var(--frontmatter-secondary-text)]`}>
|
||||
{l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerDescription, taxonomy)}
|
||||
</p>
|
||||
</div>
|
||||
<div className='flex gap-4 justify-center items-center'>
|
||||
<FilterInput
|
||||
placeholder='Filter'
|
||||
placeholder={l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerFilterInputPlaceholder, taxonomy)}
|
||||
value={filterValue}
|
||||
onChange={(value) => setFilterValue(value)}
|
||||
onReset={() => setFilterValue('')} />
|
||||
|
||||
<div>
|
||||
<button
|
||||
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium focus:outline-none rounded ${getColors(
|
||||
`text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 disabled:bg-gray-500`,
|
||||
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
|
||||
)
|
||||
}`}
|
||||
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium focus:outline-none rounded text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
|
||||
title={l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerButtonCreate, taxonomy)}
|
||||
onClick={onCreate}
|
||||
>
|
||||
@@ -183,38 +169,38 @@ export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = (
|
||||
</div>
|
||||
|
||||
<div className="mt-6 pb-6 -mr-4 pr-4 flex flex-col flex-grow overflow-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200 dark:divide-vulcan-300">
|
||||
<table className="min-w-full divide-y divide-[var(--frontmatter-border)]">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-xs font-medium uppercase ${getColors('text-gray-500 dark:text-whisper-900', 'text-[var(--frontmatter-secondary-text)]')}`}
|
||||
className={`px-6 py-3 text-left text-xs font-medium uppercase text-[var(--frontmatter-secondary-text)]'`}
|
||||
>
|
||||
{l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerTableHeadingName)}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-xs font-medium uppercase ${getColors('text-gray-500 dark:text-whisper-900', 'text-[var(--frontmatter-secondary-text)]')}`}
|
||||
className={`px-6 py-3 text-left text-xs font-medium uppercase text-[var(--frontmatter-secondary-text)]`}
|
||||
>
|
||||
{l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerTableHeadingCount)}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-right text-xs font-medium uppercase ${getColors('text-gray-500 dark:text-whisper-900', 'text-[var(--frontmatter-secondary-text)]')}`}
|
||||
className={`px-6 py-3 text-right text-xs font-medium uppercase text-[var(--frontmatter-secondary-text)]`}
|
||||
>
|
||||
{l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerTableHeadingAction)}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className={`divide-y ${getColors(`divide-gray-200 dark:divide-vulcan-300`, `divide-[var(--frontmatter-border)]`)}`}>
|
||||
<tbody className={`divide-y divide-[var(--frontmatter-border)]`}>
|
||||
{items && items.length > 0
|
||||
? items.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-sm font-medium ${getColors(`text-gray-800 dark:text-gray-200`, `text-[var(--frontmatter-text)]`)}`}>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}>
|
||||
<TagIcon className="inline-block h-4 w-4 mr-2" />
|
||||
<span>{item}</span>
|
||||
</td>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-sm font-medium ${getColors(`text-gray-800 dark:text-gray-200`, `text-[var(--frontmatter-text)]`)}`}>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}>
|
||||
<TaxonomyLookup taxonomy={taxonomy} value={item} pages={pages} />
|
||||
</td>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-right text-sm font-medium`}>
|
||||
@@ -226,7 +212,7 @@ export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = (
|
||||
(unmappedItems.length === 0 && (
|
||||
<tr>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm font-medium ${getColors(`text-gray-800 dark:text-gray-200`, `text-[var(--frontmatter-text)]`)}`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}
|
||||
colSpan={4}
|
||||
>
|
||||
{l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerTableRowEmpty, taxonomy)}
|
||||
@@ -239,13 +225,13 @@ export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = (
|
||||
unmappedItems.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm font-medium ${getColors(`text-gray-800 dark:text-gray-200`, `text-[var(--frontmatter-text)]`)}`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}
|
||||
title={l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerTableUnmappedTitle)}
|
||||
>
|
||||
<ExclamationTriangleIcon className="inline-block h-4 w-4 mr-2" />
|
||||
<span>{item}</span>
|
||||
</td>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-sm font-medium ${getColors(`text-gray-800 dark:text-gray-200`, `text-[var(--frontmatter-text)]`)}`}>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}>
|
||||
<TaxonomyLookup taxonomy={taxonomy} value={item} pages={pages} />
|
||||
</td>
|
||||
<td className={`px-6 py-4 whitespace-nowrap text-right text-sm font-medium`}>
|
||||
|
||||
@@ -5,11 +5,16 @@ import { SettingsSelector } from '../../state';
|
||||
import { getTaxonomyField } from '../../../helpers/getTaxonomyField';
|
||||
import { Sorting } from '../../../helpers/Sorting';
|
||||
import { ArrowLeftIcon } from '@heroicons/react/24/outline';
|
||||
import { Button } from '../Common/Button';
|
||||
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
|
||||
import { FilterInput } from './FilterInput';
|
||||
import { useDebounce } from '../../../hooks/useDebounce';
|
||||
|
||||
export interface ITaxonomyTaggingProps {
|
||||
taxonomy: string | null;
|
||||
value: string;
|
||||
pages: Page[];
|
||||
onContentMapping: (value: string, pages: Page[]) => void;
|
||||
onDismiss: () => void;
|
||||
}
|
||||
|
||||
@@ -17,9 +22,28 @@ export const TaxonomyTagging: React.FunctionComponent<ITaxonomyTaggingProps> = (
|
||||
taxonomy,
|
||||
value,
|
||||
pages,
|
||||
onDismiss
|
||||
onContentMapping,
|
||||
onDismiss,
|
||||
}: React.PropsWithChildren<ITaxonomyTaggingProps>) => {
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const [selectedPages, setSelectedPages] = React.useState<Page[]>([]);
|
||||
const [filterValue, setFilterValue] = React.useState('');
|
||||
const debounceFilterValue = useDebounce<string>(filterValue, 500);
|
||||
|
||||
const onCheckboxClick = React.useCallback((page: Page) => {
|
||||
const pageIdx = selectedPages.findIndex((p: Page) => p.fmFilePath === page.fmFilePath);
|
||||
if (pageIdx === -1) {
|
||||
setSelectedPages([...selectedPages, page]);
|
||||
} else {
|
||||
const newSelectedPages = [...selectedPages];
|
||||
newSelectedPages.splice(pageIdx, 1);
|
||||
setSelectedPages(newSelectedPages);
|
||||
}
|
||||
}, [selectedPages]);
|
||||
|
||||
const checkIfChecked = React.useCallback((page: Page) => {
|
||||
return selectedPages.find((p: Page) => p.fmFilePath === page.fmFilePath);
|
||||
}, [selectedPages]);
|
||||
|
||||
const untaggedPages = React.useMemo(() => {
|
||||
let untagged: Page[] = [];
|
||||
@@ -56,32 +80,80 @@ export const TaxonomyTagging: React.FunctionComponent<ITaxonomyTaggingProps> = (
|
||||
|
||||
untagged = untagged.sort(Sorting.number('fmPublished')).reverse();
|
||||
|
||||
if (debounceFilterValue) {
|
||||
return untagged.filter((p) => p.title.toLowerCase().includes(debounceFilterValue.toLowerCase()));
|
||||
}
|
||||
|
||||
return untagged;
|
||||
}, [pages, taxonomy, value]);
|
||||
}, [pages, taxonomy, value, debounceFilterValue]);
|
||||
|
||||
console.log(`Selected pages`, selectedPages)
|
||||
|
||||
return (
|
||||
<div className={`py-6 px-4 flex flex-col h-full overflow-hidden`}>
|
||||
<div className={`flex w-full justify-between flex-shrink-0`}>
|
||||
<h2 className='text-lg first-letter:uppercase flex items-center'>
|
||||
|
||||
<button onClick={onDismiss} title='Back' className='mr-2'>
|
||||
<div className={`flex gap-2 items-center`}>
|
||||
<button onClick={onDismiss} title='Back'>
|
||||
<span className='sr-only'>Back</span>
|
||||
<ArrowLeftIcon className='w-5 h-5 text-[var(--frontmatter-text)]' />
|
||||
</button>
|
||||
|
||||
{taxonomy}: {value}
|
||||
</h2>
|
||||
<h2 className={`text-lg first-letter:uppercase text-[var(--frontmatter-text)]`}>
|
||||
Map your content with: {value} <span className='ml-2'></span>
|
||||
</h2>
|
||||
</div>
|
||||
<div className='flex gap-4 justify-center items-center'>
|
||||
<FilterInput
|
||||
placeholder='Filter'
|
||||
value={filterValue}
|
||||
onChange={(value) => setFilterValue(value)}
|
||||
onReset={() => setFilterValue('')} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-6 -mr-4 pr-4 flex flex-col flex-grow overflow-auto'>
|
||||
<ul>
|
||||
{untaggedPages.map((page) => (
|
||||
<li key={page.fmFilePath}>
|
||||
<input type='checkbox' />
|
||||
<span>{page.title}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className='mt-6 mb-2 -mr-4 pr-4 flex flex-col flex-grow overflow-auto'>
|
||||
<table className="min-w-full divide-y divide-[var(--frontmatter-border)]">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
className={``}
|
||||
>
|
||||
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`pr-6 py-3 text-left text-xs font-medium uppercase text-[var(--frontmatter-secondary-text)]`}
|
||||
>
|
||||
Name
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className={`divide-y divide-[var(--frontmatter-border)]`}>
|
||||
{untaggedPages.map((page) => (
|
||||
<tr key={page.fmFilePath} className='py-2'>
|
||||
<td className={`pl-6 w-[25px]`}>
|
||||
<VSCodeCheckbox
|
||||
onClick={() => onCheckboxClick(page)}
|
||||
checked={checkIfChecked(page)}>
|
||||
<span className='sr-only'>Tag page</span>
|
||||
</VSCodeCheckbox>
|
||||
</td>
|
||||
<td className={`pr-6 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}>
|
||||
<button
|
||||
title={page.title}
|
||||
onClick={() => onCheckboxClick(page)}>
|
||||
{page.title}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-end space-x-2'>
|
||||
<Button onClick={onDismiss} secondary>Cancel</Button>
|
||||
<Button onClick={() => onContentMapping(value, selectedPages)}>Apply</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { ChevronRightIcon, ArrowDownTrayIcon } from '@heroicons/react/24/outline';
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -32,6 +32,16 @@ export const TaxonomyView: React.FunctionComponent<ITaxonomyViewProps> = ({
|
||||
Messenger.send(DashboardMessage.importTaxonomy);
|
||||
};
|
||||
|
||||
const onContentMapping = React.useCallback((value: string, pages: Page[]) => {
|
||||
messageHandler.request(DashboardMessage.mapTaxonomy, {
|
||||
taxonomy: selectedTaxonomy,
|
||||
value,
|
||||
pages
|
||||
}).then(() => {
|
||||
setContentTagging(null);
|
||||
});
|
||||
}, [selectedTaxonomy]);
|
||||
|
||||
useEffect(() => {
|
||||
setTaxonomySettings({
|
||||
tags: settings?.tags || [],
|
||||
@@ -107,6 +117,7 @@ export const TaxonomyView: React.FunctionComponent<ITaxonomyViewProps> = ({
|
||||
value={contentTagging}
|
||||
taxonomy={selectedTaxonomy}
|
||||
pages={pages}
|
||||
onContentMapping={(value: string, pages: Page[]) => onContentMapping(value, pages)}
|
||||
onDismiss={() => setContentTagging(null)} />
|
||||
) : (
|
||||
<TaxonomyManager
|
||||
|
||||
@@ -130,10 +130,10 @@
|
||||
}
|
||||
|
||||
input[type='submit'] {
|
||||
@apply mt-4 inline-flex w-auto cursor-pointer items-center border border-transparent bg-teal-600 px-3 py-2 text-sm font-medium leading-4 text-white;
|
||||
@apply mt-4 inline-flex w-auto items-center rounded border border-transparent bg-[var(--frontmatter-button-background)] px-3 py-2 text-sm font-medium leading-4 text-[var(--vscode-button-foreground)];
|
||||
|
||||
&:hover {
|
||||
@apply bg-teal-700;
|
||||
@apply bg-[var(--frontmatter-button-hoverBackground)];
|
||||
}
|
||||
|
||||
&:focus {
|
||||
@@ -141,7 +141,7 @@
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@apply bg-gray-500 opacity-50;
|
||||
@apply opacity-50;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import { SettingsListener as PanelSettingsListener } from '../listeners/panel';
|
||||
import { SettingsListener as DashboardSettingsListener } from '../listeners/dashboard';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { Page } from '../dashboardWebView/models';
|
||||
|
||||
export class TaxonomyHelper {
|
||||
private static db: JsonDB;
|
||||
@@ -262,13 +263,14 @@ export class TaxonomyHelper {
|
||||
* @returns
|
||||
*/
|
||||
public static async process(
|
||||
type: 'edit' | 'merge' | 'delete',
|
||||
type: 'insert' | 'edit' | 'merge' | 'delete',
|
||||
taxonomyType: TaxonomyType | string,
|
||||
oldValue: string,
|
||||
newValue?: string
|
||||
newValue?: string,
|
||||
pages?: Page[]
|
||||
) {
|
||||
// Retrieve all the markdown files
|
||||
const allFiles = await FilesHelper.getAllFiles();
|
||||
const allFiles = type === 'insert' ? pages : await FilesHelper.getAllFiles();
|
||||
if (!allFiles) {
|
||||
return;
|
||||
}
|
||||
@@ -284,7 +286,14 @@ export class TaxonomyHelper {
|
||||
|
||||
let progressText = ``;
|
||||
|
||||
if (type === 'edit') {
|
||||
if (type === 'insert') {
|
||||
progressText = l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperProcessInsert,
|
||||
EXTENSION_NAME,
|
||||
taxonomyName,
|
||||
newValue || ''
|
||||
);
|
||||
} else if (type === 'edit') {
|
||||
progressText = l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperProcessEdit,
|
||||
EXTENSION_NAME,
|
||||
@@ -309,7 +318,7 @@ export class TaxonomyHelper {
|
||||
);
|
||||
}
|
||||
|
||||
window.withProgress(
|
||||
await window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: progressText,
|
||||
@@ -324,7 +333,8 @@ export class TaxonomyHelper {
|
||||
for (const file of allFiles) {
|
||||
progress.report({ increment: ++i / progressNr });
|
||||
|
||||
const mdFile = await readFileAsync(parseWinPath(file.fsPath), {
|
||||
const filePath = type === 'insert' ? (file as Page).fmFilePath : file.fsPath;
|
||||
const mdFile = await readFileAsync(parseWinPath(filePath), {
|
||||
encoding: 'utf8'
|
||||
});
|
||||
|
||||
@@ -342,7 +352,27 @@ export class TaxonomyHelper {
|
||||
taxonomies = taxonomies.split(`,`);
|
||||
}
|
||||
|
||||
if (taxonomies && taxonomies.length > 0) {
|
||||
const spaces = window.activeTextEditor?.options?.tabSize;
|
||||
|
||||
if (type === 'insert' && newValue) {
|
||||
if (taxonomies && taxonomies.length > 0) {
|
||||
taxonomies.push(newValue);
|
||||
} else {
|
||||
taxonomies = [newValue];
|
||||
}
|
||||
|
||||
const newTaxValue = [...new Set(taxonomies)].sort();
|
||||
ContentType.setFieldValue(data, fieldNames, newTaxValue);
|
||||
|
||||
// Update the file
|
||||
await writeFileAsync(
|
||||
parseWinPath(filePath),
|
||||
FrontMatterParser.toFile(article.content, article.data, mdFile, {
|
||||
indent: spaces || 2
|
||||
} as DumpOptions as any),
|
||||
{ encoding: 'utf8' }
|
||||
);
|
||||
} else if (type !== 'insert' && taxonomies && taxonomies.length > 0) {
|
||||
const idx = taxonomies.findIndex((o) => o === oldValue);
|
||||
|
||||
if (idx !== -1) {
|
||||
@@ -355,7 +385,6 @@ export class TaxonomyHelper {
|
||||
const newTaxValue = [...new Set(taxonomies)].sort();
|
||||
ContentType.setFieldValue(data, fieldNames, newTaxValue);
|
||||
|
||||
const spaces = window.activeTextEditor?.options?.tabSize;
|
||||
// Update the file
|
||||
await writeFileAsync(
|
||||
parseWinPath(file.fsPath),
|
||||
@@ -375,7 +404,9 @@ export class TaxonomyHelper {
|
||||
|
||||
await this.addToSettings(taxonomyType, oldValue, newValue);
|
||||
|
||||
if (type === 'edit') {
|
||||
if (type === 'insert') {
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperProcessInsertSuccess));
|
||||
} else if (type === 'edit') {
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperProcessEditSuccess));
|
||||
} else if (type === 'merge') {
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperProcessMergeSuccess));
|
||||
@@ -502,6 +533,21 @@ export class TaxonomyHelper {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the taxonomy type based from the string
|
||||
* @param taxonomyType
|
||||
* @returns
|
||||
*/
|
||||
public static getTypeFromString(taxonomyType: string): TaxonomyType | string {
|
||||
if (taxonomyType === 'tags') {
|
||||
return TaxonomyType.Tag;
|
||||
} else if (taxonomyType === 'categories') {
|
||||
return TaxonomyType.Category;
|
||||
} else {
|
||||
return taxonomyType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the fields for the taxonomy field
|
||||
* @returns
|
||||
@@ -587,19 +633,4 @@ export class TaxonomyHelper {
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the taxonomy type based from the string
|
||||
* @param taxonomyType
|
||||
* @returns
|
||||
*/
|
||||
private static getTypeFromString(taxonomyType: string): TaxonomyType | string {
|
||||
if (taxonomyType === 'tags') {
|
||||
return TaxonomyType.Tag;
|
||||
} else if (taxonomyType === 'categories') {
|
||||
return TaxonomyType.Category;
|
||||
} else {
|
||||
return taxonomyType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
|
||||
import { TaxonomyHelper } from '../../helpers';
|
||||
import { PostMessageData } from '../../models';
|
||||
import { BaseListener } from './BaseListener';
|
||||
import { Page } from '../../dashboardWebView/models';
|
||||
|
||||
export class TaxonomyListener extends BaseListener {
|
||||
/**
|
||||
@@ -39,9 +40,36 @@ export class TaxonomyListener extends BaseListener {
|
||||
case DashboardMessage.importTaxonomy:
|
||||
commands.executeCommand(COMMAND_NAME.exportTaxonomy);
|
||||
break;
|
||||
case DashboardMessage.mapTaxonomy:
|
||||
TaxonomyListener.mapTaxonomy(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static async mapTaxonomy({
|
||||
command,
|
||||
requestId,
|
||||
payload: { taxonomy, value, pages }
|
||||
}: {
|
||||
command: string;
|
||||
requestId?: string;
|
||||
payload: { taxonomy: string; value: string; pages: Page[] };
|
||||
}) {
|
||||
if (!command || !requestId || !taxonomy || !value || !pages) {
|
||||
return;
|
||||
}
|
||||
|
||||
await TaxonomyHelper.process(
|
||||
'insert',
|
||||
TaxonomyHelper.getTypeFromString(taxonomy),
|
||||
'',
|
||||
value,
|
||||
pages
|
||||
);
|
||||
|
||||
this.sendRequest(command as any, requestId, {});
|
||||
}
|
||||
|
||||
private static getData() {
|
||||
// Retrieve the tags, categories and custom taxonomy
|
||||
const taxonomyData = TaxonomyHelper.getAll();
|
||||
|
||||
@@ -975,6 +975,10 @@ export enum LocalizationKey {
|
||||
* Missing in your settings
|
||||
*/
|
||||
dashboardTaxonomyViewTaxonomyManagerTableUnmappedTitle = 'dashboard.taxonomyView.taxonomyManager.table.unmapped.title',
|
||||
/**
|
||||
* Filter
|
||||
*/
|
||||
dashboardTaxonomyViewTaxonomyManagerFilterInputPlaceholder = 'dashboard.taxonomyView.taxonomyManager.filterInput.placeholder',
|
||||
/**
|
||||
* Select the taxonomy
|
||||
*/
|
||||
@@ -2172,6 +2176,10 @@ export enum LocalizationKey {
|
||||
* The value already exists.
|
||||
*/
|
||||
helpersTaxonomyHelperCreateNewInputValidateExists = 'helpers.taxonomyHelper.createNew.input.validate.exists',
|
||||
/**
|
||||
* {0}: Renaming "{1}" from {2} to {3}.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessInsert = 'helpers.taxonomyHelper.process.insert',
|
||||
/**
|
||||
* {0}: Renaming "{1}" from {2} to {3}.
|
||||
*/
|
||||
@@ -2184,6 +2192,10 @@ export enum LocalizationKey {
|
||||
* {0}: Deleting "{1}" from {2}.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessDelete = 'helpers.taxonomyHelper.process.delete',
|
||||
/**
|
||||
* Insert completed.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessInsertSuccess = 'helpers.taxonomyHelper.process.insert.success',
|
||||
/**
|
||||
* Edit completed.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user