mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-07-04 00:41:00 +02:00
Merge branch 'issue/566' into dev
This commit is contained in:
+183
-98
@@ -12,7 +12,7 @@ import {
|
||||
} from './../constants';
|
||||
import { ArticleHelper } from './../helpers/ArticleHelper';
|
||||
import { join } from 'path';
|
||||
import { commands, env, Uri, ViewColumn, window } from 'vscode';
|
||||
import { commands, env, Uri, ViewColumn, window, WebviewPanel } from 'vscode';
|
||||
import { Extension, parseWinPath, processKnownPlaceholders, Settings } from '../helpers';
|
||||
import { ContentFolder, ContentType, PreviewSettings } from '../models';
|
||||
import { format } from 'date-fns';
|
||||
@@ -21,8 +21,13 @@ import { Article } from '.';
|
||||
import { urlJoin } from 'url-join-ts';
|
||||
import { WebviewHelper } from '@estruyf/vscode';
|
||||
import { Folders } from './Folders';
|
||||
import { DataListener } from '../listeners/panel';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
|
||||
export class Preview {
|
||||
public static filePath: string | undefined = undefined;
|
||||
public static webviews: { [filePath: string]: WebviewPanel } = {};
|
||||
|
||||
/**
|
||||
* Init the preview
|
||||
*/
|
||||
@@ -42,13 +47,179 @@ export class Preview {
|
||||
}
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
const crntFilePath = editor?.document.uri.fsPath;
|
||||
this.filePath = crntFilePath;
|
||||
|
||||
if (crntFilePath && this.webviews[crntFilePath]) {
|
||||
this.webviews[crntFilePath].reveal();
|
||||
return;
|
||||
}
|
||||
|
||||
const article = editor ? ArticleHelper.getFrontMatter(editor) : null;
|
||||
const slug = await this.getContentSlug(article, editor?.document.uri.fsPath);
|
||||
|
||||
// Create the preview webview
|
||||
const webView = window.createWebviewPanel(
|
||||
'frontMatterPreview',
|
||||
article?.data?.title ? `Preview: ${article?.data?.title}` : 'FrontMatter Preview',
|
||||
{
|
||||
viewColumn: ViewColumn.Beside,
|
||||
preserveFocus: true
|
||||
},
|
||||
{
|
||||
enableScripts: true
|
||||
}
|
||||
);
|
||||
|
||||
if (crntFilePath) {
|
||||
this.webviews[crntFilePath] = webView;
|
||||
}
|
||||
|
||||
webView.iconPath = {
|
||||
dark: Uri.file(join(extensionPath, 'assets/icons/frontmatter-short-dark.svg')),
|
||||
light: Uri.file(join(extensionPath, 'assets/icons/frontmatter-short-light.svg'))
|
||||
};
|
||||
|
||||
const localhostUrl = await this.getLocalServerUrl();
|
||||
|
||||
const cspSource = webView.webview.cspSource;
|
||||
|
||||
webView.onDidDispose(() => {
|
||||
this.filePath = undefined;
|
||||
if (crntFilePath) {
|
||||
delete this.webviews[crntFilePath];
|
||||
}
|
||||
webView.dispose();
|
||||
});
|
||||
|
||||
webView.onDidChangeViewState(async (e) => {
|
||||
if (e.webviewPanel.visible) {
|
||||
this.filePath = crntFilePath;
|
||||
|
||||
if (crntFilePath) {
|
||||
const article = await ArticleHelper.getFrontMatterByPath(crntFilePath);
|
||||
DataListener.pushMetadata(article?.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
webView.webview.onDidReceiveMessage((message) => {
|
||||
switch (message.command) {
|
||||
case PreviewCommands.toVSCode.open:
|
||||
if (message.data) {
|
||||
commands.executeCommand('vscode.open', message.data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const dashboardFile = 'dashboardWebView.js';
|
||||
const localPort = `9000`;
|
||||
const localServerUrl = `localhost:${localPort}`;
|
||||
|
||||
const nonce = WebviewHelper.getNonce();
|
||||
|
||||
const ext = Extension.getInstance();
|
||||
const isProd = ext.isProductionMode;
|
||||
const version = ext.getVersion();
|
||||
const isBeta = ext.isBetaVersion();
|
||||
const extensionUri = ext.extensionPath;
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${localhostUrl} ${cspSource} http: https:;`,
|
||||
`script-src ${
|
||||
isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
} 'unsafe-eval'`,
|
||||
`style-src ${cspSource} 'self' 'unsafe-inline' http: https:`,
|
||||
`connect-src https://o1022172.ingest.sentry.io ${
|
||||
isProd
|
||||
? ``
|
||||
: `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
}`,
|
||||
`frame-src ${localhostUrl} ${cspSource} http: https:;`
|
||||
];
|
||||
|
||||
let scriptUri = '';
|
||||
if (isProd) {
|
||||
scriptUri = webView.webview
|
||||
.asWebviewUri(Uri.joinPath(extensionUri, 'dist', dashboardFile))
|
||||
.toString();
|
||||
} else {
|
||||
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
|
||||
}
|
||||
|
||||
// Get experimental setting
|
||||
const experimental = Settings.get(SETTING_EXPERIMENTAL);
|
||||
|
||||
webView.webview.html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="${csp.join('; ')}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Front Matter Preview</title>
|
||||
</head>
|
||||
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden">
|
||||
<div id="app" data-type="preview" data-url="${urlJoin(
|
||||
localhostUrl.toString(),
|
||||
slug || ''
|
||||
)}" data-isProd="${isProd}" data-environment="${
|
||||
isBeta ? 'BETA' : 'main'
|
||||
}" data-version="${version.usedVersion}" ${
|
||||
experimental ? `data-experimental="${experimental}"` : ''
|
||||
} style="width:100%;height:100%;margin:0;padding:0;"></div>
|
||||
|
||||
<script ${isProd ? `nonce="${nonce}"` : ''} src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Telemetry.send(TelemetryEvent.openPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the url of the preview webview
|
||||
* @param filePath
|
||||
* @param slug
|
||||
*/
|
||||
public static async updatePageUrl(filePath: string, slug?: string) {
|
||||
const webView = this.webviews[filePath];
|
||||
if (webView) {
|
||||
const localhost = await this.getLocalServerUrl();
|
||||
const article = await ArticleHelper.getFrontMatterByPath(filePath);
|
||||
const slug = await this.getContentSlug(article, filePath);
|
||||
|
||||
webView.webview.postMessage({
|
||||
command: PreviewCommands.toWebview.updateUrl,
|
||||
payload: urlJoin(localhost.toString(), slug || '')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the slug of the content
|
||||
* @param article
|
||||
* @param filePath
|
||||
* @returns
|
||||
*/
|
||||
private static async getContentSlug(
|
||||
article: ParsedFrontMatter | null,
|
||||
filePath?: string
|
||||
): Promise<string | undefined> {
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
let slug = article?.data ? article.data.slug : '';
|
||||
|
||||
const settings = this.getSettings();
|
||||
let pathname = settings.pathname;
|
||||
|
||||
let selectedFolder: ContentFolder | undefined | null = null;
|
||||
const filePath = parseWinPath(editor?.document.uri.fsPath);
|
||||
filePath = parseWinPath(filePath);
|
||||
|
||||
let contentType: ContentType | undefined = undefined;
|
||||
if (article?.data) {
|
||||
@@ -143,104 +314,18 @@ export class Preview {
|
||||
slug = slug.substring(0, slug.endsWith('_index') ? slug.length - 6 : slug.length - 5);
|
||||
}
|
||||
|
||||
// Create the preview webview
|
||||
const webView = window.createWebviewPanel(
|
||||
'frontMatterPreview',
|
||||
article?.data?.title ? `Preview: ${article?.data?.title}` : 'FrontMatter Preview',
|
||||
{
|
||||
viewColumn: ViewColumn.Beside,
|
||||
preserveFocus: true
|
||||
},
|
||||
{
|
||||
enableScripts: true
|
||||
}
|
||||
);
|
||||
return slug;
|
||||
}
|
||||
|
||||
webView.iconPath = {
|
||||
dark: Uri.file(join(extensionPath, 'assets/icons/frontmatter-short-dark.svg')),
|
||||
light: Uri.file(join(extensionPath, 'assets/icons/frontmatter-short-light.svg'))
|
||||
};
|
||||
|
||||
const crntUrl = settings.host.startsWith('http') ? settings.host : `http://${settings.host}`;
|
||||
/**
|
||||
* Retrieve the localhost url
|
||||
* @returns
|
||||
*/
|
||||
private static async getLocalServerUrl() {
|
||||
const settings = Preview.getSettings();
|
||||
const crntUrl = settings?.host?.startsWith('http') ? settings.host : `http://${settings.host}`;
|
||||
const localhostUrl = await env.asExternalUri(Uri.parse(crntUrl));
|
||||
|
||||
const cspSource = webView.webview.cspSource;
|
||||
|
||||
webView.webview.onDidReceiveMessage((message) => {
|
||||
switch (message.command) {
|
||||
case PreviewCommands.toVSCode.open:
|
||||
if (message.data) {
|
||||
commands.executeCommand('vscode.open', message.data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const dashboardFile = 'dashboardWebView.js';
|
||||
const localPort = `9000`;
|
||||
const localServerUrl = `localhost:${localPort}`;
|
||||
|
||||
const nonce = WebviewHelper.getNonce();
|
||||
|
||||
const ext = Extension.getInstance();
|
||||
const isProd = ext.isProductionMode;
|
||||
const version = ext.getVersion();
|
||||
const isBeta = ext.isBetaVersion();
|
||||
const extensionUri = ext.extensionPath;
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${localhostUrl} ${cspSource} http: https:;`,
|
||||
`script-src ${
|
||||
isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
} 'unsafe-eval'`,
|
||||
`style-src ${cspSource} 'self' 'unsafe-inline' http: https:`,
|
||||
`connect-src https://o1022172.ingest.sentry.io ${
|
||||
isProd
|
||||
? ``
|
||||
: `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
}`,
|
||||
`frame-src ${localhostUrl} ${cspSource} http: https:;`
|
||||
];
|
||||
|
||||
let scriptUri = '';
|
||||
if (isProd) {
|
||||
scriptUri = webView.webview
|
||||
.asWebviewUri(Uri.joinPath(extensionUri, 'dist', dashboardFile))
|
||||
.toString();
|
||||
} else {
|
||||
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
|
||||
}
|
||||
|
||||
// Get experimental setting
|
||||
const experimental = Settings.get(SETTING_EXPERIMENTAL);
|
||||
|
||||
webView.webview.html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="${csp.join('; ')}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Front Matter Preview</title>
|
||||
</head>
|
||||
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden">
|
||||
<div id="app" data-type="preview" data-url="${urlJoin(
|
||||
localhostUrl.toString(),
|
||||
slug || ''
|
||||
)}" data-isProd="${isProd}" data-environment="${
|
||||
isBeta ? 'BETA' : 'main'
|
||||
}" data-version="${version.usedVersion}" ${
|
||||
experimental ? `data-experimental="${experimental}"` : ''
|
||||
} style="width:100%;height:100%;margin:0;padding:0;"></div>
|
||||
|
||||
<script ${isProd ? `nonce="${nonce}"` : ''} src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Telemetry.send(TelemetryEvent.openPreview);
|
||||
return localhostUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@ import { ContentType } from '../helpers/ContentType';
|
||||
import { DataListener } from '../listeners/panel';
|
||||
import { commands } from 'vscode';
|
||||
import { Field } from '../models';
|
||||
import { Preview } from './Preview';
|
||||
|
||||
export class StatusListener {
|
||||
/**
|
||||
@@ -36,11 +37,20 @@ export class StatusListener {
|
||||
}
|
||||
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor && ArticleHelper.isSupportedFile()) {
|
||||
let document = editor?.document;
|
||||
|
||||
if (!document) {
|
||||
const filePath = Preview.filePath;
|
||||
if (filePath) {
|
||||
document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath));
|
||||
}
|
||||
}
|
||||
|
||||
if (document && ArticleHelper.isSupportedFile(document)) {
|
||||
try {
|
||||
commands.executeCommand('setContext', CONTEXT.isValidFile, true);
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
const article = await ArticleHelper.getFrontMatterByPath(document.uri.fsPath);
|
||||
|
||||
// Update the StatusBar based on the article draft state
|
||||
if (article && typeof article.data['draft'] !== 'undefined') {
|
||||
@@ -65,16 +75,18 @@ export class StatusListener {
|
||||
const descriptionField =
|
||||
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
|
||||
|
||||
if (article.data[titleField] && titleLength > -1) {
|
||||
if (editor && article.data[titleField] && titleLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, titleField, titleLength);
|
||||
}
|
||||
|
||||
if (article.data[descriptionField] && descLength > -1) {
|
||||
if (editor && article.data[descriptionField] && descLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, descriptionField, descLength);
|
||||
}
|
||||
|
||||
// Check the required fields
|
||||
StatusListener.verifyRequiredFields(editor, article, collection);
|
||||
if (editor) {
|
||||
StatusListener.verifyRequiredFields(editor, article, collection);
|
||||
}
|
||||
}
|
||||
|
||||
const panel = ExplorerView.getInstance();
|
||||
|
||||
@@ -2,5 +2,7 @@ export const PreviewCommands = {
|
||||
toVSCode: {
|
||||
open: `preview.open`
|
||||
},
|
||||
fromVSCode: {}
|
||||
toWebview: {
|
||||
updateUrl: `preview.updateUrl`
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as React from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { PreviewCommands } from '../../../constants';
|
||||
import useThemeColors from '../../hooks/useThemeColors';
|
||||
import { EventData } from '@estruyf/vscode/dist/models';
|
||||
|
||||
export interface IPreviewProps {
|
||||
url: string | null;
|
||||
@@ -35,10 +36,24 @@ export const Preview: React.FunctionComponent<IPreviewProps> = ({
|
||||
iframeRef.current!.src = navUrl;
|
||||
};
|
||||
|
||||
const msgListener = (message: MessageEvent<EventData<any>>) => {
|
||||
if (message.data.command === PreviewCommands.toWebview.updateUrl) {
|
||||
setCrntUrl(message.data.payload);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setCrntUrl(url);
|
||||
}, [url]);
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.listen(msgListener);
|
||||
|
||||
return () => {
|
||||
Messenger.unlisten(msgListener);
|
||||
};
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="w-full h-full bg-white">
|
||||
<div
|
||||
@@ -77,7 +92,7 @@ export const Preview: React.FunctionComponent<IPreviewProps> = ({
|
||||
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
src={url || ''}
|
||||
src={crntUrl || url || ''}
|
||||
className={`w-full border-0`}
|
||||
style={{
|
||||
height: 'calc(100% - 30px)',
|
||||
|
||||
@@ -111,12 +111,11 @@ export class ArticleHelper {
|
||||
*/
|
||||
public static async updateByPath(path: string, article: ParsedFrontMatter) {
|
||||
const file = await workspace.openTextDocument(Uri.parse(path));
|
||||
const editor = await window.showTextDocument(file);
|
||||
|
||||
if (file && editor) {
|
||||
if (file) {
|
||||
const update = this.generateUpdate(file, article);
|
||||
|
||||
await editor.edit((builder) => builder.replace(update.range, update.newText));
|
||||
await workspace.fs.writeFile(file.uri, new TextEncoder().encode(update.newText));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,18 +569,18 @@ export class ArticleHelper {
|
||||
* Get the details of the current article
|
||||
* @returns
|
||||
*/
|
||||
public static getDetails() {
|
||||
public static async getDetails(filePath: string) {
|
||||
const baseUrl = Settings.get<string>(SETTING_SITE_BASEURL);
|
||||
const editor = window.activeTextEditor;
|
||||
if (!editor) {
|
||||
if (!filePath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ArticleHelper.isSupportedFile()) {
|
||||
const document = await workspace.openTextDocument(filePath);
|
||||
if (!ArticleHelper.isSupportedFile(document)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
const article = await ArticleHelper.getFrontMatterByPath(filePath);
|
||||
|
||||
if (article && article.content) {
|
||||
let content = article.content;
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Field } from '../models';
|
||||
import { existsSync } from 'fs';
|
||||
import { Folders } from '../commands/Folders';
|
||||
import { parseWinPath } from './parseWinPath';
|
||||
import { Preview } from '../commands';
|
||||
|
||||
export class ImageHelper {
|
||||
/**
|
||||
@@ -15,7 +16,7 @@ export class ImageHelper {
|
||||
* @returns
|
||||
*/
|
||||
public static allRelToAbs(field: Field, value: string | string[] | undefined) {
|
||||
const filePath = window.activeTextEditor?.document.uri.fsPath;
|
||||
const filePath = window.activeTextEditor?.document.uri.fsPath || Preview.filePath;
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES
|
||||
} from '../../constants';
|
||||
import { Article } from '../../commands';
|
||||
import { Article, Preview } from '../../commands';
|
||||
import { ParsedFrontMatter } from '../../parsers';
|
||||
import { processKnownPlaceholders } from '../../helpers/PlaceholderHelper';
|
||||
import { PostMessageData } from '../../models';
|
||||
@@ -84,16 +84,18 @@ export class DataListener extends BaseListener {
|
||||
* Triggers a metadata change in the panel
|
||||
* @param metadata
|
||||
*/
|
||||
public static pushMetadata(metadata: any) {
|
||||
public static async pushMetadata(metadata: any) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const filePath = window.activeTextEditor?.document.uri.fsPath;
|
||||
const filePath = window.activeTextEditor?.document.uri.fsPath || Preview.filePath;
|
||||
const commaSeparated = Settings.get<string[]>(SETTING_COMMA_SEPARATED_FIELDS);
|
||||
const contentTypes = Settings.get<string>(SETTING_TAXONOMY_CONTENT_TYPES);
|
||||
|
||||
let articleDetails = null;
|
||||
|
||||
try {
|
||||
articleDetails = ArticleHelper.getDetails();
|
||||
if (filePath) {
|
||||
articleDetails = await ArticleHelper.getDetails(filePath);
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(`DataListener::pushMetadata: ${(e as Error).message}`);
|
||||
}
|
||||
@@ -136,6 +138,10 @@ export class DataListener extends BaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
if (filePath && updatedMetadata[DefaultFields.Slug]) {
|
||||
Preview.updatePageUrl(filePath, updatedMetadata[DefaultFields.Slug]);
|
||||
}
|
||||
|
||||
this.sendMsg(Command.metadata, updatedMetadata);
|
||||
|
||||
DataListener.lastMetadataUpdate = updatedMetadata;
|
||||
@@ -148,11 +154,13 @@ export class DataListener extends BaseListener {
|
||||
field,
|
||||
parents,
|
||||
value,
|
||||
filePath,
|
||||
blockData
|
||||
}: {
|
||||
field: string;
|
||||
value: any;
|
||||
parents?: string[];
|
||||
filePath?: string;
|
||||
blockData?: BlockFieldData;
|
||||
fieldData?: { multiple: boolean; value: string[] };
|
||||
}) {
|
||||
@@ -161,11 +169,21 @@ export class DataListener extends BaseListener {
|
||||
}
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
|
||||
let article;
|
||||
if (filePath) {
|
||||
article = await ArticleHelper.getFrontMatterByPath(filePath);
|
||||
} else {
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
if (!article) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
if (!article) {
|
||||
return;
|
||||
}
|
||||
@@ -216,7 +234,12 @@ export class DataListener extends BaseListener {
|
||||
parentObj[field] = value;
|
||||
}
|
||||
|
||||
ArticleHelper.update(editor, article);
|
||||
if (editor) {
|
||||
ArticleHelper.update(editor, article);
|
||||
} else if (filePath) {
|
||||
await ArticleHelper.updateByPath(filePath, article);
|
||||
}
|
||||
|
||||
this.pushMetadata(article.data);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ const Metadata: React.FunctionComponent<IMetadataProps> = ({
|
||||
}: React.PropsWithChildren<IMetadataProps>) => {
|
||||
const contentType = useContentType(settings, metadata);
|
||||
|
||||
const sendUpdate = (field: string | undefined, value: any, parents: string[]) => {
|
||||
const sendUpdate = React.useCallback((field: string | undefined, value: any, parents: string[]) => {
|
||||
if (!field) {
|
||||
return;
|
||||
}
|
||||
@@ -39,9 +39,10 @@ const Metadata: React.FunctionComponent<IMetadataProps> = ({
|
||||
Messenger.send(CommandToCode.updateMetadata, {
|
||||
field,
|
||||
parents,
|
||||
value
|
||||
value,
|
||||
filePath: metadata.filePath
|
||||
});
|
||||
};
|
||||
}, [metadata.filePath]);
|
||||
|
||||
if (!settings) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user