From 937494f81c7ebfc9a16ca85a24b81fb8a6a17d27 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Sun, 17 Jul 2022 08:13:42 +0200 Subject: [PATCH 01/58] Hide open settings + new docs and settings link --- src/constants/Links.ts | 2 ++ src/panelWebView/components/OtherActions.tsx | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/constants/Links.ts b/src/constants/Links.ts index f6323a21..48e04847 100644 --- a/src/constants/Links.ts +++ b/src/constants/Links.ts @@ -2,5 +2,7 @@ export const GITHUB_LINK = "https://github.com/estruyf/vscode-front-matter"; export const ISSUE_LINK = "https://github.com/estruyf/vscode-front-matter/issues"; export const SPONSOR_LINK = "https://github.com/sponsors/estruyf"; export const REVIEW_LINK = "https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter&ssr=false#review-details"; +export const DOCUMENTATION_LINK = "https://frontmatter.codes/docs"; +export const DOCUMENTATION_SETTINGS_LINK = "https://frontmatter.codes/docs/settings"; export const SENTRY_LINK = "https://1ac45704bbe74264a7b4674bdc2abf48@o1022172.ingest.sentry.io/5988293"; \ No newline at end of file diff --git a/src/panelWebView/components/OtherActions.tsx b/src/panelWebView/components/OtherActions.tsx index a93c8485..9d2e10f5 100644 --- a/src/panelWebView/components/OtherActions.tsx +++ b/src/panelWebView/components/OtherActions.tsx @@ -10,8 +10,9 @@ import { SettingsIcon } from './Icons/SettingsIcon'; import { TemplateIcon } from './Icons/TemplateIcon'; import { WritingIcon } from './Icons/WritingIcon'; import { OtherActionButton } from './OtherActionButton'; -import { ISSUE_LINK } from '../../constants/Links'; +import { DOCUMENTATION_LINK, DOCUMENTATION_SETTINGS_LINK, ISSUE_LINK } from '../../constants/Links'; import { Messenger } from '@estruyf/vscode/dist/client'; +import { BookOpenIcon } from '@heroicons/react/outline'; export interface IOtherActionsProps { isFile: boolean; @@ -50,14 +51,22 @@ const OtherActions: React.FunctionComponent = ({isFile, sett Toggle center mode - Create as template + Create template - Open settings + {/* Open settings */} Reveal file in folder Reveal project folder +
+ Documentation +
+ +
+ Settings overview +
+
Report an issue
From 8c0ce05133e9c41d8aabd6da6792f6e9a2331ed5 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Sun, 17 Jul 2022 08:13:51 +0200 Subject: [PATCH 02/58] Hide settings icon --- src/panelWebView/components/OtherActions.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/panelWebView/components/OtherActions.tsx b/src/panelWebView/components/OtherActions.tsx index 9d2e10f5..f241f6e8 100644 --- a/src/panelWebView/components/OtherActions.tsx +++ b/src/panelWebView/components/OtherActions.tsx @@ -6,7 +6,6 @@ import { BugIcon } from './Icons/BugIcon'; import { CenterIcon } from './Icons/CenterIcon'; import { FileIcon } from './Icons/FileIcon'; import { FolderOpenedIcon } from './Icons/FolderOpenedIcon'; -import { SettingsIcon } from './Icons/SettingsIcon'; import { TemplateIcon } from './Icons/TemplateIcon'; import { WritingIcon } from './Icons/WritingIcon'; import { OtherActionButton } from './OtherActionButton'; From dab6a46d983e03da6bf901f19c11aa01bb51b369 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 18 Jul 2022 17:30:19 +0300 Subject: [PATCH 03/58] #372 - Update taxonomy to taxonomies --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- src/dashboardWebView/components/Header/Tabs.tsx | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c288dc..a5c048bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [8.1.0] - 2022-xx-xx + +### 🎨 Enhancements + +- [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies + +### ⚡️ Optimizations + +### 🐞 Fixes + ## [8.0.1] - 2022-07-13 ### 🐞 Fixes diff --git a/package.json b/package.json index b71f0c93..923e1516 100644 --- a/package.json +++ b/package.json @@ -1533,7 +1533,7 @@ }, { "command": "frontMatter.dashboard.taxonomy", - "title": "Open taxonomy dashboard", + "title": "Open taxonomies dashboard", "category": "Front matter", "icon": { "dark": "/assets/icons/frontmatter-small-dark.svg", diff --git a/src/dashboardWebView/components/Header/Tabs.tsx b/src/dashboardWebView/components/Header/Tabs.tsx index 4b2af0c9..ca60730b 100644 --- a/src/dashboardWebView/components/Header/Tabs.tsx +++ b/src/dashboardWebView/components/Header/Tabs.tsx @@ -54,7 +54,7 @@ export const Tabs: React.FunctionComponent = ({ onNavigate }: React. - Taxonomy + Taxonomies From 1aa8f77590e1d417bd33c8b3797def0c594cf506 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 20 Jul 2022 15:00:17 +0300 Subject: [PATCH 04/58] #370 - updated JSON schema --- CHANGELOG.md | 1 + package.json | 32 +++++++++++++++++++++++++++++--- src/helpers/TaxonomyHelper.ts | 2 +- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5c048bf..d70f839b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### 🎨 Enhancements +- [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy - [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies ### ⚡️ Optimizations diff --git a/package.json b/package.json index 923e1516..520d14b6 100644 --- a/package.json +++ b/package.json @@ -893,7 +893,20 @@ "taxonomyId": { "type": "string", "default": "", - "description": "The ID of your taxonomy field" + "description": "The ID of your taxonomy field. It cannot contain the \"tags\" or \"categories\" value.", + "not": { + "anyOf": [ + { + "const": "" + }, + { + "const": "tags" + }, + { + "const": "categories" + } + ] + } }, "fileExtensions": { "type": "array", @@ -1151,11 +1164,24 @@ "properties": { "id": { "type": "string", - "description": "ID for your taxonomy field" + "description": "ID for your taxonomy field. It cannot contain the \"tags\" or \"categories\" value.", + "not": { + "anyOf": [ + { + "const": "" + }, + { + "const": "tags" + }, + { + "const": "categories" + } + ] + } }, "options": { "type": "array", - "description": "Options from which you can pick", + "description": "Options from which you can pick.", "items": { "type": "string" } diff --git a/src/helpers/TaxonomyHelper.ts b/src/helpers/TaxonomyHelper.ts index 4f55db81..b69c0715 100644 --- a/src/helpers/TaxonomyHelper.ts +++ b/src/helpers/TaxonomyHelper.ts @@ -116,7 +116,7 @@ export class TaxonomyHelper { const options = this.getTaxonomyOptions(taxonomyType); const newOption = await window.showInputBox({ - title: `Create a new ${taxonomyType} value`, + title: `Create a new ${type} value`, placeHolder: `The value you want to add`, ignoreFocusOut: true, validateInput: (text) => { From 9445ce6d370a86eb7dd2f2a9bf598691f615e338 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 21 Jul 2022 13:15:49 +0300 Subject: [PATCH 05/58] #374 - Auto-fold the front matter section --- CHANGELOG.md | 1 + package.json | 25 +++++-- src/constants/settings.ts | 3 + src/extension.ts | 2 +- src/helpers/Extension.ts | 4 ++ src/providers/MarkdownFoldingProvider.ts | 89 +++++++++++++++++++++++- 6 files changed, 113 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d70f839b..096f6f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy - [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies +- [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead ### ⚡️ Optimizations diff --git a/package.json b/package.json index 520d14b6..1964bbf2 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,17 @@ "markdownDescription": "Specify if you want to highlight the Front Matter in the Markdown file. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.content.fmhighlight)", "scope": "Content" }, + "frontMatter.content.hideFm": { + "type": "boolean", + "markdownDescription": "Specify if you want to hide the Front Matter in the Markdown file. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.content.hidefrontmatter)", + "scope": "Content" + }, + "frontMatter.content.hideFmMessage": { + "type": "string", + "default": "Use the editor panel to make front matter changes", + "markdownDescription": "Specify the message to display when the Front Matter is hidden. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.content.hidefrontmatter.message)", + "scope": "Content" + }, "frontMatter.content.pageFolders": { "type": "array", "default": [], @@ -1323,6 +1334,12 @@ "default": false, "markdownDescription": "Specify if you want to disable the telemetry. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.telemetry.disable)" }, + "frontMatter.templates.enabled": { + "type": "boolean", + "default": false, + "markdownDescription": "Specify if you want to use templates. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.templates.enabled)", + "scope": "Templates" + }, "frontMatter.templates.folder": { "type": "string", "default": ".frontmatter/templates", @@ -1334,12 +1351,6 @@ "default": "yyyy-MM-dd", "markdownDescription": "Specify the prefix you want to add for your new article filenames. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.templates.prefix)", "scope": "Templates" - }, - "frontMatter.templates.enabled": { - "type": "boolean", - "default": false, - "markdownDescription": "Specify if you want to use templates. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.templates.enabled)", - "scope": "Templates" } } }, @@ -2049,4 +2060,4 @@ "dependencies": { "node-fetch": "^2.6.7" } -} +} \ No newline at end of file diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 82951cef..5e79dc4d 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -59,6 +59,9 @@ export const SETTING_MEDIA_SORTING_DEFAULT = "content.defaultSorting"; export const SETTING_CONTENT_DEFAULT_FILETYPE = "content.defaultFileType"; export const SETTING_CONTENT_SUPPORTED_FILETYPES = "content.supportedFileTypes"; +export const SETTING_CONTENT_HIDE_FRONTMATTER = "content.hideFm"; +export const SETTING_CONTENT_HIDE_FRONTMATTER_MESSAGE = "content.hideFmMessage"; + export const SETTING_MEDIA_SUPPORTED_MIMETYPES = "media.supportedMimeTypes"; export const SETTING_DASHBOARD_OPENONSTART = "dashboard.openOnStart"; diff --git a/src/extension.ts b/src/extension.ts index 4a8d585e..8a0a634d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -205,7 +205,7 @@ export async function activate(context: vscode.ExtensionContext) { SettingsListener.getSettings(); DataListener.getFoldersAndFiles(); - MarkdownFoldingProvider.triggerHighlighting(); + MarkdownFoldingProvider.triggerHighlighting(true); ModeSwitch.register(); }); diff --git a/src/helpers/Extension.ts b/src/helpers/Extension.ts index 7473734c..31847e65 100644 --- a/src/helpers/Extension.ts +++ b/src/helpers/Extension.ts @@ -260,6 +260,10 @@ export class Extension { return true; } + public asAbsolutePath(path: string) { + return this.ctx.asAbsolutePath(path); + } + public get packageJson() { const frontMatter = extensions.getExtension(this.isBetaVersion() ? EXTENSION_BETA_ID : EXTENSION_ID)!; return frontMatter.packageJSON; diff --git a/src/providers/MarkdownFoldingProvider.ts b/src/providers/MarkdownFoldingProvider.ts index 755c6f55..1bfc6851 100644 --- a/src/providers/MarkdownFoldingProvider.ts +++ b/src/providers/MarkdownFoldingProvider.ts @@ -1,5 +1,7 @@ +import { SETTING_CONTENT_HIDE_FRONTMATTER, SETTING_CONTENT_HIDE_FRONTMATTER_MESSAGE } from './../constants/settings'; +import { ThemeColor } from 'vscode'; import { ArticleHelper } from '../helpers'; -import { languages, TextEditorDecorationType } from 'vscode'; +import { commands, DecorationOptions, languages, TextEditorDecorationType } from 'vscode'; import { CancellationToken, FoldingContext, FoldingRange, FoldingRangeKind, FoldingRangeProvider, Range, TextDocument, window, Position } from 'vscode'; import { SETTING_CONTENT_FRONTMATTER_HIGHLIGHT, SETTING_CONTENT_SUPPORTED_FILETYPES, SETTING_FRONTMATTER_TYPE } from '../constants'; import { Settings } from '../helpers'; @@ -11,6 +13,7 @@ export class MarkdownFoldingProvider implements FoldingRangeProvider { private static end: number | null = null; private static endLine: number | null = null; private static decType: TextEditorDecorationType | null = null; + private static crntDecoration: TextEditorDecorationType | null = null; public static register() { const supportedFiles = Settings.get(SETTING_CONTENT_SUPPORTED_FILETYPES); @@ -37,15 +40,19 @@ export class MarkdownFoldingProvider implements FoldingRangeProvider { return ranges; } - public static triggerHighlighting() { + public static triggerHighlighting(configChange: boolean = false) { const activeDoc = window.activeTextEditor?.document; + if (configChange && this.crntDecoration) { + this.resetDecoration(); + } + const isSupported = ArticleHelper.isSupportedFile(activeDoc); if (isSupported) { const fmHighlight = Settings.get(SETTING_CONTENT_FRONTMATTER_HIGHLIGHT); const range = MarkdownFoldingProvider.getFrontMatterRange(); - + if (range) { if (MarkdownFoldingProvider.decType !== null) { MarkdownFoldingProvider.decType.dispose(); @@ -56,6 +63,11 @@ export class MarkdownFoldingProvider implements FoldingRangeProvider { window.activeTextEditor?.setDecorations(MarkdownFoldingProvider.decType, [range]); } } + + const hideFrontMatter = Settings.get(SETTING_CONTENT_HIDE_FRONTMATTER); + if (hideFrontMatter) { + this.hideFrontMatterFromDocument(range); + } } } @@ -119,4 +131,75 @@ export class MarkdownFoldingProvider implements FoldingRangeProvider { return null; } + + /** + * Hide the front matter on the page + * @param range + * @returns + */ + private static hideFrontMatterFromDocument = async (range: Range| null) => { + + const editor = window.activeTextEditor; + if (!editor) { + return; + } + + const decorators: DecorationOptions[] = []; + + if (range) { + decorators.push({ + range: range + }); + } + + if (!this.crntDecoration) { + this.crntDecoration = this.getHiddenDecoration(); + } + + editor.setDecorations( + this.crntDecoration, + decorators + ); + + commands.executeCommand('editor.fold', {selectionLines: [range?.start.line],direction: "up"}); + } + + /** + * Resets the decoration in the document + * @returns + */ + private static resetDecoration() { + if (!this.crntDecoration) { + return; + } + + const editor = window.activeTextEditor; + if (!editor) { + return; + } + + editor.setDecorations( + this.crntDecoration, + [] + ); + + this.crntDecoration = null; + } + + /** + * Retrieve the hidden decoration for the text to hide + * @returns + */ + private static getHiddenDecoration(): TextEditorDecorationType { + const contentText = Settings.get(SETTING_CONTENT_HIDE_FRONTMATTER_MESSAGE); + + return window.createTextEditorDecorationType({ + after: { + contentText, + fontStyle: 'italic', + color: new ThemeColor('editorInfo.foreground'), + }, + textDecoration: "none; display: none;" + }); + } } \ No newline at end of file From 7badfda41b95efbb34b8b790d7fa2e5c04da59fa Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 21 Jul 2022 18:38:53 +0300 Subject: [PATCH 06/58] #352 - Custom placeholders now support scripting --- CHANGELOG.md | 1 + src/commands/Article.ts | 6 ++-- src/commands/Template.ts | 2 +- src/helpers/ArticleHelper.ts | 43 +++++++++++++++++++++++++---- src/helpers/ContentType.ts | 10 +++---- src/helpers/CustomScript.ts | 7 ++++- src/listeners/panel/DataListener.ts | 11 ++++++-- src/models/CustomPlaceholder.ts | 6 ++++ src/models/PanelSettings.ts | 2 +- src/models/index.ts | 1 + 10 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 src/models/CustomPlaceholder.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 096f6f20..ac8e1503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### 🎨 Enhancements +- [#352](https://github.com/estruyf/vscode-front-matter/issues/352): Custom placeholders now support scripting - [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy - [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies - [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead diff --git a/src/commands/Article.ts b/src/commands/Article.ts index 00b42508..724a8845 100644 --- a/src/commands/Article.ts +++ b/src/commands/Article.ts @@ -2,7 +2,7 @@ import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType'; import { isValidFile } from './../helpers/isValidFile'; import { SETTING_AUTO_UPDATE_DATE, SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX, CONFIG_KEY, SETTING_DATE_FORMAT, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_CONTENT_PLACEHOLDERS, TelemetryEvent } from './../constants'; import * as vscode from 'vscode'; -import { Field, TaxonomyType } from "../models"; +import { CustomPlaceholder, Field, TaxonomyType } from "../models"; import { format } from "date-fns"; import { ArticleHelper, Settings, SlugHelper } from '../helpers'; import { Notifications } from '../helpers/Notifications'; @@ -225,8 +225,8 @@ export class Article { } // Update the fields containing a custom placeholder that depends on slug - const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS); - const customPlaceholders = placeholders?.filter(p => p.value.includes("{{slug}}")); + const placeholders = Settings.get(SETTING_CONTENT_PLACEHOLDERS); + const customPlaceholders = placeholders?.filter(p => p.value && p.value.includes("{{slug}}")); const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; for (const customPlaceholder of (customPlaceholders || [])) { const customPlaceholderFields = contentType.fields.filter(f => f.default === `{{${customPlaceholder.id}}}`); diff --git a/src/commands/Template.ts b/src/commands/Template.ts index 8c138964..e7428849 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -175,7 +175,7 @@ export class Template { } if (frontMatter.data) { - frontMatter.data = ArticleHelper.updatePlaceholders(frontMatter.data, titleValue); + frontMatter.data = await ArticleHelper.updatePlaceholders(frontMatter.data, titleValue, newFilePath); frontMatter = Article.updateDate(frontMatter); diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index fc7be101..0100a50f 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -1,3 +1,4 @@ +import { CustomPlaceholder } from './../models/CustomPlaceholder'; import { Uri, workspace } from 'vscode'; import { MarkdownFoldingProvider } from './../providers/MarkdownFoldingProvider'; import { DEFAULT_CONTENT_TYPE, DEFAULT_CONTENT_TYPE_NAME } from './../constants/ContentType'; @@ -22,6 +23,8 @@ import { fromMarkdown } from 'mdast-util-from-markdown'; import { Link, Parent } from 'mdast-util-from-markdown/lib'; import { Content } from 'mdast'; import { processKnownPlaceholders } from './PlaceholderHelper'; +import { CustomScript } from './CustomScript'; +import { Folders } from '../commands/Folders'; export class ArticleHelper { private static notifiedFiles: string[] = []; @@ -368,7 +371,7 @@ export class ArticleHelper { * @param title * @returns */ - public static updatePlaceholders(data: any, title: string) { + public static async updatePlaceholders(data: any, title: string, filePath: string) { const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; const fmData = Object.assign({}, data); @@ -384,7 +387,7 @@ export class ArticleHelper { } fmData[fieldName] = processKnownPlaceholders(fmData[fieldName], title, dateFormat); - fmData[fieldName] = this.processCustomPlaceholders(fmData[fieldName], title); + fmData[fieldName] = await this.processCustomPlaceholders(fmData[fieldName], title, filePath); } return fmData; @@ -396,16 +399,44 @@ export class ArticleHelper { * @param title * @returns */ - public static processCustomPlaceholders(value: string, title: string) { + public static async processCustomPlaceholders(value: string, title: string, filePath: string) { if (value && typeof value === "string") { const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; - const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS); + const placeholders = Settings.get(SETTING_CONTENT_PLACEHOLDERS); if (placeholders && placeholders.length > 0) { for (const placeholder of placeholders) { if (value.includes(`{{${placeholder.id}}}`)) { + + let placeHolderValue = placeholder.value || ""; + if (placeholder.script) { + const wsFolder = Folders.getWorkspaceFolder(); + const script = { title: placeholder.id, script: placeholder.script, command: placeholder.command }; + let output: string | any = await CustomScript.executeScript(script, wsFolder?.fsPath || "", `'${filePath}' '${title}'`); + + if (output) { + // Check if the output needs to be parsed + if (output.includes("{") && output.includes("}")) { + try { + output = JSON.parse(output); + } catch (e) { + // Do nothing + } + } else { + output = output.split("\n"); + } + + placeHolderValue = output; + } + } + const regex = new RegExp(`{{${placeholder.id}}}`, "g"); - const updatedValue = processKnownPlaceholders(placeholder.value, title, dateFormat); - value = value.replace(regex, updatedValue); + const updatedValue = processKnownPlaceholders(placeHolderValue, title, dateFormat); + + if (value === `{{${placeholder.id}}}`) { + value = updatedValue; + } else { + value = value.replace(regex, updatedValue); + } } } } diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 84a5ed7a..263a4e7a 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -526,7 +526,7 @@ export class ContentType { } } - let data: any = this.processFields(contentType, titleValue, templateData?.data || {}); + let data: any = await this.processFields(contentType, titleValue, templateData?.data || {}, newFilePath); data = ArticleHelper.updateDates(Object.assign({}, data)); @@ -553,7 +553,7 @@ export class ContentType { * @param contentType * @param data */ - private static processFields(obj: IContentType | Field, titleValue: string, data: any) { + private static async processFields(obj: IContentType | Field, titleValue: string, data: any, filePath: string) { if (obj.fields) { const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; @@ -561,19 +561,19 @@ export class ContentType { if (field.name === "title") { if (field.default) { data[field.name] = processKnownPlaceholders(field.default, titleValue, dateFormat); - data[field.name] = ArticleHelper.processCustomPlaceholders(data[field.name], titleValue); + data[field.name] = await ArticleHelper.processCustomPlaceholders(data[field.name], titleValue, filePath); } else { data[field.name] = titleValue; } } else { if (field.type === "fields") { - data[field.name] = this.processFields(field, titleValue, {}); + data[field.name] = await this.processFields(field, titleValue, {}, filePath); } else { const defaultValue = field.default; if (typeof defaultValue === "string") { data[field.name] = processKnownPlaceholders(defaultValue, titleValue, dateFormat); - data[field.name] = ArticleHelper.processCustomPlaceholders(data[field.name], titleValue); + data[field.name] = await ArticleHelper.processCustomPlaceholders(data[field.name], titleValue, filePath); } else { data[field.name] = typeof defaultValue !== "undefined" ? defaultValue : ""; } diff --git a/src/helpers/CustomScript.ts b/src/helpers/CustomScript.ts index ae0989fa..ee4df28f 100644 --- a/src/helpers/CustomScript.ts +++ b/src/helpers/CustomScript.ts @@ -246,7 +246,7 @@ export class CustomScript { * @param args * @returns */ - private static async executeScript(script: ICustomScript, wsPath: string, args: string): Promise { + public static async executeScript(script: ICustomScript, wsPath: string, args: string): Promise { return new Promise((resolve, reject) => { // Check the command to use @@ -264,6 +264,11 @@ export class CustomScript { reject(error.message); } + if (stdout && stdout.endsWith(`\n`)) { + // Remove empty line at the end of the string + stdout = stdout.slice(0, -1); + } + resolve(stdout); }); }); diff --git a/src/listeners/panel/DataListener.ts b/src/listeners/panel/DataListener.ts index aa056ed9..aa2ab62e 100644 --- a/src/listeners/panel/DataListener.ts +++ b/src/listeners/panel/DataListener.ts @@ -322,11 +322,18 @@ export class DataListener extends BaseListener { } } - private static updatePlaceholder(field: string, value: string, title: string) { + /** + * Update the placeholder + * @param field + * @param value + * @param title + */ + private static async updatePlaceholder(field: string, value: string, title: string) { if (field && value) { + const crntFile = window.activeTextEditor?.document; const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; value = processKnownPlaceholders(value, title || "", dateFormat); - value = ArticleHelper.processCustomPlaceholders(value, title || ""); + value = await ArticleHelper.processCustomPlaceholders(value, title || "", crntFile?.uri.fsPath || ""); } this.sendMsg(Command.updatePlaceholder, { field, value }); diff --git a/src/models/CustomPlaceholder.ts b/src/models/CustomPlaceholder.ts new file mode 100644 index 00000000..b95d783b --- /dev/null +++ b/src/models/CustomPlaceholder.ts @@ -0,0 +1,6 @@ +export interface CustomPlaceholder { + id: string; + value?: string; + script?: string; + command?: string +} \ No newline at end of file diff --git a/src/models/PanelSettings.ts b/src/models/PanelSettings.ts index 51439951..7366d567 100644 --- a/src/models/PanelSettings.ts +++ b/src/models/PanelSettings.ts @@ -118,7 +118,7 @@ export interface CustomScript { output?: "notification" | "editor"; outputType?: string; type?: ScriptType; - command?: CommandType; + command?: CommandType | string; } export interface PreviewSettings { diff --git a/src/models/index.ts b/src/models/index.ts index 65b60c25..51c13234 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,6 +1,7 @@ export * from './BlockFieldData'; export * from './Choice'; export * from './ContentFolder'; +export * from './CustomPlaceholder'; export * from './CustomTaxonomyData'; export * from './DashboardData'; export * from './DataFile'; From c0e6c79c6718c08c9d8d854e3df17ae7889f518c Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 22 Jul 2022 16:03:45 +0300 Subject: [PATCH 07/58] qna link --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 1964bbf2..3a093083 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "sponsor": { "url": "https://github.com/sponsors/estruyf" }, + "qna": "https://github.com/estruyf/vscode-front-matter/discussions", "engines": { "vscode": "^1.63.0" }, From 89aab6c74e4e807cf5a66bc7b05d5b4739348764 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 27 Jul 2022 11:56:51 +0200 Subject: [PATCH 08/58] #352 - Added notification + progress notification --- src/helpers/ArticleHelper.ts | 52 ++++++++++++++----------- src/helpers/ContentType.ts | 74 +++++++++++++++++++----------------- 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 0100a50f..aa054757 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -407,36 +407,42 @@ export class ArticleHelper { for (const placeholder of placeholders) { if (value.includes(`{{${placeholder.id}}}`)) { - let placeHolderValue = placeholder.value || ""; - if (placeholder.script) { - const wsFolder = Folders.getWorkspaceFolder(); - const script = { title: placeholder.id, script: placeholder.script, command: placeholder.command }; - let output: string | any = await CustomScript.executeScript(script, wsFolder?.fsPath || "", `'${filePath}' '${title}'`); + try { + let placeHolderValue = placeholder.value || ""; + if (placeholder.script) { + const wsFolder = Folders.getWorkspaceFolder(); + const script = { title: placeholder.id, script: placeholder.script, command: placeholder.command }; + let output: string | any = await CustomScript.executeScript(script, wsFolder?.fsPath || "", `'${wsFolder?.fsPath}' '${filePath}' '${title}'`); - if (output) { - // Check if the output needs to be parsed - if (output.includes("{") && output.includes("}")) { - try { - output = JSON.parse(output); - } catch (e) { - // Do nothing + if (output) { + // Check if the output needs to be parsed + if (output.includes("{") && output.includes("}")) { + try { + output = JSON.parse(output); + } catch (e) { + // Do nothing + } + } else { + output = output.split("\n"); } - } else { - output = output.split("\n"); + + placeHolderValue = output; } - - placeHolderValue = output; } - } - const regex = new RegExp(`{{${placeholder.id}}}`, "g"); - const updatedValue = processKnownPlaceholders(placeHolderValue, title, dateFormat); + const regex = new RegExp(`{{${placeholder.id}}}`, "g"); + const updatedValue = processKnownPlaceholders(placeHolderValue, title, dateFormat); - if (value === `{{${placeholder.id}}}`) { - value = updatedValue; - } else { - value = value.replace(regex, updatedValue); + if (value === `{{${placeholder.id}}}`) { + value = updatedValue; + } else { + value = value.replace(regex, updatedValue); + } + } catch (e) { + Notifications.error(`Error while processing the ${placeholder.id} placeholder`); + Logger.error((e as Error).message); } + } } } diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 263a4e7a..5b1845db 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -3,7 +3,7 @@ import { PagesListener } from './../listeners/dashboard'; import { ArticleHelper, Settings } from "."; import { FEATURE_FLAG, SETTING_CONTENT_DRAFT_FIELD, SETTING_DATE_FORMAT, SETTING_FRAMEWORK_ID, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TAXONOMY_FIELD_GROUPS, TelemetryEvent } from "../constants"; import { ContentType as IContentType, DraftField, Field, FieldGroup, FieldType } from '../models'; -import { Uri, commands, window } from 'vscode'; +import { Uri, commands, window, ProgressLocation } from 'vscode'; import { Folders } from "../commands/Folders"; import { Questions } from "./Questions"; import { existsSync, writeFileSync } from "fs"; @@ -499,53 +499,59 @@ export class ContentType { * @returns */ private static async create(contentType: IContentType, folderPath: string) { - const titleValue = await Questions.ContentTitle(); - if (!titleValue) { - return; - } + window.withProgress({ + location: ProgressLocation.Notification, + title: "Front Matter: Creating content...", + cancellable: false + }, async () => { + const titleValue = await Questions.ContentTitle(); + if (!titleValue) { + return; + } - let templatePath = contentType.template; - let templateData: ParsedFrontMatter | null = null; - if (templatePath) { - templatePath = Folders.getAbsFilePath(templatePath); - templateData = ArticleHelper.getFrontMatterByPath(templatePath); - } + let templatePath = contentType.template; + let templateData: ParsedFrontMatter | null = null; + if (templatePath) { + templatePath = Folders.getAbsFilePath(templatePath); + templateData = ArticleHelper.getFrontMatterByPath(templatePath); + } - let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue); - if (!newFilePath) { - return; - } + let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue); + if (!newFilePath) { + return; + } - if (contentType.name === "default") { - const crntFramework = Settings.get(SETTING_FRAMEWORK_ID); - if (crntFramework?.toLowerCase() === "jekyll") { - const idx = contentType.fields.findIndex(f => f.name === "draft"); - if (idx > -1) { - contentType.fields.splice(idx, 1); + if (contentType.name === "default") { + const crntFramework = Settings.get(SETTING_FRAMEWORK_ID); + if (crntFramework?.toLowerCase() === "jekyll") { + const idx = contentType.fields.findIndex(f => f.name === "draft"); + if (idx > -1) { + contentType.fields.splice(idx, 1); + } } } - } - let data: any = await this.processFields(contentType, titleValue, templateData?.data || {}, newFilePath); + let data: any = await this.processFields(contentType, titleValue, templateData?.data || {}, newFilePath); - data = ArticleHelper.updateDates(Object.assign({}, data)); + data = ArticleHelper.updateDates(Object.assign({}, data)); - if (contentType.name !== DEFAULT_CONTENT_TYPE_NAME) { - data['type'] = contentType.name; - } + if (contentType.name !== DEFAULT_CONTENT_TYPE_NAME) { + data['type'] = contentType.name; + } - const content = ArticleHelper.stringifyFrontMatter(templateData?.content || ``, data); + const content = ArticleHelper.stringifyFrontMatter(templateData?.content || ``, data); - writeFileSync(newFilePath, content, { encoding: "utf8" }); + writeFileSync(newFilePath, content, { encoding: "utf8" }); - await commands.executeCommand('vscode.open', Uri.file(newFilePath)); + await commands.executeCommand('vscode.open', Uri.file(newFilePath)); - Notifications.info(`Your new content has been created.`); + Notifications.info(`Your new content has been created.`); - Telemetry.send(TelemetryEvent.createContentFromContentType); + Telemetry.send(TelemetryEvent.createContentFromContentType); - // Trigger a refresh for the dashboard - PagesListener.refresh(); + // Trigger a refresh for the dashboard + PagesListener.refresh(); + }) } /** From 9a9ec33f9fb94cbfd776fd846e6d9b92d1ac2fcf Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 27 Jul 2022 12:08:39 +0200 Subject: [PATCH 09/58] Sorting fix --- .../components/TaxonomyView/TaxonomyManager.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx b/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx index ac383064..d58665a6 100644 --- a/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx +++ b/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx @@ -38,6 +38,9 @@ export const TaxonomyManager: React.FunctionComponent = ( // Alphabetically sort the items crntItems = Object.assign([], crntItems).sort((a: string, b: string) => { + a = a || ""; + b = b || ""; + if (a.toLowerCase() < b.toLowerCase()) { return -1; } From 07ed95793c730b0e9586f26a6e5bbb279a00a2b8 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 28 Jul 2022 11:36:26 +0200 Subject: [PATCH 10/58] #378 - Last modified update only to content in content folders --- CHANGELOG.md | 2 ++ package.json | 2 +- src/commands/Article.ts | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac8e1503..0615fd2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ ### 🐞 Fixes +- [#378](https://github.com/estruyf/vscode-front-matter/issues/378): Fix last modified update only to content in content folders + ## [8.0.1] - 2022-07-13 ### 🐞 Fixes diff --git a/package.json b/package.json index 3a093083..7b79caa3 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "frontMatter.content.autoUpdateDate": { "type": "boolean", "default": false, - "markdownDescription": "Specify if you want to automatically update the modified date of your article/page. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.content.autoupdatedate)", + "markdownDescription": "Specify if you want to automatically update the modified date of your article/page (only content located in your content folder). [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.content.autoupdatedate)", "scope": "Content" }, "frontMatter.content.defaultFileType": { diff --git a/src/commands/Article.ts b/src/commands/Article.ts index 724a8845..97ff9240 100644 --- a/src/commands/Article.ts +++ b/src/commands/Article.ts @@ -1,3 +1,4 @@ +import { Folders } from './Folders'; import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType'; import { isValidFile } from './../helpers/isValidFile'; import { SETTING_AUTO_UPDATE_DATE, SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX, CONFIG_KEY, SETTING_DATE_FORMAT, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_CONTENT_PLACEHOLDERS, TelemetryEvent } from './../constants'; @@ -323,6 +324,14 @@ export class Article { if (document && ArticleHelper.isSupportedFile(document)) { const autoUpdate = Settings.get(SETTING_AUTO_UPDATE_DATE); + // Is article located in one of the content folders + const folders = Folders.get(); + const documentPath = parseWinPath(document.fileName); + const folder = folders.find(f => documentPath.startsWith(f.path)); + if (!folder) { + return; + } + if (autoUpdate) { event.waitUntil(Article.setLastModifiedDateOnSave(document)); } From 30dc33a8592b1dc49ab89abee7867d0b528ad07e Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 29 Jul 2022 16:13:46 +0200 Subject: [PATCH 11/58] #377: Git sync actions added on panel and content dashboard --- CHANGELOG.md | 6 + assets/media/styles.css | 3 +- package-lock.json | 57 +++++++++ package.json | 13 ++- src/commands/Dashboard.ts | 3 +- src/constants/GeneralCommands.ts | 3 + src/constants/settings.ts | 3 + .../components/Header/Header.tsx | 3 + .../components/Header/SyncButton.tsx | 55 +++++++++ src/dashboardWebView/hooks/useMessages.tsx | 10 +- src/dashboardWebView/models/Settings.ts | 3 +- src/explorerView/ExplorerView.ts | 3 +- src/extension.ts | 12 +- src/helpers/DashboardSettings.ts | 8 +- src/helpers/DebounceCallback.ts | 9 ++ src/helpers/PanelSettings.ts | 9 +- src/helpers/SettingsHelper.ts | 58 ++++++---- src/helpers/index.ts | 1 + src/listeners/general/GitListener.ts | 109 ++++++++++++++++++ src/listeners/general/index.ts | 1 + src/models/GitSettings.ts | 5 + src/models/PanelSettings.ts | 3 +- src/models/index.ts | 1 + src/panelWebView/ViewPanel.tsx | 3 + src/panelWebView/components/ActionButton.tsx | 6 +- src/panelWebView/components/BaseView.tsx | 3 + src/panelWebView/components/Git/GitAction.tsx | 55 +++++++++ src/panelWebView/hooks/useMessages.tsx | 10 +- src/panelWebView/styles.css | 27 +++++ tailwind.config.js | 10 ++ 30 files changed, 443 insertions(+), 49 deletions(-) create mode 100644 src/dashboardWebView/components/Header/SyncButton.tsx create mode 100644 src/helpers/DebounceCallback.ts create mode 100644 src/listeners/general/GitListener.ts create mode 100644 src/models/GitSettings.ts create mode 100644 src/panelWebView/components/Git/GitAction.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 0615fd2e..1580caca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [8.1.0] - 2022-xx-xx +### ✨ New features + +- [#377](https://github.com/estruyf/vscode-front-matter/issues/377): Git sync actions added on panel and content dashboard (pull and push your changes to remote) + ### 🎨 Enhancements - [#352](https://github.com/estruyf/vscode-front-matter/issues/352): Custom placeholders now support scripting @@ -11,6 +15,8 @@ ### ⚡️ Optimizations +- Internal post message optimizations to the webviews + ### 🐞 Fixes - [#378](https://github.com/estruyf/vscode-front-matter/issues/378): Fix last modified update only to content in content folders diff --git a/assets/media/styles.css b/assets/media/styles.css index f13676f6..0f0492bf 100644 --- a/assets/media/styles.css +++ b/assets/media/styles.css @@ -41,7 +41,8 @@ } .collapsible__body, -.ext_settings { +.ext_settings, +.git_actions { padding: 1rem 1.25rem; box-sizing: border-box; } diff --git a/package-lock.json b/package-lock.json index f716d25e..012e7989 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,6 +81,7 @@ "recoil": "^0.4.1", "rimraf": "^3.0.2", "semver": "^7.3.7", + "simple-git": "^3.10.0", "style-loader": "2.0.0", "tailwindcss": "^2.2.7", "tailwindcss-nested-groups": "^1.2.4", @@ -217,6 +218,21 @@ "integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==", "dev": true }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true + }, "node_modules/@microsoft/fast-element": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.7.0.tgz", @@ -8800,6 +8816,21 @@ "simple-concat": "^1.0.0" } }, + "node_modules/simple-git": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.10.0.tgz", + "integrity": "sha512-2w35xrS5rVtAW0g67LqtxCZN5cdddz/woQRfS0OJXaljXEoTychZ4jnE+CQgra/wX4ZvHeiChTUMenCwfIYEYw==", + "dev": true, + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -11023,6 +11054,21 @@ "integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==", "dev": true }, + "@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "requires": { + "debug": "^4.1.1" + } + }, + "@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true + }, "@microsoft/fast-element": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.7.0.tgz", @@ -17608,6 +17654,17 @@ "simple-concat": "^1.0.0" } }, + "simple-git": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.10.0.tgz", + "integrity": "sha512-2w35xrS5rVtAW0g67LqtxCZN5cdddz/woQRfS0OJXaljXEoTychZ4jnE+CQgra/wX4ZvHeiChTUMenCwfIYEYw==", + "dev": true, + "requires": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + } + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", diff --git a/package.json b/package.json index 7b79caa3..94b88749 100644 --- a/package.json +++ b/package.json @@ -642,6 +642,16 @@ "default": null, "markdownDescription": "Specify the command you want to use to start your static site generator or framework. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.framework.startcommand)" }, + "frontMatter.git.actions": { + "type": "boolean", + "markdownDescription": "Specify if you want to use the Git actions for your website. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.git.actions)", + "default": false + }, + "frontMatter.git.commitMsg": { + "type": "string", + "markdownDescription": "Specify the commit message you want to use for the sync. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.git.commitmsg)", + "default": "Synced by Front Matter" + }, "frontMatter.global.activeMode": { "type": [ "string", @@ -2038,6 +2048,7 @@ "recoil": "^0.4.1", "rimraf": "^3.0.2", "semver": "^7.3.7", + "simple-git": "^3.10.0", "style-loader": "2.0.0", "tailwindcss": "^2.2.7", "tailwindcss-nested-groups": "^1.2.4", @@ -2061,4 +2072,4 @@ "dependencies": { "node-fetch": "^2.6.7" } -} \ No newline at end of file +} diff --git a/src/commands/Dashboard.ts b/src/commands/Dashboard.ts index fd02151e..e0d888b9 100644 --- a/src/commands/Dashboard.ts +++ b/src/commands/Dashboard.ts @@ -9,7 +9,7 @@ import { DashboardData } from '../models/DashboardData'; import { MediaLibrary } from '../helpers/MediaLibrary'; import { DashboardListener, MediaListener, SettingsListener, TelemetryListener, DataListener, PagesListener, ExtensionListener, SnippetListener, TaxonomyListener } from '../listeners/dashboard'; import { MediaListener as PanelMediaListener } from '../listeners/panel' -import { ModeListener } from '../listeners/general'; +import { GitListener, ModeListener } from '../listeners/general'; export class Dashboard { private static webview: WebviewPanel | null = null; @@ -146,6 +146,7 @@ export class Dashboard { TelemetryListener.process(msg); SnippetListener.process(msg); ModeListener.process(msg); + GitListener.process(msg); TaxonomyListener.process(msg); }); } diff --git a/src/constants/GeneralCommands.ts b/src/constants/GeneralCommands.ts index 476dc452..fe696fc0 100644 --- a/src/constants/GeneralCommands.ts +++ b/src/constants/GeneralCommands.ts @@ -3,8 +3,11 @@ export const GeneralCommands = { toWebview: { setMode: "setMode", + gitSyncingStart: "gitSyncingStart", + gitSyncingEnd: "gitSyncingEnd", }, toVSCode: { openLink: "openLink", + gitSync: "gitSync", } }; \ No newline at end of file diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 5e79dc4d..8e6f9620 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -78,6 +78,9 @@ export const SETTING_FRAMEWORK_START = "framework.startCommand"; export const SETTING_SITE_BASEURL = "site.baseURL"; +export const SETTING_GIT_ACTIONS = "git.actions"; +export const SETTING_GIT_COMMIT_MSG = "git.commitMsg"; + /** * @deprecated */ diff --git a/src/dashboardWebView/components/Header/Header.tsx b/src/dashboardWebView/components/Header/Header.tsx index 4ad2920d..464aa5fe 100644 --- a/src/dashboardWebView/components/Header/Header.tsx +++ b/src/dashboardWebView/components/Header/Header.tsx @@ -22,6 +22,7 @@ import { LightningBoltIcon, PlusIcon } from '@heroicons/react/outline'; import { useLocation, useNavigate } from 'react-router-dom'; import { routePaths } from '../..'; import { useEffect } from 'react'; +import { SyncButton } from './SyncButton'; export interface IHeaderProps { header?: React.ReactNode; @@ -108,6 +109,8 @@ export const Header: React.FunctionComponent = ({header, totalPage
+ + = (props: React.PropsWithChildren) => { + const settings = useRecoilValue(SettingsSelector); + const [ isSyncing, setIsSyncing ] = useState(false); + + const pull = () => { + Messenger.send(GeneralCommands.toVSCode.gitSync); + }; + + const messageListener = (message: MessageEvent>) => { + const { command, data } = message.data; + + if (command === GeneralCommands.toWebview.gitSyncingStart) { + setIsSyncing(true); + } else if (command === GeneralCommands.toWebview.gitSyncingEnd) { + setIsSyncing(false); + } + }; + + useEffect(() => { + Messenger.listen(messageListener); + + return () => { + Messenger.unlisten(messageListener); + } + }, []); + + if (!settings?.git?.actions || !settings?.git.isGitRepo) { + return null; + } + + return ( +
+ +
+ ); +}; \ No newline at end of file diff --git a/src/dashboardWebView/hooks/useMessages.tsx b/src/dashboardWebView/hooks/useMessages.tsx index 7d7c83c5..f9315f17 100644 --- a/src/dashboardWebView/hooks/useMessages.tsx +++ b/src/dashboardWebView/hooks/useMessages.tsx @@ -18,7 +18,7 @@ export default function useMessages() { const [, setView] = useRecoilState(DashboardViewAtom); const [, setSearchReady] = useRecoilState(SearchReadyAtom); - Messenger.listen((event: MessageEvent>) => { + const messageListener = (event: MessageEvent>) => { const message = event.data; switch (message.command) { @@ -53,14 +53,20 @@ export default function useMessages() { setMode(message.data); break; } - }); + }; useEffect(() => { + Messenger.listen(messageListener); + setLoading(true); Messenger.send(DashboardMessage.getViewType); Messenger.send(DashboardMessage.getTheme); Messenger.send(DashboardMessage.getData); Messenger.send(DashboardMessage.getMode); + + return () => { + Messenger.unlisten(messageListener); + } }, ['']); return { diff --git a/src/dashboardWebView/models/Settings.ts b/src/dashboardWebView/models/Settings.ts index d9d94ae9..7add77bf 100644 --- a/src/dashboardWebView/models/Settings.ts +++ b/src/dashboardWebView/models/Settings.ts @@ -1,12 +1,13 @@ import { DataType } from './../../models/DataType'; import { VersionInfo } from '../../models/VersionInfo'; import { ContentFolder } from '../../models/ContentFolder'; -import { ContentType, CustomScript, CustomTaxonomy, DraftField, Framework, Snippets, SortingSetting } from '../../models'; +import { ContentType, CustomScript, CustomTaxonomy, DraftField, Framework, GitSettings, Snippets, SortingSetting } from '../../models'; import { SortingOption } from './SortingOption'; import { DashboardViewType } from '.'; import { DataFile } from '../../models/DataFile'; export interface Settings { + git: GitSettings; beta: boolean; initialized: boolean; wsFolder: string; diff --git a/src/explorerView/ExplorerView.ts b/src/explorerView/ExplorerView.ts index 12edc8e0..a61bd54a 100644 --- a/src/explorerView/ExplorerView.ts +++ b/src/explorerView/ExplorerView.ts @@ -7,7 +7,7 @@ import { TagType } from '../panelWebView/TagType'; import { WebviewHelper } from '@estruyf/vscode'; import { Extension } from '../helpers/Extension'; import { Telemetry } from '../helpers/Telemetry'; -import { ModeListener } from '../listeners/general'; +import { GitListener, ModeListener } from '../listeners/general'; export class ExplorerView implements WebviewViewProvider, Disposable { public static readonly viewType = "frontMatter.explorer"; @@ -82,6 +82,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable { SettingsListener.process(msg); TaxonomyListener.process(msg); ModeListener.process(msg); + GitListener.process(msg); }); webviewView.onDidChangeVisibility(() => { diff --git a/src/extension.ts b/src/extension.ts index 8a0a634d..e5a7201b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -14,7 +14,7 @@ import { TagType } from './panelWebView/TagType'; import { ExplorerView } from './explorerView/ExplorerView'; import { Extension } from './helpers/Extension'; import { DashboardData } from './models/DashboardData'; -import { Logger, Settings as SettingsHelper } from './helpers'; +import { debounceCallback, Logger, Settings as SettingsHelper } from './helpers'; import { Content } from './commands/Content'; import ContentProvider from './providers/ContentProvider'; import { Wysiwyg } from './commands/Wysiwyg'; @@ -297,14 +297,4 @@ const handleAutoDateUpdate = (e: vscode.TextDocumentWillSaveEvent) => { const triggerShowDraftStatus = (location: string) => { Logger.info(`Triggering draft status update: ${location}`); statusDebouncer(() => { StatusListener.verify(frontMatterStatusBar, collection); }, 1000); -}; - -const debounceCallback = () => { - let timeout: NodeJS.Timeout; - - return (fnc: any, time: number) => { - const functionCall = (...args: any[]) => fnc.apply(args); - clearTimeout(timeout); - timeout = setTimeout(functionCall, time) as any; - }; }; \ No newline at end of file diff --git a/src/helpers/DashboardSettings.ts b/src/helpers/DashboardSettings.ts index a071bdc6..04e93fbb 100644 --- a/src/helpers/DashboardSettings.ts +++ b/src/helpers/DashboardSettings.ts @@ -1,8 +1,9 @@ +import { GitListener } from './../listeners/general/GitListener'; import { basename, join } from "path"; import { workspace } from "vscode"; import { Folders } from "../commands/Folders"; import { Project } from "../commands/Project"; -import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT, SETTING_DASHBOARD_CONTENT_TAGS, SETTING_MEDIA_SUPPORTED_MIMETYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TEMPLATES_ENABLED } from "../constants"; +import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT, SETTING_DASHBOARD_CONTENT_TAGS, SETTING_MEDIA_SUPPORTED_MIMETYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TEMPLATES_ENABLED, SETTING_GIT_ACTIONS } from "../constants"; import { DashboardViewType, SortingOption, Settings as ISettings } from "../dashboardWebView/models"; import { CustomScript, DraftField, Snippets, SortingSetting, TaxonomyType } from "../models"; import { DataFile } from "../models/DataFile"; @@ -19,8 +20,13 @@ export class DashboardSettings { const ext = Extension.getInstance(); const wsFolder = Folders.getWorkspaceFolder(); const isInitialized = Project.isInitialized(); + const gitActions = Settings.get(SETTING_GIT_ACTIONS); return { + git: { + isGitRepo: gitActions ? await GitListener.isGitRepository() : false, + actions: gitActions || false + }, beta: ext.isBetaVersion(), wsFolder: wsFolder ? wsFolder.fsPath : '', staticFolder: Folders.getStaticFolderRelativePath(), diff --git a/src/helpers/DebounceCallback.ts b/src/helpers/DebounceCallback.ts new file mode 100644 index 00000000..6075f985 --- /dev/null +++ b/src/helpers/DebounceCallback.ts @@ -0,0 +1,9 @@ +export const debounceCallback = () => { + let timeout: NodeJS.Timeout; + + return (fnc: any, time: number) => { + const functionCall = (...args: any[]) => fnc.apply(args); + clearTimeout(timeout); + timeout = setTimeout(functionCall, time) as any; + }; +}; \ No newline at end of file diff --git a/src/helpers/PanelSettings.ts b/src/helpers/PanelSettings.ts index 6664baf6..16b9a6e7 100644 --- a/src/helpers/PanelSettings.ts +++ b/src/helpers/PanelSettings.ts @@ -3,13 +3,20 @@ import { Extension, Settings } from "." import { Dashboard } from "../commands/Dashboard" import { Preview } from "../commands/Preview" import { Template } from "../commands/Template" -import { CONTEXT, DefaultFields, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_FRONTMATTER_HIGHLIGHT, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_FRAMEWORK_START, SETTING_AUTO_UPDATE_DATE, SETTING_COMMA_SEPARATED_FIELDS, SETTING_CUSTOM_SCRIPTS, SETTING_DATE_FORMAT, SETTING_PANEL_FREEFORM, SETTING_SEO_CONTENT_MIN_LENGTH, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_SLUG_LENGTH, SETTING_SEO_TITLE_LENGTH, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TAXONOMY_CATEGORIES, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TAXONOMY_FIELD_GROUPS, SETTING_TAXONOMY_TAGS } from "../constants" +import { CONTEXT, DefaultFields, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_FRONTMATTER_HIGHLIGHT, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_FRAMEWORK_START, SETTING_AUTO_UPDATE_DATE, SETTING_COMMA_SEPARATED_FIELDS, SETTING_CUSTOM_SCRIPTS, SETTING_DATE_FORMAT, SETTING_PANEL_FREEFORM, SETTING_SEO_CONTENT_MIN_LENGTH, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_SLUG_LENGTH, SETTING_SEO_TITLE_LENGTH, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TAXONOMY_CATEGORIES, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TAXONOMY_FIELD_GROUPS, SETTING_TAXONOMY_TAGS, SETTING_GIT_ACTIONS } from "../constants" +import { GitListener } from "../listeners/general" import { CustomScript, DataType, DraftField, FieldGroup, PanelSettings as IPanelSettings, ScriptType } from "../models" export class PanelSettings { public static async get(): Promise { + const gitActions = Settings.get(SETTING_GIT_ACTIONS); + return { + git: { + isGitRepo: gitActions ? await GitListener.isGitRepository() : false, + actions: gitActions || false + }, seo: { title: Settings.get(SETTING_SEO_TITLE_LENGTH) as number || -1, slug: Settings.get(SETTING_SEO_SLUG_LENGTH) as number || -1, diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts index 251a5974..1833005f 100644 --- a/src/helpers/SettingsHelper.ts +++ b/src/helpers/SettingsHelper.ts @@ -8,30 +8,22 @@ import { Folders } from '../commands/Folders'; import { join, basename } from 'path'; import { existsSync, readFileSync, watch, writeFileSync } from 'fs'; import { Extension } from './Extension'; +import { debounceCallback } from './DebounceCallback'; export class Settings { public static globalFile = "frontmatter.json"; private static config: vscode.WorkspaceConfiguration; private static globalConfig: any; + public static init() { - const fmConfig = Settings.projectConfigPath; - if (fmConfig && existsSync(fmConfig)) { - const localConfig = readFileSync(fmConfig, 'utf8'); - Settings.globalConfig = JSON.parse(localConfig); - commands.executeCommand('setContext', CONTEXT.isEnabled, true); - } else { - Settings.globalConfig = undefined; - } + Settings.readConfig(); Settings.config = vscode.workspace.getConfiguration(CONFIG_KEY); Settings.onConfigChange((global?: any) => { - if (global) { - Settings.globalConfig = Object.assign({}, global); - } else { - Settings.config = vscode.workspace.getConfiguration(CONFIG_KEY); - } + Settings.readConfig(); + Settings.config = vscode.workspace.getConfiguration(CONFIG_KEY); }); } @@ -61,6 +53,7 @@ export class Settings { */ public static onConfigChange(callback: (global?: any) => void) { const projectConfig = Settings.projectConfigPath; + const configDebouncer = debounceCallback(); workspace.onDidChangeConfiguration(() => { callback(); @@ -68,8 +61,10 @@ export class Settings { // Background listener for when it is not a user interaction if (projectConfig && existsSync(projectConfig)) { - watch(projectConfig, () => { - callback(); + let watcher = workspace.createFileSystemWatcher(projectConfig, true, false, true); + watcher.onDidChange(async (uri: Uri) => { + configDebouncer(() => callback(), 200); + // callback() }); } @@ -81,7 +76,8 @@ export class Settings { if (file) { const fileContents = file.getText(); const json = JSON.parse(fileContents); - callback(json); + configDebouncer(() => callback(json), 200); + // callback(json) } } }); @@ -346,6 +342,19 @@ export class Settings { return hasSetting; } + /** + * Get the project config path + * @returns + */ + public static get projectConfigPath() { + const wsFolder = Folders.getWorkspaceFolder(); + if (wsFolder) { + const fmConfig = join(wsFolder.fsPath, Settings.globalFile); + return fmConfig; + } + return undefined; + } + /** * Check if its the project config * @param filePath @@ -363,15 +372,16 @@ export class Settings { } /** - * Get the project config path - * @returns + * Read the global config file */ - public static get projectConfigPath() { - const wsFolder = Folders.getWorkspaceFolder(); - if (wsFolder) { - const fmConfig = join(wsFolder.fsPath, Settings.globalFile); - return fmConfig; + private static readConfig() { + const fmConfig = Settings.projectConfigPath; + if (fmConfig && existsSync(fmConfig)) { + const localConfig = readFileSync(fmConfig, 'utf8'); + Settings.globalConfig = JSON.parse(localConfig); + commands.executeCommand('setContext', CONTEXT.isEnabled, true); + } else { + Settings.globalConfig = undefined; } - return undefined; } } \ No newline at end of file diff --git a/src/helpers/index.ts b/src/helpers/index.ts index c7a90cc7..7284ae68 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -4,6 +4,7 @@ export * from './CustomScript'; export * from './DashboardSettings'; export * from './DataFileHelper'; export * from './DateHelper'; +export * from './DebounceCallback'; export * from './Extension'; export * from './FilesHelper'; export * from './FrameworkDetector'; diff --git a/src/listeners/general/GitListener.ts b/src/listeners/general/GitListener.ts new file mode 100644 index 00000000..a5271457 --- /dev/null +++ b/src/listeners/general/GitListener.ts @@ -0,0 +1,109 @@ +import { Settings } from './../../helpers/SettingsHelper'; +import { Dashboard } from '../../commands/Dashboard'; +import { ExplorerView } from '../../explorerView/ExplorerView'; +import { Extension, Logger } from '../../helpers'; +import { GeneralCommands } from './../../constants/GeneralCommands'; +import simpleGit, { SimpleGit } from 'simple-git'; +import { SETTING_GIT_COMMIT_MSG } from '../../constants'; +import { Folders } from '../../commands/Folders'; + +export class GitListener { + private static client: SimpleGit | null = null; + + /** + * Process the messages + * @param msg + */ + public static process(msg: { command: string, data: any }) { + switch(msg.command) { + case GeneralCommands.toVSCode.gitSync: + this.sync(); + break; + } + } + + public static async sync() { + try { + this.sendMsg(GeneralCommands.toWebview.gitSyncingStart, {}); + + await this.pull(); + await this.push(); + + this.sendMsg(GeneralCommands.toWebview.gitSyncingEnd, {}); + } catch (e) { + Logger.error((e as Error).message); + this.sendMsg(GeneralCommands.toWebview.gitSyncingEnd, {}); + } + } + + public static async isGitRepository() { + const git = this.getClient(); + if (!git) { + return false; + } + + const isRepo = await git.checkIsRepo(); + + if (!isRepo) { + Logger.warning(`Current workspace is not a GIT repository`); + } + + return isRepo; + } + + private static async pull() { + const git = this.getClient(); + if (!git) { + return; + } + + Logger.info(`Pulling from remote`); + await git.pull(); + } + + private static async push() { + const commitMsg = Settings.get(SETTING_GIT_COMMIT_MSG); + + const git = this.getClient(); + if (!git) { + return; + } + + Logger.info(`Pushing to remote`); + + const status = await git.status(); + + for (const file of status.not_added) { + await git.add(file); + } + for (const file of status.modified) { + await git.add(file); + } + + await git.commit(commitMsg || "Synced by Front Matter") + + await git.push(); + } + + private static getClient() { + const wsFolder = Folders.getWorkspaceFolder(); + + const options = { + baseDir: wsFolder?.fsPath || "", + binary: 'git', + maxConcurrentProcesses: 6, + } + + return simpleGit(options); + } + + private static sendMsg(command: string, data: any) { + + const extPath = Extension.getInstance().extensionPath; + const panel = ExplorerView.getInstance(extPath); + + panel.sendMessage({ command: command as any, data }); + + Dashboard.postWebviewMessage({ command: command as any, data }); + } +} \ No newline at end of file diff --git a/src/listeners/general/index.ts b/src/listeners/general/index.ts index 54a53db1..6af09d8f 100644 --- a/src/listeners/general/index.ts +++ b/src/listeners/general/index.ts @@ -1 +1,2 @@ export * from './ModeListener'; +export * from './GitListener'; diff --git a/src/models/GitSettings.ts b/src/models/GitSettings.ts new file mode 100644 index 00000000..ab79e4dd --- /dev/null +++ b/src/models/GitSettings.ts @@ -0,0 +1,5 @@ + +export interface GitSettings { + isGitRepo: boolean; + actions: boolean; +} \ No newline at end of file diff --git a/src/models/PanelSettings.ts b/src/models/PanelSettings.ts index 7366d567..b9dfabb4 100644 --- a/src/models/PanelSettings.ts +++ b/src/models/PanelSettings.ts @@ -1,10 +1,11 @@ import { FileStat } from "vscode"; -import { DraftField } from "."; +import { DraftField, GitSettings } from "."; import { Choice } from "./Choice"; import { DashboardData } from "./DashboardData"; import { DataType } from "./DataType"; export interface PanelSettings { + git: GitSettings; seo: SEO; slug: Slug; tags: string[]; diff --git a/src/models/index.ts b/src/models/index.ts index 51c13234..e484e46e 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -9,6 +9,7 @@ export * from './DataFolder'; export * from './DataType'; export * from './DraftField'; export * from './Framework'; +export * from './GitSettings'; export * from './MediaPaths'; export * from './Mode'; export * from './PanelSettings'; diff --git a/src/panelWebView/ViewPanel.tsx b/src/panelWebView/ViewPanel.tsx index 0cd56ead..04466a0a 100644 --- a/src/panelWebView/ViewPanel.tsx +++ b/src/panelWebView/ViewPanel.tsx @@ -11,6 +11,7 @@ import { SponsorMsg } from './components/SponsorMsg'; import useMessages from './hooks/useMessages'; import { FeatureFlag } from '../components/features/FeatureFlag'; import { FEATURE_FLAG } from '../constants/Features'; +import { GitAction } from './components/Git/GitAction'; export interface IViewPanelProps { } @@ -41,6 +42,8 @@ export const ViewPanel: React.FunctionComponent = (props: React return (
+ + diff --git a/src/panelWebView/components/ActionButton.tsx b/src/panelWebView/components/ActionButton.tsx index b96a76ab..a4399710 100644 --- a/src/panelWebView/components/ActionButton.tsx +++ b/src/panelWebView/components/ActionButton.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; export interface IActionButtonProps { - title: string; + title: JSX.Element | string; className?: string; disabled?: boolean; onClick: (e: React.SyntheticEvent) => void; @@ -10,7 +10,9 @@ export interface IActionButtonProps { const ActionButton: React.FunctionComponent = ({className, onClick, disabled,title}: React.PropsWithChildren) => { return (
- +
); }; diff --git a/src/panelWebView/components/BaseView.tsx b/src/panelWebView/components/BaseView.tsx index b66c5689..93444a43 100644 --- a/src/panelWebView/components/BaseView.tsx +++ b/src/panelWebView/components/BaseView.tsx @@ -10,6 +10,7 @@ import { StartServerButton } from './StartServerButton'; import { FeatureFlag } from '../../components/features/FeatureFlag'; import { FEATURE_FLAG } from '../../constants/Features'; import { Messenger } from '@estruyf/vscode/dist/client'; +import { GitAction } from './Git/GitAction'; export interface IBaseViewProps { settings: PanelSettings | undefined; @@ -44,6 +45,8 @@ const BaseView: React.FunctionComponent = ({settings, folderAndF return (
+ + diff --git a/src/panelWebView/components/Git/GitAction.tsx b/src/panelWebView/components/Git/GitAction.tsx new file mode 100644 index 00000000..faff7db1 --- /dev/null +++ b/src/panelWebView/components/Git/GitAction.tsx @@ -0,0 +1,55 @@ +import { Messenger } from '@estruyf/vscode/dist/client'; +import { EventData } from '@estruyf/vscode/dist/models'; +import { RefreshIcon } from '@heroicons/react/outline'; +import * as React from 'react'; +import { useEffect, useState } from 'react'; +import { GeneralCommands } from '../../../constants'; +import { PanelSettings } from '../../../models'; +import { ActionButton } from '../ActionButton'; + +export interface IGitActionProps { + settings: PanelSettings | undefined +} + +export const GitAction: React.FunctionComponent = ({ settings }: React.PropsWithChildren) => { + const [ isSyncing, setIsSyncing ] = useState(false); + + const pull = () => { + Messenger.send(GeneralCommands.toVSCode.gitSync); + }; + + const messageListener = (message: MessageEvent>) => { + const { command, data } = message.data; + + if (command === GeneralCommands.toWebview.gitSyncingStart) { + setIsSyncing(true); + } else if (command === GeneralCommands.toWebview.gitSyncingEnd) { + setIsSyncing(false); + } + }; + + useEffect(() => { + Messenger.listen(messageListener); + + return () => { + Messenger.unlisten(messageListener); + } + }, []); + + if (!settings?.git?.actions || !settings?.git.isGitRepo) { + return null; + } + + return ( +
+ + + Sync +
+ )} /> +
+ ); +}; \ No newline at end of file diff --git a/src/panelWebView/hooks/useMessages.tsx b/src/panelWebView/hooks/useMessages.tsx index 14aa91cb..68a51c89 100644 --- a/src/panelWebView/hooks/useMessages.tsx +++ b/src/panelWebView/hooks/useMessages.tsx @@ -7,6 +7,7 @@ import { Command } from '../Command'; import { CommandToCode } from '../CommandToCode'; import { TagType } from '../TagType'; import { Messenger } from '@estruyf/vscode/dist/client'; +import { EventData } from '@estruyf/vscode/dist/models'; export default function useMessages() { const [metadata, setMetadata] = useState({}); @@ -17,7 +18,7 @@ export default function useMessages() { const [mediaSelecting, setMediaSelecting] = useState(undefined); const [mode, setMode] = useState(undefined); - window.addEventListener('message', event => { + const messageListener = (event: MessageEvent>) => { const message = event.data; switch (message.command) { @@ -48,7 +49,7 @@ export default function useMessages() { setMode(message.data); break; } - }); + }; useEffect(() => { if (loading) { @@ -59,6 +60,7 @@ export default function useMessages() { }, [loading]) useEffect(() => { + Messenger.listen(messageListener); setLoading(true); // Show what you got after 5 seconds @@ -68,6 +70,10 @@ export default function useMessages() { Messenger.send(CommandToCode.getData); Messenger.send(CommandToCode.getMode); + + return () => { + Messenger.unlisten(messageListener); + } }, []); return { diff --git a/src/panelWebView/styles.css b/src/panelWebView/styles.css index e7bed06c..5afce082 100644 --- a/src/panelWebView/styles.css +++ b/src/panelWebView/styles.css @@ -1,4 +1,14 @@ +/* Animations */ +@keyframes spin { + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } +} +/* CSS */ .block_field__form, .list_field__form { background-color: transparent; @@ -508,6 +518,23 @@ vscode-divider { } } +/* Git actions */ +.git_actions__sync { + display: flex; + align-items: center; + justify-content: center; +} + +.git_actions__sync svg { + height: 1.25rem; + width: 1.25rem; + margin-right: .5rem; +} + +.animate-spin { + animation: spin 1s linear infinite; +} + /* Quill changes */ .ql-toolbar.ql-snow, .ql-container.ql-snow { diff --git a/tailwind.config.js b/tailwind.config.js index 3e708823..c8be881c 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -6,6 +6,16 @@ module.exports = { darkMode: 'class', // or 'media' or 'class' theme: { extend: { + animation: { + 'reverse-spin': 'reverse-spin 1s linear infinite' + }, + keyframes: { + 'reverse-spin': { + from: { + transform: 'rotate(360deg)' + }, + } + }, colors: { white: colors.white, gray: colors.trueGray, From 670791fcf6877ac8a8f5dcdc6bebde139916e5c7 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 29 Jul 2022 16:16:38 +0200 Subject: [PATCH 12/58] #377 - update setting name --- package.json | 4 ++-- src/constants/settings.ts | 2 +- src/helpers/DashboardSettings.ts | 4 ++-- src/helpers/PanelSettings.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 94b88749..b4b077cd 100644 --- a/package.json +++ b/package.json @@ -642,9 +642,9 @@ "default": null, "markdownDescription": "Specify the command you want to use to start your static site generator or framework. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.framework.startcommand)" }, - "frontMatter.git.actions": { + "frontMatter.git.enabled": { "type": "boolean", - "markdownDescription": "Specify if you want to use the Git actions for your website. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.git.actions)", + "markdownDescription": "Specify if you want to use the Git actions for your website. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.git.enabled)", "default": false }, "frontMatter.git.commitMsg": { diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 8e6f9620..4bcc196a 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -78,7 +78,7 @@ export const SETTING_FRAMEWORK_START = "framework.startCommand"; export const SETTING_SITE_BASEURL = "site.baseURL"; -export const SETTING_GIT_ACTIONS = "git.actions"; +export const SETTING_GIT_ENABLED = "git.enabled"; export const SETTING_GIT_COMMIT_MSG = "git.commitMsg"; /** diff --git a/src/helpers/DashboardSettings.ts b/src/helpers/DashboardSettings.ts index 04e93fbb..bf1aacc2 100644 --- a/src/helpers/DashboardSettings.ts +++ b/src/helpers/DashboardSettings.ts @@ -3,7 +3,7 @@ import { basename, join } from "path"; import { workspace } from "vscode"; import { Folders } from "../commands/Folders"; import { Project } from "../commands/Project"; -import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT, SETTING_DASHBOARD_CONTENT_TAGS, SETTING_MEDIA_SUPPORTED_MIMETYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TEMPLATES_ENABLED, SETTING_GIT_ACTIONS } from "../constants"; +import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT, SETTING_DASHBOARD_CONTENT_TAGS, SETTING_MEDIA_SUPPORTED_MIMETYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TEMPLATES_ENABLED, SETTING_GIT_ENABLED } from "../constants"; import { DashboardViewType, SortingOption, Settings as ISettings } from "../dashboardWebView/models"; import { CustomScript, DraftField, Snippets, SortingSetting, TaxonomyType } from "../models"; import { DataFile } from "../models/DataFile"; @@ -20,7 +20,7 @@ export class DashboardSettings { const ext = Extension.getInstance(); const wsFolder = Folders.getWorkspaceFolder(); const isInitialized = Project.isInitialized(); - const gitActions = Settings.get(SETTING_GIT_ACTIONS); + const gitActions = Settings.get(SETTING_GIT_ENABLED); return { git: { diff --git a/src/helpers/PanelSettings.ts b/src/helpers/PanelSettings.ts index 16b9a6e7..5f2ab9d4 100644 --- a/src/helpers/PanelSettings.ts +++ b/src/helpers/PanelSettings.ts @@ -3,14 +3,14 @@ import { Extension, Settings } from "." import { Dashboard } from "../commands/Dashboard" import { Preview } from "../commands/Preview" import { Template } from "../commands/Template" -import { CONTEXT, DefaultFields, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_FRONTMATTER_HIGHLIGHT, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_FRAMEWORK_START, SETTING_AUTO_UPDATE_DATE, SETTING_COMMA_SEPARATED_FIELDS, SETTING_CUSTOM_SCRIPTS, SETTING_DATE_FORMAT, SETTING_PANEL_FREEFORM, SETTING_SEO_CONTENT_MIN_LENGTH, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_SLUG_LENGTH, SETTING_SEO_TITLE_LENGTH, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TAXONOMY_CATEGORIES, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TAXONOMY_FIELD_GROUPS, SETTING_TAXONOMY_TAGS, SETTING_GIT_ACTIONS } from "../constants" +import { CONTEXT, DefaultFields, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_FRONTMATTER_HIGHLIGHT, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_FRAMEWORK_START, SETTING_AUTO_UPDATE_DATE, SETTING_COMMA_SEPARATED_FIELDS, SETTING_CUSTOM_SCRIPTS, SETTING_DATE_FORMAT, SETTING_PANEL_FREEFORM, SETTING_SEO_CONTENT_MIN_LENGTH, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_SLUG_LENGTH, SETTING_SEO_TITLE_LENGTH, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TAXONOMY_CATEGORIES, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TAXONOMY_CUSTOM, SETTING_TAXONOMY_FIELD_GROUPS, SETTING_TAXONOMY_TAGS, SETTING_GIT_ENABLED } from "../constants" import { GitListener } from "../listeners/general" import { CustomScript, DataType, DraftField, FieldGroup, PanelSettings as IPanelSettings, ScriptType } from "../models" export class PanelSettings { public static async get(): Promise { - const gitActions = Settings.get(SETTING_GIT_ACTIONS); + const gitActions = Settings.get(SETTING_GIT_ENABLED); return { git: { From 3ca6609ace6a9f684fda4f5c12b080b040c5c008 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Sat, 30 Jul 2022 14:23:57 +0200 Subject: [PATCH 13/58] #377 - Git sync command --- package.json | 95 +++++++++++++++------------- src/constants/Extension.ts | 3 + src/constants/TelemetryEvent.ts | 3 + src/constants/context.ts | 2 + src/extension.ts | 5 ++ src/helpers/Extension.ts | 10 +++ src/listeners/general/GitListener.ts | 37 ++++++++++- 7 files changed, 109 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index b4b077cd..fba9c40f 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "activitybar": [ { "id": "frontmatter-explorer", - "title": "FrontMatter", + "title": "Front Matter", "icon": "assets/frontmatter-short-min.svg" } ] @@ -69,9 +69,9 @@ "frontmatter-explorer": [ { "id": "frontMatter.explorer", - "name": "FrontMatter", + "name": "Front Matter", "icon": "assets/frontmatter-short-min.svg", - "contextualTitle": "FrontMatter", + "contextualTitle": "Front Matter", "type": "webview" } ] @@ -1369,27 +1369,27 @@ { "command": "frontMatter.authenticate", "title": "Authenticate", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.contenttype.generate", "title": "Generate content type from current file", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.contenttype.addMissingFields", "title": "Add missing fields from front matter to content type", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.contenttype.setContentType", "title": "Set the content type to use for the current file", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.markup.blockquote", "title": "Blockquote", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/blockquote-light.svg", "dark": "assets/icons/blockquote-dark.svg" @@ -1398,7 +1398,7 @@ { "command": "frontMatter.markup.bold", "title": "Bold", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/bold-light.svg", "dark": "assets/icons/bold-dark.svg" @@ -1407,7 +1407,7 @@ { "command": "frontMatter.dashboard.close", "title": "Close dashboard", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/frontmatter-small-teal.svg", "light": "/assets/icons/frontmatter-small-teal.svg" @@ -1416,7 +1416,7 @@ { "command": "frontMatter.markup.code", "title": "Code", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/code-light.svg", "dark": "assets/icons/code-dark.svg" @@ -1425,7 +1425,7 @@ { "command": "frontMatter.markup.codeblock", "title": "Codeblock", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/codeblock-light.svg", "dark": "assets/icons/codeblock-dark.svg" @@ -1434,7 +1434,7 @@ { "command": "frontMatter.collapseSections", "title": "Collapse sections", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/close-light.svg", "dark": "assets/icons/close-dark.svg" @@ -1443,37 +1443,37 @@ { "command": "frontMatter.initTemplate", "title": "Initialize the template folder", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.createTemplate", "title": "Create template from current file", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.createCategory", "title": "Create category", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.createContent", "title": "Create new content from defined content type or template", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.createTag", "title": "Create tag", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.diagnostics", "title": "Diagnostic logging", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.exportTaxonomy", "title": "Export all tags & categories to your settings", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.createFromTemplate", @@ -1490,12 +1490,12 @@ { "command": "frontMatter.generateSlug", "title": "Generate slug based on content title", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.markup.heading", "title": "Heading", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/heading-light.svg", "dark": "assets/icons/heading-dark.svg" @@ -1504,17 +1504,17 @@ { "command": "frontMatter.init", "title": "Initialize project", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.insertCategories", "title": "Insert categories", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.insertMedia", "title": "Insert media into your content", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/media-dark.svg", "light": "/assets/icons/media-light.svg" @@ -1523,7 +1523,7 @@ { "command": "frontMatter.insertSnippet", "title": "Insert snippet into your content", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/scissors-dark.svg", "light": "/assets/icons/scissors-light.svg" @@ -1532,12 +1532,12 @@ { "command": "frontMatter.insertTags", "title": "Insert tags", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.markup.italic", "title": "Italic", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/italic-light.svg", "dark": "assets/icons/italic-dark.svg" @@ -1546,7 +1546,7 @@ { "command": "frontMatter.dashboard", "title": "Open dashboard", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/frontmatter-small-dark.svg", "light": "/assets/icons/frontmatter-small-light.svg" @@ -1555,7 +1555,7 @@ { "command": "frontMatter.dashboard.data", "title": "Open data dashboard", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/frontmatter-small-dark.svg", "light": "/assets/icons/frontmatter-small-light.svg" @@ -1564,7 +1564,7 @@ { "command": "frontMatter.dashboard.media", "title": "Open media dashboard", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/frontmatter-small-dark.svg", "light": "/assets/icons/frontmatter-small-light.svg" @@ -1573,7 +1573,7 @@ { "command": "frontMatter.dashboard.snippets", "title": "Open snippets dashboard", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/frontmatter-small-dark.svg", "light": "/assets/icons/frontmatter-small-light.svg" @@ -1582,7 +1582,7 @@ { "command": "frontMatter.dashboard.taxonomy", "title": "Open taxonomies dashboard", - "category": "Front matter", + "category": "Front Matter", "icon": { "dark": "/assets/icons/frontmatter-small-dark.svg", "light": "/assets/icons/frontmatter-small-light.svg" @@ -1591,7 +1591,7 @@ { "command": "frontMatter.markup.orderedlist", "title": "Ordered list", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/ordered-list-light.svg", "dark": "assets/icons/ordered-list-dark.svg" @@ -1600,7 +1600,7 @@ { "command": "frontMatter.markup.options", "title": "Other markup options", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/options-light.svg", "dark": "assets/icons/options-dark.svg" @@ -1609,27 +1609,27 @@ { "command": "frontMatter.preview", "title": "Preview content", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.promoteSettings", "title": "Promote settings from local to team level", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.remap", "title": "Remap or remove tag/category in all articles", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.setLastModifiedDate", "title": "Set lastmod date", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.markup.strikethrough", "title": "Strikethrough", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/strikethrough-light.svg", "dark": "assets/icons/strikethrough-dark.svg" @@ -1638,22 +1638,27 @@ { "command": "frontMatter.mode.switch", "title": "Switch mode", - "category": "Front matter", + "category": "Front Matter", "icon": "$(preview)" }, { "command": "frontMatter.markup.tasklist", "title": "Task list", - "category": "Front matter" + "category": "Front Matter" }, { "command": "frontMatter.markup.unorderedlist", "title": "Unordered list", - "category": "Front matter", + "category": "Front Matter", "icon": { "light": "assets/icons/unordered-list-light.svg", "dark": "assets/icons/unordered-list-dark.svg" } + }, + { + "command": "frontMatter.git.sync", + "title": "Sync", + "category": "Front Matter" } ], "menus": { @@ -1772,6 +1777,10 @@ "command": "frontMatter.dashboard.snippets", "when": "frontMatter:dashboard:snippets:enabled" }, + { + "command": "frontMatter.git.sync", + "when": "frontMatter:git:enabled" + }, { "command": "frontMatter.collapseSections", "when": "false" diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index e3cffae4..ada6a795 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -62,4 +62,7 @@ export const COMMAND_NAME = { generateContentType: getCommandName("contenttype.generate"), addMissingFields: getCommandName("contenttype.addMissingFields"), setContentType: getCommandName("contenttype.setContentType"), + + // Git + gitSync: getCommandName("git.sync"), }; \ No newline at end of file diff --git a/src/constants/TelemetryEvent.ts b/src/constants/TelemetryEvent.ts index 4b6bb928..302a1327 100644 --- a/src/constants/TelemetryEvent.ts +++ b/src/constants/TelemetryEvent.ts @@ -43,4 +43,7 @@ export const TelemetryEvent = { webviewContentsView: 'webviewContentsView', webviewSnippetsView: 'webviewSnippetsView', webviewTaxonomyDashboard: 'webviewTaxonomyDashboard', + + // Git + gitSync: 'gitSync', }; \ No newline at end of file diff --git a/src/constants/context.ts b/src/constants/context.ts index 007ddae4..4878599d 100644 --- a/src/constants/context.ts +++ b/src/constants/context.ts @@ -13,4 +13,6 @@ export const CONTEXT = { isSnippetsDashboardEnabled: "frontMatter:dashboard:snippets:enabled", isDataDashboardEnabled: "frontMatter:dashboard:data:enabled", + + isGitEnabled: "frontMatter:git:enabled", }; \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index e5a7201b..84cd562d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,3 +1,4 @@ +import { GitListener } from './listeners/general/GitListener'; import * as vscode from 'vscode'; import { Telemetry } from './helpers/Telemetry'; import { ContentType } from './helpers/ContentType'; @@ -202,6 +203,7 @@ export async function activate(context: vscode.ExtensionContext) { SettingsHelper.onConfigChange((global?: any) => { Template.init(); Preview.init(); + GitListener.init(); SettingsListener.getSettings(); DataListener.getFoldersAndFiles(); @@ -261,6 +263,9 @@ export async function activate(context: vscode.ExtensionContext) { // Diagnostics subscriptions.push(vscode.commands.registerCommand(COMMAND_NAME.diagnostics, Diagnostics.show)); + // Git + GitListener.init(); + // Subscribe all commands subscriptions.push( insertTags, diff --git a/src/helpers/Extension.ts b/src/helpers/Extension.ts index 31847e65..4ab882ec 100644 --- a/src/helpers/Extension.ts +++ b/src/helpers/Extension.ts @@ -104,10 +104,20 @@ export class Extension { return this.ctx.extensionMode === ExtensionMode.Production; } + /** + * Get the diagnostic collection for the extension + */ public get diagnosticCollection(): DiagnosticCollection { return this._collection; } + /** + * Get extension subscriptions + */ + public get subscriptions() { + return this.ctx.subscriptions; + } + /** * Set the current version information for the extension */ diff --git a/src/listeners/general/GitListener.ts b/src/listeners/general/GitListener.ts index a5271457..82b19e32 100644 --- a/src/listeners/general/GitListener.ts +++ b/src/listeners/general/GitListener.ts @@ -1,15 +1,39 @@ import { Settings } from './../../helpers/SettingsHelper'; import { Dashboard } from '../../commands/Dashboard'; import { ExplorerView } from '../../explorerView/ExplorerView'; -import { Extension, Logger } from '../../helpers'; +import { Extension, Logger, Telemetry } from '../../helpers'; import { GeneralCommands } from './../../constants/GeneralCommands'; import simpleGit, { SimpleGit } from 'simple-git'; -import { SETTING_GIT_COMMIT_MSG } from '../../constants'; +import { COMMAND_NAME, CONTEXT, SETTING_GIT_COMMIT_MSG, SETTING_GIT_ENABLED, TelemetryEvent } from '../../constants'; import { Folders } from '../../commands/Folders'; +import { commands } from 'vscode'; export class GitListener { + private static isRegistered: boolean = false; private static client: SimpleGit | null = null; + public static async init() { + let isEnabled = false; + const gitEnabled = Settings.get(SETTING_GIT_ENABLED); + if (gitEnabled) { + const isRepo = await GitListener.isGitRepository(); + if (isRepo) { + isEnabled = true; + } + } + + await commands.executeCommand('setContext', CONTEXT.isGitEnabled, isEnabled); + + if (!this.isRegistered) { + const ext = Extension.getInstance(); + ext.subscriptions.push( + commands.registerCommand(COMMAND_NAME.gitSync, GitListener.sync) + ); + + this.isRegistered = true; + } + } + /** * Process the messages * @param msg @@ -26,6 +50,8 @@ export class GitListener { try { this.sendMsg(GeneralCommands.toWebview.gitSyncingStart, {}); + Telemetry.send(TelemetryEvent.gitSync); + await this.pull(); await this.push(); @@ -86,6 +112,10 @@ export class GitListener { } private static getClient() { + if (this.client) { + return this.client; + } + const wsFolder = Folders.getWorkspaceFolder(); const options = { @@ -94,7 +124,8 @@ export class GitListener { maxConcurrentProcesses: 6, } - return simpleGit(options); + this.client = simpleGit(options); + return this.client; } private static sendMsg(command: string, data: any) { From c8ecc923095f1361323afd805221c1f820e9b2a0 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 4 Aug 2022 15:23:41 +0200 Subject: [PATCH 14/58] #376: post script functionality --- CHANGELOG.md | 1 + package.json | 14 +++++ .../components/ChoiceButton.tsx | 5 +- .../components/Contents/ContentActions.tsx | 2 +- .../components/Header/Header.tsx | 60 +++++++++++-------- .../components/Media/FolderCreation.tsx | 3 +- .../components/Media/Item.tsx | 3 +- src/helpers/ContentType.ts | 19 +++++- src/helpers/CustomScript.ts | 38 ++++++++---- src/helpers/PanelSettings.ts | 2 +- src/models/PanelSettings.ts | 5 +- 11 files changed, 104 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1580caca..5aafdf97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### ✨ New features +- [#376](https://github.com/estruyf/vscode-front-matter/issues/376): Ability to run scripts after content was created - [#377](https://github.com/estruyf/vscode-front-matter/issues/377): Git sync actions added on panel and content dashboard (pull and push your changes to remote) ### 🎨 Enhancements diff --git a/package.json b/package.json index b4b077cd..f41be4fb 100644 --- a/package.json +++ b/package.json @@ -363,6 +363,10 @@ "items": { "type": "object", "properties": { + "id": { + "type": "string", + "description": "ID of the script." + }, "title": { "type": "string", "description": "Title you want to give to your script. Will be shown as the title of the button." @@ -419,6 +423,11 @@ ], "description": "The type of script you want to execute.", "default": "node" + }, + "hidden": { + "type": "boolean", + "description": "Hide the action from the UI", + "default": false } }, "additionalProperties": false, @@ -1123,6 +1132,11 @@ "type": "string", "default": "", "description": "An optional template that can be used for creating new content." + }, + "postScript": { + "type": "string", + "default": "", + "description": "An optional post script that can be used after new content creation." } }, "additionalProperties": false, diff --git a/src/dashboardWebView/components/ChoiceButton.tsx b/src/dashboardWebView/components/ChoiceButton.tsx index 323700e8..7d8d6bb2 100644 --- a/src/dashboardWebView/components/ChoiceButton.tsx +++ b/src/dashboardWebView/components/ChoiceButton.tsx @@ -12,11 +12,10 @@ export interface IChoiceButtonProps { onClick: () => void; }[]; disabled?: boolean; - isTemplatesEnabled?: boolean; onClick: () => void; } -export const ChoiceButton: React.FunctionComponent = ({onClick, disabled, choices, isTemplatesEnabled, title}: React.PropsWithChildren) => { +export const ChoiceButton: React.FunctionComponent = ({onClick, disabled, choices, title}: React.PropsWithChildren) => { return ( { - isTemplatesEnabled && ( + choices.length > 0 && ( = ({ }, [path]); const customScriptActions = React.useMemo(() => { - return (scripts || []).filter(script => (script.type === undefined || script.type === ScriptType.Content) && !script.bulk).map(script => ( + return (scripts || []).filter(script => (script.type === undefined || script.type === ScriptType.Content) && !script.bulk && !script.hidden).map(script => ( {script.title}
} diff --git a/src/dashboardWebView/components/Header/Header.tsx b/src/dashboardWebView/components/Header/Header.tsx index 464aa5fe..d88b2c24 100644 --- a/src/dashboardWebView/components/Header/Header.tsx +++ b/src/dashboardWebView/components/Header/Header.tsx @@ -21,7 +21,7 @@ import { CustomScript } from '../../../models'; import { LightningBoltIcon, PlusIcon } from '@heroicons/react/outline'; import { useLocation, useNavigate } from 'react-router-dom'; import { routePaths } from '../..'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { SyncButton } from './SyncButton'; export interface IHeaderProps { @@ -73,6 +73,38 @@ export const Header: React.FunctionComponent = ({header, totalPage onClick: () => runBulkScript(s) })); + const choiceOptions = useMemo(() => { + const isEnabled = settings?.dashboardState?.contents?.templatesEnabled || false; + + if (isEnabled) { + return [ + { + title: ( +
+ + Create by content type +
+ ), + onClick: createByContentType, + disabled: !settings?.initialized + }, { + title: ( +
+ + Create by template +
+ ), + onClick: createByTemplate, + disabled: !settings?.initialized + }, + ...customActions + ]; + } + + return []; + + }, [settings?.dashboardState?.contents?.templatesEnabled]); + useEffect(() => { if (location.search) { const searchParams = new URLSearchParams(location.search); @@ -114,30 +146,8 @@ export const Header: React.FunctionComponent = ({header, totalPage - - Create by content type -
- ), - onClick: createByContentType, - disabled: !settings?.initialized - }, { - title: ( -
- - Create by template -
- ), - onClick: createByTemplate, - disabled: !settings?.initialized - }, - ...customActions - ]} - onClick={createContent} - isTemplatesEnabled={settings?.dashboardState?.contents?.templatesEnabled || undefined} + choices={choiceOptions} + onClick={createContent} disabled={!settings?.initialized} />
diff --git a/src/dashboardWebView/components/Media/FolderCreation.tsx b/src/dashboardWebView/components/Media/FolderCreation.tsx index 2258ceb1..d6591620 100644 --- a/src/dashboardWebView/components/Media/FolderCreation.tsx +++ b/src/dashboardWebView/components/Media/FolderCreation.tsx @@ -23,7 +23,8 @@ export const FolderCreation: React.FunctionComponent = (pr Messenger.send(DashboardMessage.runCustomScript, {script, path: selectedFolder}); }; - const scripts = (settings?.scripts || []).filter(script => script.type === ScriptType.MediaFolder); + const scripts = (settings?.scripts || []).filter(script => script.type === ScriptType.MediaFolder && !script.hidden); + if (scripts.length > 0) { return (
diff --git a/src/dashboardWebView/components/Media/Item.tsx b/src/dashboardWebView/components/Media/Item.tsx index 7b5cbbe8..e674ae10 100644 --- a/src/dashboardWebView/components/Media/Item.tsx +++ b/src/dashboardWebView/components/Media/Item.tsx @@ -225,7 +225,7 @@ export const Item: React.FunctionComponent = ({media}: React.PropsWi }; const customScriptActions = () => { - return (settings?.scripts || []).filter(script => script.type === ScriptType.MediaFile).map(script => ( + return (settings?.scripts || []).filter(script => script.type === ScriptType.MediaFile && !script.hidden).map(script => ( {script.title}
} @@ -259,7 +259,6 @@ export const Item: React.FunctionComponent = ({media}: React.PropsWi const extension = path.split('.').pop(); let icon = ; - console.log(media); if (isImageFile) { return ; diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 5b1845db..f1b3cf1d 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -1,9 +1,9 @@ import { ModeListener } from './../listeners/general/ModeListener'; import { PagesListener } from './../listeners/dashboard'; -import { ArticleHelper, Settings } from "."; +import { ArticleHelper, CustomScript, Settings } from "."; import { FEATURE_FLAG, SETTING_CONTENT_DRAFT_FIELD, SETTING_DATE_FORMAT, SETTING_FRAMEWORK_ID, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TAXONOMY_FIELD_GROUPS, TelemetryEvent } from "../constants"; -import { ContentType as IContentType, DraftField, Field, FieldGroup, FieldType } from '../models'; -import { Uri, commands, window, ProgressLocation } from 'vscode'; +import { ContentType as IContentType, DraftField, Field, FieldGroup, FieldType, ScriptType } from '../models'; +import { Uri, commands, window, ProgressLocation, workspace } from 'vscode'; import { Folders } from "../commands/Folders"; import { Questions } from "./Questions"; import { existsSync, writeFileSync } from "fs"; @@ -543,6 +543,19 @@ export class ContentType { writeFileSync(newFilePath, content, { encoding: "utf8" }); + // Check if the content type has a post script to execute + if (contentType.postScript) { + const scripts = await CustomScript.getScripts(); + const script = scripts.find(s => s.id === contentType.postScript); + + if (script && (script.type === ScriptType.Content || !script?.type)) { + await CustomScript.run(script, newFilePath); + + const doc = await workspace.openTextDocument(Uri.file(newFilePath)); + await doc.save(); + } + } + await commands.executeCommand('vscode.open', Uri.file(newFilePath)); Notifications.info(`Your new content has been created.`); diff --git a/src/helpers/CustomScript.ts b/src/helpers/CustomScript.ts index ee4df28f..ee9f3e67 100644 --- a/src/helpers/CustomScript.ts +++ b/src/helpers/CustomScript.ts @@ -1,3 +1,4 @@ +import { Settings } from './SettingsHelper'; import { CommandType } from './../models/PanelSettings'; import { CustomScript as ICustomScript, ScriptType } from '../models/PanelSettings'; import { window, env as vscodeEnv, ProgressLocation } from 'vscode'; @@ -12,9 +13,24 @@ import { Dashboard } from '../commands/Dashboard'; import { DashboardCommand } from '../dashboardWebView/DashboardCommand'; import { ParsedFrontMatter } from '../parsers'; import { TelemetryEvent } from '../constants/TelemetryEvent'; +import { SETTING_CUSTOM_SCRIPTS } from '../constants'; export class CustomScript { + /** + * Retrieve all scripts + * @returns + */ + public static async getScripts(): Promise { + const scripts = Settings.get(SETTING_CUSTOM_SCRIPTS) || []; + return scripts; + } + + /** + * Run a script + * @param script + * @param path + */ public static async run(script: ICustomScript, path: string | null = null): Promise { const wsFolder = Folders.getWorkspaceFolder(); @@ -24,19 +40,19 @@ export class CustomScript { if (script.type === ScriptType.MediaFile || script.type === ScriptType.MediaFolder) { Telemetry.send(TelemetryEvent.runMediaScript); - CustomScript.runMediaScript(wsPath, path, script); + await CustomScript.runMediaScript(wsPath, path, script); } else { Telemetry.send(TelemetryEvent.runCustomScript); if (script.bulk) { // Run script on all files - CustomScript.bulkRun(wsPath, script); + await CustomScript.bulkRun(wsPath, script); } else if (path) { // Run script for provided path - CustomScript.singleRun(wsPath, script, path); + await CustomScript.singleRun(wsPath, script, path); } else { // Run script on current file. - CustomScript.singleRun(wsPath, script); + await CustomScript.singleRun(wsPath, script); } } } @@ -64,13 +80,13 @@ export class CustomScript { } if (articlePath && article) { - window.withProgress({ + return window.withProgress({ location: ProgressLocation.Notification, title: `Executing: ${script.title}`, cancellable: false }, async () => { const output = await CustomScript.runScript(wsPath, article, articlePath as string, script); - CustomScript.showOutput(output, script, articlePath); + await CustomScript.showOutput(output, script, articlePath); }); } else { Notifications.warning(`${script.title}: Article couldn't be retrieved.`); @@ -116,7 +132,7 @@ export class CustomScript { } } - CustomScript.showOutput(output.join(`\n`), script); + await CustomScript.showOutput(output.join(`\n`), script); }); } @@ -142,7 +158,7 @@ export class CustomScript { try { const output = await CustomScript.executeScript(script, wsPath, `"${wsPath}" "${path}"`); - CustomScript.showOutput(output, script); + await CustomScript.showOutput(output, script); Dashboard.postWebviewMessage({ command: DashboardCommand.mediaUpdate @@ -188,7 +204,7 @@ export class CustomScript { * @param output * @param script */ - private static showOutput(output: string | null, script: ICustomScript, articlePath?: string | null): void { + private static async showOutput(output: string | null, script: ICustomScript, articlePath?: string | null): Promise { if (output) { try { const data = JSON.parse(output); @@ -212,9 +228,9 @@ export class CustomScript { } if (articlePath) { - ArticleHelper.updateByPath(articlePath, article); + await ArticleHelper.updateByPath(articlePath, article); } else if (editor) { - ArticleHelper.update(editor, article); + await ArticleHelper.update(editor, article); } else { throw new Error(`Couldn't update article.`); } diff --git a/src/helpers/PanelSettings.ts b/src/helpers/PanelSettings.ts index 5f2ab9d4..cec43fe9 100644 --- a/src/helpers/PanelSettings.ts +++ b/src/helpers/PanelSettings.ts @@ -36,7 +36,7 @@ export class PanelSettings { categories: Settings.get(SETTING_TAXONOMY_CATEGORIES, true) || [], customTaxonomy: Settings.get(SETTING_TAXONOMY_CUSTOM, true) || [], freeform: Settings.get(SETTING_PANEL_FREEFORM), - scripts: (Settings.get(SETTING_CUSTOM_SCRIPTS) || []).filter(s => s.type === ScriptType.Content || !s.type), + scripts: (Settings.get(SETTING_CUSTOM_SCRIPTS) || []).filter(s => (s.type === ScriptType.Content || !s.type) && !s.hidden), isInitialized: await Template.isInitialized(), modifiedDateUpdate: Settings.get(SETTING_AUTO_UPDATE_DATE) || false, writingSettingsEnabled: this.isWritingSettingsEnabled() || false, diff --git a/src/models/PanelSettings.ts b/src/models/PanelSettings.ts index b9dfabb4..57379266 100644 --- a/src/models/PanelSettings.ts +++ b/src/models/PanelSettings.ts @@ -48,6 +48,7 @@ export interface ContentType { previewPath?: string | null; pageBundle?: boolean; template?: string; + postScript?: string; } export type FieldType = "string" | "number" | "datetime" | "boolean" | "image" | "choice" | "tags" | "categories" | "draft" | "taxonomy" | "fields" | "json" | "block" | "file" | "dataFile" | "list" | "slug"; @@ -112,6 +113,7 @@ export interface FileInfo extends FileStat { }; export interface CustomScript { + id?: string; title: string; script: string; nodeBin?: string; @@ -120,6 +122,7 @@ export interface CustomScript { outputType?: string; type?: ScriptType; command?: CommandType | string; + hidden?: boolean; } export interface PreviewSettings { @@ -135,7 +138,7 @@ export interface CustomTaxonomy { export enum ScriptType { Content = "content", MediaFolder = "mediaFolder", - MediaFile = "mediaFile" + MediaFile = "mediaFile", } export enum CommandType { From 44f30f70d55749b9c5f0d1eaa333007c997ba06d Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 4 Aug 2022 20:58:45 +0200 Subject: [PATCH 15/58] Update authenticate command --- src/commands/Backers.ts | 4 ++-- src/constants/Extension.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/commands/Backers.ts b/src/commands/Backers.ts index 55ea0168..73bb80a4 100644 --- a/src/commands/Backers.ts +++ b/src/commands/Backers.ts @@ -1,5 +1,5 @@ import { commands, ExtensionContext } from 'vscode'; -import { CONTEXT } from '../constants'; +import { COMMAND_NAME, CONTEXT } from '../constants'; import { Extension } from '../helpers'; import { Credentials } from "../services/Credentials"; import fetch from "node-fetch"; @@ -17,7 +17,7 @@ export class Backers { Backers.tryUsernameCheck(); context.subscriptions.push( - commands.registerCommand('frontMatter.authenticate', async () => { + commands.registerCommand(COMMAND_NAME.authenticate, async () => { Backers.tryUsernameCheck(); }) ); diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index ada6a795..dceb5811 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -65,4 +65,7 @@ export const COMMAND_NAME = { // Git gitSync: getCommandName("git.sync"), + + // Authenticate + authenticate: getCommandName("authenticate"), }; \ No newline at end of file From a4da46ca212c628aa788a7d34140870372d5abb3 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 4 Aug 2022 21:29:21 +0200 Subject: [PATCH 16/58] #379 - New `frontMatter.config.reload` command --- CHANGELOG.md | 1 + package.json | 5 ++++ src/constants/Extension.ts | 3 ++ src/helpers/SettingsHelper.ts | 56 +++++++++++++++++++++++++++++++++-- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aafdf97..1455bb43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#376](https://github.com/estruyf/vscode-front-matter/issues/376): Ability to run scripts after content was created - [#377](https://github.com/estruyf/vscode-front-matter/issues/377): Git sync actions added on panel and content dashboard (pull and push your changes to remote) +- [#379](https://github.com/estruyf/vscode-front-matter/issues/377): New `frontMatter.config.reload` command to reload the configuration file + reinitialize its listeners ### 🎨 Enhancements diff --git a/package.json b/package.json index 5c942772..1359acda 100644 --- a/package.json +++ b/package.json @@ -1380,6 +1380,11 @@ } }, "commands": [ + { + "command": "frontMatter.config.reload", + "title": "Reload config", + "category": "Front Matter" + }, { "command": "frontMatter.authenticate", "title": "Authenticate", diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index dceb5811..b2eff6c8 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -68,4 +68,7 @@ export const COMMAND_NAME = { // Authenticate authenticate: getCommandName("authenticate"), + + // Config + reloadConfig: getCommandName("config.reload"), }; \ No newline at end of file diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts index 1833005f..7f2703fe 100644 --- a/src/helpers/SettingsHelper.ts +++ b/src/helpers/SettingsHelper.ts @@ -1,24 +1,34 @@ +import { parseWinPath } from './parseWinPath'; import { Telemetry } from './Telemetry'; import { Notifications } from './Notifications'; import { commands, Uri, workspace, window } from 'vscode'; import * as vscode from 'vscode'; import { ContentType, CustomTaxonomy, TaxonomyType } from '../models'; -import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, CONFIG_KEY, CONTEXT, ExtensionState, SETTING_TAXONOMY_CUSTOM, TelemetryEvent } from '../constants'; +import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, CONFIG_KEY, CONTEXT, ExtensionState, SETTING_TAXONOMY_CUSTOM, TelemetryEvent, COMMAND_NAME } from '../constants'; import { Folders } from '../commands/Folders'; import { join, basename } from 'path'; import { existsSync, readFileSync, watch, writeFileSync } from 'fs'; import { Extension } from './Extension'; import { debounceCallback } from './DebounceCallback'; +import { Logger } from './Logger'; export class Settings { public static globalFile = "frontmatter.json"; private static config: vscode.WorkspaceConfiguration; private static globalConfig: any; - + private static isInitialized: boolean = false; + private static listeners: any[] = []; + private static fileCreationWatcher: vscode.FileSystemWatcher | undefined; public static init() { Settings.readConfig(); + if (!Settings.isInitialized) { + Settings.isInitialized = true; + + commands.registerCommand(COMMAND_NAME.reloadConfig, Settings.rebindWatchers) + } + Settings.config = vscode.workspace.getConfiguration(CONFIG_KEY); Settings.onConfigChange((global?: any) => { @@ -59,10 +69,19 @@ export class Settings { callback(); }); + if (projectConfig && !existsSync(projectConfig)) { + // Keep track of the listeners + Settings.listeners.push(callback); + // No config file, no need to watch + Settings.createFileCreationWatcher(); + return; + } + // Background listener for when it is not a user interaction if (projectConfig && existsSync(projectConfig)) { let watcher = workspace.createFileSystemWatcher(projectConfig, true, false, true); watcher.onDidChange(async (uri: Uri) => { + Logger.info(`Config change detected - ${projectConfig} changed`); configDebouncer(() => callback(), 200); // callback() }); @@ -72,6 +91,8 @@ export class Settings { const filename = e.uri.fsPath; if (Settings.checkProjectConfig(filename)) { + Logger.info(`Config change detected - ${projectConfig} saved`); + const file = await workspace.openTextDocument(e.uri); if (file) { const fileContents = file.getText(); @@ -384,4 +405,35 @@ export class Settings { Settings.globalConfig = undefined; } } + + /** + * Create a file creation watcher + */ + private static createFileCreationWatcher() { + const ext = Extension.getInstance(); + + if (!Settings.fileCreationWatcher) { + Settings.fileCreationWatcher = workspace.createFileSystemWatcher(`**/*.json`, false, true, true); + Settings.fileCreationWatcher.onDidCreate(uri => { + if (parseWinPath(uri.fsPath) === parseWinPath(Settings.projectConfigPath)) { + Settings.rebindWatchers(); + // Stop listening to file creation events + Settings.fileCreationWatcher?.dispose(); + Settings.fileCreationWatcher = undefined; + } + }, null, ext.subscriptions); + } + } + + /** + * Rebind the configuration watchers + */ + private static rebindWatchers() { + Logger.info(`Rebinding ${this.listeners.length} listeners`); + + this.listeners.forEach(l => { + Settings.onConfigChange(l); + l(); + }); + } } \ No newline at end of file From 9325ce363808b50d53fbfbfb93395df6ea300a83 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 4 Aug 2022 21:32:30 +0200 Subject: [PATCH 17/58] Keep track of all config listeners --- src/helpers/SettingsHelper.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts index 7f2703fe..57defec7 100644 --- a/src/helpers/SettingsHelper.ts +++ b/src/helpers/SettingsHelper.ts @@ -68,10 +68,11 @@ export class Settings { workspace.onDidChangeConfiguration(() => { callback(); }); + + // Keep track of the listeners + Settings.listeners.push(callback); if (projectConfig && !existsSync(projectConfig)) { - // Keep track of the listeners - Settings.listeners.push(callback); // No config file, no need to watch Settings.createFileCreationWatcher(); return; From 282c95be2921bc6f16c68f6fc49adbbcb6616119 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 4 Aug 2022 21:33:00 +0200 Subject: [PATCH 18/58] Initialize listeners --- src/helpers/SettingsHelper.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts index 57defec7..a2391cfc 100644 --- a/src/helpers/SettingsHelper.ts +++ b/src/helpers/SettingsHelper.ts @@ -23,6 +23,8 @@ export class Settings { public static init() { Settings.readConfig(); + Settings.listeners = []; + if (!Settings.isInitialized) { Settings.isInitialized = true; @@ -68,7 +70,7 @@ export class Settings { workspace.onDidChangeConfiguration(() => { callback(); }); - + // Keep track of the listeners Settings.listeners.push(callback); From ecc9c740919b3af103d2783ca4afe642e8caab03 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 10 Aug 2022 16:09:21 +0200 Subject: [PATCH 19/58] #384: Fix issue `title` field in sub-fields --- CHANGELOG.md | 1 + src/dashboardWebView/index.tsx | 5 ++++- src/helpers/ContentType.ts | 8 +++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aafdf97..92da6383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ ### 🐞 Fixes - [#378](https://github.com/estruyf/vscode-front-matter/issues/378): Fix last modified update only to content in content folders +- [#384](https://github.com/estruyf/vscode-front-matter/issues/384): Fix issue `title` field in sub-fields ## [8.0.1] - 2022-07-13 diff --git a/src/dashboardWebView/index.tsx b/src/dashboardWebView/index.tsx index cd648392..fdd64f11 100644 --- a/src/dashboardWebView/index.tsx +++ b/src/dashboardWebView/index.tsx @@ -40,7 +40,10 @@ if (elm) { tracesSampleRate: 0, // No performance tracing required release: version || "", environment: environment || "", - ignoreErrors: ['ResizeObserver loop limit exceeded'] + ignoreErrors: [ + 'ResizeObserver loop limit exceeded', + "Cannot read properties of undefined (reading 'unobserve')" + ] }); } diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index f1b3cf1d..a407887c 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -572,7 +572,7 @@ export class ContentType { * @param contentType * @param data */ - private static async processFields(obj: IContentType | Field, titleValue: string, data: any, filePath: string) { + private static async processFields(obj: IContentType | Field, titleValue: string, data: any, filePath: string, isRoot: boolean = true): Promise { if (obj.fields) { const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; @@ -581,12 +581,14 @@ export class ContentType { if (field.default) { data[field.name] = processKnownPlaceholders(field.default, titleValue, dateFormat); data[field.name] = await ArticleHelper.processCustomPlaceholders(data[field.name], titleValue, filePath); - } else { + } else if (isRoot) { data[field.name] = titleValue; + } else { + data[field.name] = "" } } else { if (field.type === "fields") { - data[field.name] = await this.processFields(field, titleValue, {}, filePath); + data[field.name] = await this.processFields(field, titleValue, {}, filePath, false); } else { const defaultValue = field.default; From 4a8bbaf82e4ab5a7bc980dc963d2d06a90e61140 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 11 Aug 2022 17:43:07 +0200 Subject: [PATCH 20/58] Fix for empty tags --- src/dashboardWebView/components/Contents/Item.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/dashboardWebView/components/Contents/Item.tsx b/src/dashboardWebView/components/Contents/Item.tsx index 0991241d..4c2314f9 100644 --- a/src/dashboardWebView/components/Contents/Item.tsx +++ b/src/dashboardWebView/components/Contents/Item.tsx @@ -89,11 +89,13 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti
{ tags.map((tag, index) => ( - - #{tag} - + tag && ( + + #{tag} + + ) )) }
From 1766c19133428f313774e8f795f15049dd8f2d3c Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 11 Aug 2022 17:52:36 +0200 Subject: [PATCH 21/58] #385: Add a default draft field value --- CHANGELOG.md | 1 + src/helpers/ContentType.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b300b217..f47b7150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy - [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies - [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead +- [#385](https://github.com/estruyf/vscode-front-matter/issues/385): If no default value for the draft field is defined, the field value will be set to `true` ### ⚡️ Optimizations diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index a407887c..3a54d6fb 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -576,6 +576,7 @@ export class ContentType { if (obj.fields) { const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; + for (const field of obj.fields) { if (field.name === "title") { if (field.default) { @@ -595,8 +596,16 @@ export class ContentType { if (typeof defaultValue === "string") { data[field.name] = processKnownPlaceholders(defaultValue, titleValue, dateFormat); data[field.name] = await ArticleHelper.processCustomPlaceholders(data[field.name], titleValue, filePath); + } else if (typeof defaultValue !== "undefined") { + data[field.name] = defaultValue; } else { - data[field.name] = typeof defaultValue !== "undefined" ? defaultValue : ""; + const draftField = ContentType.getDraftField(); + + if (field.type === "draft" && (draftField?.type === "boolean" || draftField?.type === undefined)) { + data[field.name] = true; + } else { + data[field.name] = ""; + } } } } From 911adaa5d679e289ed9da146878e419e99fe9266 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 11 Aug 2022 20:56:07 +0200 Subject: [PATCH 22/58] #383: Add the item menu to the content list view --- CHANGELOG.md | 1 + package-lock.json | 326 ++++++++++-------- package.json | 1 + .../components/Contents/ContentActions.tsx | 72 ++-- .../components/Contents/Item.tsx | 34 +- .../components/Menu/ActionMenuButton.tsx | 8 +- .../components/Menu/MenuItems.tsx | 6 +- 7 files changed, 256 insertions(+), 192 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1455bb43..f3af7d0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy - [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies - [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead +- [#383](https://github.com/estruyf/vscode-front-matter/issues/383): Add the item menu to the content list view ### ⚡️ Optimizations diff --git a/package-lock.json b/package-lock.json index 012e7989..d49f2f3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@heroicons/react": "1.0.4", "@iarna/toml": "2.2.3", "@octokit/rest": "^18.12.0", + "@popperjs/core": "^2.11.6", "@sentry/react": "^6.13.3", "@sentry/tracing": "^6.13.3", "@tailwindcss/forms": "^0.3.3", @@ -125,38 +126,50 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@bendera/vscode-webview-elements": { @@ -465,9 +478,9 @@ "dev": true }, "node_modules/@popperjs/core": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.1.tgz", - "integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==", + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", "dev": true, "funding": { "type": "opencollective", @@ -1776,26 +1789,31 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.16.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", - "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001251", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.811", - "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/buffer": { @@ -1998,14 +2016,20 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", + "version": "1.0.30001375", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001375.tgz", + "integrity": "sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/chai": { "version": "4.3.6", @@ -3268,9 +3292,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.3.814", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.814.tgz", - "integrity": "sha512-0mH03cyjh6OzMlmjauGg0TLd87ErIJqWiYxMcOLKf5w6p0YEOl7DJAj7BDlXEFmCguY5CQaKVOiMjAMODO2XDw==", + "version": "1.4.215", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.215.tgz", + "integrity": "sha512-vqZxT8C5mlDZ//hQFhneHmOLnj1LhbzxV0+I1yqHV8SB1Oo4Y5Ne9+qQhwHl7O1s9s9cRuo2l5CoLEHdhMTwZg==", "dev": true }, "node_modules/emoji-regex": { @@ -3734,31 +3758,6 @@ "node": ">=8" } }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/fast-glob/node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4165,9 +4164,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/gray-matter": { @@ -5239,9 +5238,9 @@ } }, "node_modules/jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "dependencies": { "@types/node": "*", @@ -6228,16 +6227,16 @@ ] }, "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=8" + "node": ">=8.6" } }, "node_modules/mime": { @@ -6708,9 +6707,9 @@ } }, "node_modules/node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, "node_modules/normalize-package-data": { @@ -7316,10 +7315,16 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -9942,6 +9947,32 @@ "mkdirp": "^0.5.1" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", @@ -10976,35 +11007,35 @@ } }, "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.18.6" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", "dev": true }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" @@ -11279,9 +11310,9 @@ "dev": true }, "@popperjs/core": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.1.tgz", - "integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==", + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", "dev": true }, "@sentry/browser": { @@ -12407,16 +12438,15 @@ "dev": true }, "browserslist": { - "version": "4.16.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", - "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001251", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.811", - "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" } }, "buffer": { @@ -12568,9 +12598,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", + "version": "1.0.30001375", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001375.tgz", + "integrity": "sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==", "dev": true }, "chai": { @@ -13542,9 +13572,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.814", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.814.tgz", - "integrity": "sha512-0mH03cyjh6OzMlmjauGg0TLd87ErIJqWiYxMcOLKf5w6p0YEOl7DJAj7BDlXEFmCguY5CQaKVOiMjAMODO2XDw==", + "version": "1.4.215", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.215.tgz", + "integrity": "sha512-vqZxT8C5mlDZ//hQFhneHmOLnj1LhbzxV0+I1yqHV8SB1Oo4Y5Ne9+qQhwHl7O1s9s9cRuo2l5CoLEHdhMTwZg==", "dev": true }, "emoji-regex": { @@ -13914,24 +13944,6 @@ "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" - }, - "dependencies": { - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - } } }, "fast-json-stable-stringify": { @@ -14238,9 +14250,9 @@ } }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "gray-matter": { @@ -15009,9 +15021,9 @@ "dev": true }, "jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { "@types/node": "*", @@ -15693,13 +15705,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime": { @@ -16059,9 +16071,9 @@ } }, "node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, "normalize-package-data": { @@ -16511,10 +16523,16 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pidtree": { @@ -18509,6 +18527,16 @@ "mkdirp": "^0.5.1" } }, + "update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", diff --git a/package.json b/package.json index 1359acda..0855cc30 100644 --- a/package.json +++ b/package.json @@ -2014,6 +2014,7 @@ "@heroicons/react": "1.0.4", "@iarna/toml": "2.2.3", "@octokit/rest": "^18.12.0", + "@popperjs/core": "^2.11.6", "@sentry/react": "^6.13.3", "@sentry/tracing": "^6.13.3", "@tailwindcss/forms": "^0.3.3", diff --git a/src/dashboardWebView/components/Contents/ContentActions.tsx b/src/dashboardWebView/components/Contents/ContentActions.tsx index f216429d..739f0d28 100644 --- a/src/dashboardWebView/components/Contents/ContentActions.tsx +++ b/src/dashboardWebView/components/Contents/ContentActions.tsx @@ -6,17 +6,27 @@ import { CustomScript, ScriptType } from '../../../models'; import { DashboardMessage } from '../../DashboardMessage'; import { MenuItem, MenuItems, ActionMenuButton, QuickAction } from '../Menu'; import { Alert } from '../Modals/Alert'; +import { usePopper } from 'react-popper'; +import { useState } from 'react'; export interface IContentActionsProps { title: string; path: string; scripts: CustomScript[] | undefined; + listView?: boolean; onOpen: () => void; } -export const ContentActions: React.FunctionComponent = ({ title, path, scripts, onOpen }: React.PropsWithChildren) => { +export const ContentActions: React.FunctionComponent = ({ title, path, scripts, onOpen, listView }: React.PropsWithChildren) => { const [ showDeletionAlert, setShowDeletionAlert ] = React.useState(false); + const [referenceElement, setReferenceElement] = useState(null); + const [popperElement, setPopperElement] = useState(null); + const { styles, attributes, forceUpdate } = usePopper(referenceElement, popperElement, { + placement: listView ? 'right-start' : 'bottom-end', + strategy: 'fixed' + }) + const onView = (e: React.MouseEvent) => { e.stopPropagation(); onOpen(); @@ -50,37 +60,45 @@ export const ContentActions: React.FunctionComponent = ({ return ( <> -
-
+
+
- -
- - - - - + + { + !listView && ( +
+ + + + + +
+ ) + } + +
+
- +
+ + View
} + onClick={(value, e) => onView(e)} /> - - View
} - onClick={(value, e) => onView(e)} /> + { customScriptActions } - { customScriptActions } - - Delete
} - onClick={(value, e) => onDelete(e)} /> - + Delete
} + onClick={(value, e) => onDelete(e)} /> + +
diff --git a/src/dashboardWebView/components/Contents/Item.tsx b/src/dashboardWebView/components/Contents/Item.tsx index 0991241d..8a645664 100644 --- a/src/dashboardWebView/components/Contents/Item.tsx +++ b/src/dashboardWebView/components/Contents/Item.tsx @@ -52,10 +52,9 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti if (view === DashboardViewType.Grid) { return (
  • -
    @@ -80,9 +79,9 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti onOpen={openFile} />
    -

    {title}

    + -

    {description}

    + { tags && tags.length > 0 && ( @@ -100,15 +99,26 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti ) }
    - +
  • ); } else if (view === DashboardViewType.List) { return (
  • - + +
    @@ -116,7 +126,7 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti
    { draftField && draftField.name && }
    - +
  • ); } diff --git a/src/dashboardWebView/components/Menu/ActionMenuButton.tsx b/src/dashboardWebView/components/Menu/ActionMenuButton.tsx index 05e73988..772ee068 100644 --- a/src/dashboardWebView/components/Menu/ActionMenuButton.tsx +++ b/src/dashboardWebView/components/Menu/ActionMenuButton.tsx @@ -5,11 +5,15 @@ import * as React from 'react'; export interface IActionMenuButtonProps { title: string; disabled?: boolean; + ref?: (instance: Element | null) => void; } -export const ActionMenuButton: React.FunctionComponent = ({ title, disabled }: React.PropsWithChildren) => { +export const ActionMenuButton: React.FunctionComponent = ({ title, disabled, ref }: React.PropsWithChildren) => { return ( - + {title} diff --git a/src/dashboardWebView/components/Menu/MenuItems.tsx b/src/dashboardWebView/components/Menu/MenuItems.tsx index 78c8e32b..013d294e 100644 --- a/src/dashboardWebView/components/Menu/MenuItems.tsx +++ b/src/dashboardWebView/components/Menu/MenuItems.tsx @@ -5,12 +5,14 @@ import { Fragment } from 'react'; export interface IMenuItemsProps { widthClass?: string; marginTopClass?: string; + updatePopper?: () => void; } -export const MenuItems: React.FunctionComponent = ({widthClass, marginTopClass, children}: React.PropsWithChildren) => { +export const MenuItems: React.FunctionComponent = ({widthClass, marginTopClass, children, updatePopper}: React.PropsWithChildren) => { return ( updatePopper ? updatePopper() : null} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" @@ -18,7 +20,7 @@ export const MenuItems: React.FunctionComponent = ({widthClass, leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - +
    {children}
    From 76e3c08405e1449cdd3d7b32a7c4ac7dffffb514 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 2 Sep 2022 09:49:48 +0200 Subject: [PATCH 23/58] Fix for custom placeholders that return errors --- src/helpers/ArticleHelper.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index aa054757..4eb8356e 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -441,6 +441,8 @@ export class ArticleHelper { } catch (e) { Notifications.error(`Error while processing the ${placeholder.id} placeholder`); Logger.error((e as Error).message); + + value = ""; } } From af1cc15d3de1f285bb533495bfc9559e33e2f057 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 2 Sep 2022 09:50:09 +0200 Subject: [PATCH 24/58] Fix for new popper menu on media items --- .../components/Media/Item.tsx | 122 ++++++++++-------- 1 file changed, 67 insertions(+), 55 deletions(-) diff --git a/src/dashboardWebView/components/Media/Item.tsx b/src/dashboardWebView/components/Media/Item.tsx index e674ae10..5ee91ba2 100644 --- a/src/dashboardWebView/components/Media/Item.tsx +++ b/src/dashboardWebView/components/Media/Item.tsx @@ -3,7 +3,7 @@ import { Menu } from '@headlessui/react'; import { ClipboardIcon, CodeIcon, DocumentIcon, EyeIcon, MusicNoteIcon, PencilIcon, PhotographIcon, PlusIcon, TerminalIcon, TrashIcon, VideoCameraIcon } from '@heroicons/react/outline'; import { basename, dirname } from 'path'; import * as React from 'react'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; import { CustomScript } from '../../../helpers/CustomScript'; import { parseWinPath } from '../../../helpers/parseWinPath'; @@ -18,6 +18,7 @@ import { QuickAction } from '../Menu/QuickAction'; import { Alert } from '../Modals/Alert'; import { InfoDialog } from '../Modals/InfoDialog'; import { DetailsSlideOver } from './DetailsSlideOver'; +import { usePopper } from 'react-popper'; export interface IItemProps { media: MediaInfo; @@ -25,17 +26,24 @@ export interface IItemProps { export const Item: React.FunctionComponent = ({media}: React.PropsWithChildren) => { const [ , setLightbox ] = useRecoilState(LightboxAtom); - const [ showAlert, setShowAlert ] = React.useState(false); - const [ showForm, setShowForm ] = React.useState(false); - const [ showSnippetSelection, setShowSnippetSelection ] = React.useState(false); - const [ showDetails, setShowDetails ] = React.useState(false); - const [ caption, setCaption ] = React.useState(media.caption); - const [ alt, setAlt ] = React.useState(media.alt); - const [ filename, setFilename ] = React.useState(null); + const [ showAlert, setShowAlert ] = useState(false); + const [ showForm, setShowForm ] = useState(false); + const [ showSnippetSelection, setShowSnippetSelection ] = useState(false); + const [ showDetails, setShowDetails ] = useState(false); + const [ caption, setCaption ] = useState(media.caption); + const [ alt, setAlt ] = useState(media.alt); + const [ filename, setFilename ] = useState(null); const settings = useRecoilValue(SettingsSelector); const selectedFolder = useRecoilValue(SelectedMediaFolderSelector); const viewData = useRecoilValue(ViewDataSelector); + const [referenceElement, setReferenceElement] = useState(null); + const [popperElement, setPopperElement] = useState(null); + const { styles, attributes, forceUpdate } = usePopper(referenceElement, popperElement, { + placement: 'bottom-end', + strategy: 'fixed' + }) + const mediaSnippets = useMemo(() => { if (!settings?.snippets) { return []; @@ -380,59 +388,63 @@ export const Item: React.FunctionComponent = ({media}: React.PropsWi - +
    + +
    - - - Edit metadata - - )} - onClick={updateMetadata} - /> +
    + + + Edit metadata +
    + )} + onClick={updateMetadata} + /> - { - viewData?.data?.filePath ? ( - <> - Insert image markdown} - onClick={insertToArticle} /> + { + viewData?.data?.filePath ? ( + <> + Insert image markdown} + onClick={insertToArticle} /> - { - (viewData?.data?.position && mediaSnippets.length > 0) && mediaSnippets.map((snippet, idx) => ( - {snippet.title}} - onClick={() => processSnippet(snippet)} /> - )) - } + { + (viewData?.data?.position && mediaSnippets.length > 0) && mediaSnippets.map((snippet, idx) => ( + {snippet.title}} + onClick={() => processSnippet(snippet)} /> + )) + } - { customScriptActions() } - - ) : ( - <> - - Copy media path - - )} - onClick={copyToClipboard} /> + { customScriptActions() } + + ) : ( + <> + + Copy media path + + )} + onClick={copyToClipboard} /> - { customScriptActions() } - - ) - } + { customScriptActions() } + + ) + } - Reveal media} - onClick={revealMedia} /> + Reveal media} + onClick={revealMedia} /> - Delete} - onClick={deleteMedia} /> -
    + Delete} + onClick={deleteMedia} /> + + @@ -530,4 +542,4 @@ export const Item: React.FunctionComponent = ({media}: React.PropsWi } ); -}; \ No newline at end of file +}; From 5b712e64d747b85c6f13a41f4244aef3cc8d1e8a Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 2 Sep 2022 13:26:25 +0200 Subject: [PATCH 25/58] #390: Implement another JSON parser --- .vscode/settings.json | 15 +++++++++++++++ CHANGELOG.md | 1 + package-lock.json | 13 +++++++++++++ package.json | 1 + src/helpers/ArticleHelper.ts | 3 ++- src/helpers/FrameworkDetector.ts | 3 ++- src/helpers/SettingsHelper.ts | 29 ++++++++++++++++++++--------- 7 files changed, 54 insertions(+), 11 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f903325a..2ba4819d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,4 +10,19 @@ "typescript.tsc.autoDetect": "off", "eliostruyf.writingstyleguide.terms.isDisabled": true, "eliostruyf.writingstyleguide.biasFree.isDisabled": true, + "squarl.groups": [ + { + "id": "dashboard", + "name": "Dashboard" + } + ], + "squarl.bookmarks": [ + { + "name": "App.tsx", + "path": "src/dashboardWebView/components/App.tsx", + "description": "Start of dashboard", + "type": "file", + "groupId": "dashboard" + } + ], } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b35928b..9a28ea4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead - [#383](https://github.com/estruyf/vscode-front-matter/issues/383): Add the item menu to the content list view - [#385](https://github.com/estruyf/vscode-front-matter/issues/385): If no default value for the draft field is defined, the field value will be set to `true` +- [#390](https://github.com/estruyf/vscode-front-matter/issues/390): Implement another JSON parser in order to be able to parse the `frontmatter.json` file better ### ⚡️ Optimizations diff --git a/package-lock.json b/package-lock.json index d49f2f3d..93c58ba0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,6 +57,7 @@ "html-webpack-plugin": "4.5.0", "image-size": "^1.0.0", "invariant": "^2.2.4", + "jsonc-parser": "^3.2.0", "lodash-es": "^4.17.21", "lodash.omit": "^4.5.0", "lodash.uniqby": "4.7.0", @@ -5330,6 +5331,12 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -15097,6 +15104,12 @@ "minimist": "^1.2.0" } }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", diff --git a/package.json b/package.json index 0855cc30..c608e4a4 100644 --- a/package.json +++ b/package.json @@ -2052,6 +2052,7 @@ "html-webpack-plugin": "4.5.0", "image-size": "^1.0.0", "invariant": "^2.2.4", + "jsonc-parser": "^3.2.0", "lodash-es": "^4.17.21", "lodash.omit": "^4.5.0", "lodash.uniqby": "4.7.0", diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 4eb8356e..b6ea919b 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -1,3 +1,4 @@ +import * as jsoncParser from 'jsonc-parser'; import { CustomPlaceholder } from './../models/CustomPlaceholder'; import { Uri, workspace } from 'vscode'; import { MarkdownFoldingProvider } from './../providers/MarkdownFoldingProvider'; @@ -418,7 +419,7 @@ export class ArticleHelper { // Check if the output needs to be parsed if (output.includes("{") && output.includes("}")) { try { - output = JSON.parse(output); + output = jsoncParser.parse(output); } catch (e) { // Do nothing } diff --git a/src/helpers/FrameworkDetector.ts b/src/helpers/FrameworkDetector.ts index 862c1ca0..d1607e0c 100644 --- a/src/helpers/FrameworkDetector.ts +++ b/src/helpers/FrameworkDetector.ts @@ -1,3 +1,4 @@ +import * as jsoncParser from 'jsonc-parser'; import { existsSync, readFileSync } from "fs"; import jsyaml = require("js-yaml"); import { join, resolve } from "path"; @@ -29,7 +30,7 @@ export class FrameworkDetector { if (existsSync(pkgFile)) { let packageJson: any = readFileSync(pkgFile, "utf8"); if (packageJson) { - packageJson = typeof packageJson === "string" ? JSON.parse(packageJson) : packageJson; + packageJson = typeof packageJson === "string" ? jsoncParser.parse(packageJson) : packageJson; dependencies = packageJson.dependencies || null; devDependencies = packageJson.devDependencies || null; diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts index a2391cfc..9f711b66 100644 --- a/src/helpers/SettingsHelper.ts +++ b/src/helpers/SettingsHelper.ts @@ -11,6 +11,7 @@ import { existsSync, readFileSync, watch, writeFileSync } from 'fs'; import { Extension } from './Extension'; import { debounceCallback } from './DebounceCallback'; import { Logger } from './Logger'; +import * as jsoncParser from 'jsonc-parser'; export class Settings { public static globalFile = "frontmatter.json"; @@ -99,7 +100,7 @@ export class Settings { const file = await workspace.openTextDocument(e.uri); if (file) { const fileContents = file.getText(); - const json = JSON.parse(fileContents); + const json = jsoncParser.parse(fileContents); configDebouncer(() => callback(json), 200); // callback(json) } @@ -133,7 +134,11 @@ export class Settings { /** * Retrieve a setting from global and local config */ - public static get(name: string, merging: boolean = false): T | undefined{ + public static get(name: string, merging: boolean = false): T | undefined { + if (!Settings.config) { + return; + } + const configInpection = Settings.config.inspect(name); let setting = undefined; @@ -170,7 +175,7 @@ export class Settings { if (updateGlobal) { if (fmConfig && existsSync(fmConfig)) { const localConfig = readFileSync(fmConfig, 'utf8'); - Settings.globalConfig = JSON.parse(localConfig); + Settings.globalConfig = jsoncParser.parse(localConfig); Settings.globalConfig[`${CONFIG_KEY}.${name}`] = value; writeFileSync(fmConfig, JSON.stringify(Settings.globalConfig, null, 2), 'utf8'); @@ -399,13 +404,19 @@ export class Settings { * Read the global config file */ private static readConfig() { - const fmConfig = Settings.projectConfigPath; - if (fmConfig && existsSync(fmConfig)) { - const localConfig = readFileSync(fmConfig, 'utf8'); - Settings.globalConfig = JSON.parse(localConfig); - commands.executeCommand('setContext', CONTEXT.isEnabled, true); - } else { + try { + const fmConfig = Settings.projectConfigPath; + if (fmConfig && existsSync(fmConfig)) { + const localConfig = readFileSync(fmConfig, 'utf8'); + Settings.globalConfig = jsoncParser.parse(localConfig); + commands.executeCommand('setContext', CONTEXT.isEnabled, true); + } else { + Settings.globalConfig = undefined; + } + } catch (e) { Settings.globalConfig = undefined; + Notifications.error(`Error reading "frontmatter.json" config file. Check [output window](command:${COMMAND_NAME.showOutputChannel}) for more details.`); + Logger.error((e as Error).message); } } From dda9b88752aa338ff14a12d1f4e4d73602ff589d Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 2 Sep 2022 13:42:50 +0200 Subject: [PATCH 26/58] #388: Added a stop server action --- CHANGELOG.md | 1 + src/listeners/panel/DataListener.ts | 43 ++++++++++++++++--- src/panelWebView/CommandToCode.ts | 1 + .../components/StartServerButton.tsx | 11 ++++- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a28ea4e..0a54e4a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead - [#383](https://github.com/estruyf/vscode-front-matter/issues/383): Add the item menu to the content list view - [#385](https://github.com/estruyf/vscode-front-matter/issues/385): If no default value for the draft field is defined, the field value will be set to `true` +- [#388](https://github.com/estruyf/vscode-front-matter/issues/388): New stop server action has been added to the panel - [#390](https://github.com/estruyf/vscode-front-matter/issues/390): Implement another JSON parser in order to be able to parse the `frontmatter.json` file better ### ⚡️ Optimizations diff --git a/src/listeners/panel/DataListener.ts b/src/listeners/panel/DataListener.ts index aa2ab62e..722f4286 100644 --- a/src/listeners/panel/DataListener.ts +++ b/src/listeners/panel/DataListener.ts @@ -16,6 +16,7 @@ const FILE_LIMIT = 10; export class DataListener extends BaseListener { private static lastMetadataUpdate: any = {}; + private static readonly terminalName: string = 'Local server'; /** * Process the messages for the dashboard views @@ -41,6 +42,9 @@ export class DataListener extends BaseListener { case CommandToCode.frameworkCommand: this.openTerminalWithCommand(msg.data.command); break; + case CommandToCode.stopServer: + this.stopServer(); + break; case CommandToCode.updatePlaceholder: this.updatePlaceholder(msg?.data?.field, msg?.data?.value, msg?.data?.title); break; @@ -305,23 +309,48 @@ export class DataListener extends BaseListener { */ private static openTerminalWithCommand(command: string) { if (command) { - let terminal = window.activeTerminal; + let localServerTerminal = DataListener.findServerTerminal(); + if (localServerTerminal) { + localServerTerminal.dispose(); + } - if (!terminal || (terminal && terminal.state.isInteractedWith === true)) { - terminal = window.createTerminal({ - name: `Starting local server`, + if (!localServerTerminal || (localServerTerminal && localServerTerminal.state.isInteractedWith === true)) { + localServerTerminal = window.createTerminal({ + name: this.terminalName, iconPath: new ThemeIcon('server-environment'), message: `Starting local server`, }); } - if (terminal) { - terminal.sendText(command); - terminal.show(false); + if (localServerTerminal) { + localServerTerminal.sendText(command); + localServerTerminal.show(false); } } } + /** + * Stop the local server + */ + private static stopServer() { + const localServerTerminal = DataListener.findServerTerminal(); + if (localServerTerminal) { + localServerTerminal.dispose(); + } + } + + /** + * Find the server terminal + * @returns + */ + private static findServerTerminal() { + let terminals = window.terminals; + if (terminals) { + const localServerTerminal = terminals.find(t => t.name === DataListener.terminalName); + return localServerTerminal; + } + } + /** * Update the placeholder * @param field diff --git a/src/panelWebView/CommandToCode.ts b/src/panelWebView/CommandToCode.ts index 935b3757..9a94e557 100644 --- a/src/panelWebView/CommandToCode.ts +++ b/src/panelWebView/CommandToCode.ts @@ -39,4 +39,5 @@ export enum CommandToCode { setContentType = "set-content-type", getDataEntries = "get-data-entries", generateSlug = "generate-slug", + stopServer = "stop-server", } \ No newline at end of file diff --git a/src/panelWebView/components/StartServerButton.tsx b/src/panelWebView/components/StartServerButton.tsx index f22e675b..0ef02424 100644 --- a/src/panelWebView/components/StartServerButton.tsx +++ b/src/panelWebView/components/StartServerButton.tsx @@ -14,8 +14,17 @@ export const StartServerButton: React.FunctionComponent const startLocalServer = (command: string) => { Messenger.send(CommandToCode.frameworkCommand, { command }); }; + + const stopLocalServer = () => { + Messenger.send(CommandToCode.stopServer); + }; return ( - startCommand ? : null + startCommand ? ( + <> + + + + ) : null ); }; \ No newline at end of file From 69e0dc3343a8e186ae6a3120badd592434990f66 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 2 Sep 2022 13:44:11 +0200 Subject: [PATCH 27/58] Hide the initialize project action --- src/panelWebView/components/BaseView.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/panelWebView/components/BaseView.tsx b/src/panelWebView/components/BaseView.tsx index 93444a43..af0a7498 100644 --- a/src/panelWebView/components/BaseView.tsx +++ b/src/panelWebView/components/BaseView.tsx @@ -56,7 +56,9 @@ const BaseView: React.FunctionComponent = ({settings, folderAndF
    - + { + !settings?.isInitialized && + } { From 88c8cc82c8cb93a7465d3b267abf5b81c0344e65 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 5 Sep 2022 10:37:30 +0200 Subject: [PATCH 28/58] #394: Ordering of snippet fields is based on their field definition --- CHANGELOG.md | 1 + .../components/SnippetsView/SnippetForm.tsx | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a54e4a2..cf7324c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - [#385](https://github.com/estruyf/vscode-front-matter/issues/385): If no default value for the draft field is defined, the field value will be set to `true` - [#388](https://github.com/estruyf/vscode-front-matter/issues/388): New stop server action has been added to the panel - [#390](https://github.com/estruyf/vscode-front-matter/issues/390): Implement another JSON parser in order to be able to parse the `frontmatter.json` file better +- [#394](https://github.com/estruyf/vscode-front-matter/issues/394): Ordering of snippet fields is based on their field definition ### ⚡️ Optimizations diff --git a/src/dashboardWebView/components/SnippetsView/SnippetForm.tsx b/src/dashboardWebView/components/SnippetsView/SnippetForm.tsx index f7aadffd..2695977f 100644 --- a/src/dashboardWebView/components/SnippetsView/SnippetForm.tsx +++ b/src/dashboardWebView/components/SnippetsView/SnippetForm.tsx @@ -79,15 +79,21 @@ const SnippetForm: React.ForwardRefRenderFunction f.name === fieldName); - - if (field) { + // Loop over all fields to check if they are present in the snippet + for (const field of snippetFields) { + const idx = placeholders.findIndex(fieldName => fieldName === field.name); + if (idx > -1) { allFields.push({ ...field, value: insertPlaceholderValues(field.default || "") }); - } else { + } + } + + // Loop over all placeholders to find the ones that are not present in the snippet fields + for (const fieldName of placeholders) { + const idx = snippetFields.findIndex(field => field.name === fieldName); + if (idx === -1) { allFields.push({ name: fieldName, title: fieldName, From bc3d5cb6b2713e01128a58423fe58d16568886da Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 5 Sep 2022 10:53:57 +0200 Subject: [PATCH 29/58] Added contact links for issues --- .github/ISSUE_TEMPLATE/config.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..1d81c56d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false +contact_links: + - name: Documentation + url: https://frontmatter.codes/docs + about: See our documentation. + - name: Changelog + url: https://frontmatter.codes/updates + about: See our changelog. + - name: Front Matter website + url: https://frontmatter.codes + about: Our website. + - name: Support Front Matter + url: https://github.com/sponsors/estruyf + about: Support Front Matter development. \ No newline at end of file From ad6c37f62dd5690c7c963cae673070d98c4d1a2e Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 5 Sep 2022 10:55:38 +0200 Subject: [PATCH 30/58] Audit fix for dependencies --- package-lock.json | 232 +++++++++++++++++++++++++++++++--------------- 1 file changed, 159 insertions(+), 73 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93c58ba0..a81cda20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -109,12 +109,13 @@ } }, "node_modules/@actions/core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", - "integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", + "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "dev": true, "dependencies": { - "@actions/http-client": "^2.0.1" + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" } }, "node_modules/@actions/http-client": { @@ -232,6 +233,64 @@ "integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==", "dev": true }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -1566,9 +1625,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "dependencies": { "lodash": "^4.17.14" @@ -6334,9 +6393,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/mkdirp": { @@ -6684,9 +6743,9 @@ } }, "node_modules/node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, "engines": { "node": ">= 6.13.0" @@ -8026,9 +8085,9 @@ } }, "node_modules/react-quill": { - "version": "2.0.0-beta.4", - "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0-beta.4.tgz", - "integrity": "sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz", + "integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==", "dev": true, "dependencies": { "@types/quill": "^1.3.10", @@ -8036,8 +8095,8 @@ "quill": "^1.3.7" }, "peerDependencies": { - "react": "^16 || ^17", - "react-dom": "^16 || ^17" + "react": "^16 || ^17 || ^18", + "react-dom": "^16 || ^17 || ^18" } }, "node_modules/react-router": { @@ -9438,9 +9497,9 @@ } }, "node_modules/terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", "dev": true, "dependencies": { "commander": "^2.20.0", @@ -9489,13 +9548,14 @@ } }, "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -9503,23 +9563,6 @@ }, "engines": { "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" } }, "node_modules/thunky": { @@ -10996,12 +11039,13 @@ }, "dependencies": { "@actions/core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", - "integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", + "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "dev": true, "requires": { - "@actions/http-client": "^2.0.1" + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" } }, "@actions/http-client": { @@ -11092,6 +11136,55 @@ "integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -12264,9 +12357,9 @@ "dev": true }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "requires": { "lodash": "^4.17.14" @@ -15790,9 +15883,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "mkdirp": { @@ -16061,9 +16154,9 @@ } }, "node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true }, "node-json-db": { @@ -17059,9 +17152,9 @@ } }, "react-quill": { - "version": "2.0.0-beta.4", - "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0-beta.4.tgz", - "integrity": "sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz", + "integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==", "dev": true, "requires": { "@types/quill": "^1.3.10", @@ -18156,9 +18249,9 @@ } }, "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", "dev": true, "requires": { "commander": "^2.20.0", @@ -18180,22 +18273,15 @@ }, "dependencies": { "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } } } } From ac4aea68ebda81017477593f39989379dd1af877 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 5 Sep 2022 14:25:59 +0200 Subject: [PATCH 31/58] #352: Schema updates --- package.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c608e4a4..0f30ebbd 100644 --- a/package.json +++ b/package.json @@ -230,12 +230,18 @@ "value": { "type": "string", "description": "The placeholder its value" + }, + "script": { + "type": "string", + "description": "The script to execute to get the value of the placeholder" + }, + "command": { + "$ref": "#scriptCommand" } }, "additionalProperties": false, "required": [ - "id", - "value" + "id" ] }, "scope": "Content" @@ -406,6 +412,7 @@ "description": "The type for which the script will be used." }, "command": { + "$id": "#scriptCommand", "type": "string", "oneOf": [ { From e4f44def472ec4d5c0bc4ca7ac34e737183ecc25 Mon Sep 17 00:00:00 2001 From: Elio Date: Mon, 5 Sep 2022 14:58:06 +0200 Subject: [PATCH 32/58] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f84ac25..11392b5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - [#378](https://github.com/estruyf/vscode-front-matter/issues/378): Fix last modified update only to content in content folders - [#384](https://github.com/estruyf/vscode-front-matter/issues/384): Fix issue `title` field in sub-fields +- [#393](https://github.com/estruyf/vscode-front-matter/issues/393): Fix Windows file path for retrieving the preview path ## [8.0.1] - 2022-07-13 @@ -67,7 +68,6 @@ ### 🐞 Fixes - [#354](https://github.com/estruyf/vscode-front-matter/issues/354): Fix Windows file path parsing for inserting media files -- [#393](https://github.com/estruyf/vscode-front-matter/issues/393): Fix Windows file path for retrieving the preview path ## [7.3.3] - 2022-06-11 From 600c225265c53d40c4448ee61faa5b5d8753d9fe Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 7 Sep 2022 08:48:14 +0200 Subject: [PATCH 33/58] Added divider between action buttons and custom ones --- .vscode/settings.json | 18 ++++++++++++++++++ src/panelWebView/components/Actions.tsx | 12 +++++++++--- src/panelWebView/components/BaseView.tsx | 4 +++- src/panelWebView/styles.css | 5 +++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2ba4819d..647e1f4e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,10 @@ { "id": "dashboard", "name": "Dashboard" + }, + { + "id": "panel", + "name": "Panel" } ], "squarl.bookmarks": [ @@ -23,6 +27,20 @@ "description": "Start of dashboard", "type": "file", "groupId": "dashboard" + }, + { + "name": "ViewPanel.tsx", + "path": "src/panelWebView/ViewPanel.tsx", + "description": "Start of panel", + "type": "file", + "groupId": "panel" + }, + { + "name": "styles.css", + "path": "src/panelWebView/styles.css", + "description": "Panel styles", + "type": "file", + "groupId": "panel" } ], } \ No newline at end of file diff --git a/src/panelWebView/components/Actions.tsx b/src/panelWebView/components/Actions.tsx index 7997fcfd..d2d434b6 100644 --- a/src/panelWebView/components/Actions.tsx +++ b/src/panelWebView/components/Actions.tsx @@ -29,9 +29,15 @@ const Actions: React.FunctionComponent = ({ metadata, settings }: { (settings && settings.scripts && settings.scripts.length > 0) && ( - settings.scripts.map((value, idx) => ( - - )) + <> +
    + + { + settings.scripts.map((value, idx) => ( + + )) + } + ) }
    diff --git a/src/panelWebView/components/BaseView.tsx b/src/panelWebView/components/BaseView.tsx index af0a7498..abf00592 100644 --- a/src/panelWebView/components/BaseView.tsx +++ b/src/panelWebView/components/BaseView.tsx @@ -55,12 +55,14 @@ const BaseView: React.FunctionComponent = ({settings, folderAndF
    + { !settings?.isInitialized && } + - + { customActions.map((script) => ( diff --git a/src/panelWebView/styles.css b/src/panelWebView/styles.css index 5afce082..aca74858 100644 --- a/src/panelWebView/styles.css +++ b/src/panelWebView/styles.css @@ -518,6 +518,11 @@ vscode-divider { } } +/* Divider */ +.divider { + background: var(--divider-background); +} + /* Git actions */ .git_actions__sync { display: flex; From 3557360297d646d921ee0144473b6be79e3057e8 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 7 Sep 2022 09:59:27 +0200 Subject: [PATCH 34/58] #396 - Fix for index and _index previews --- CHANGELOG.md | 1 + src/commands/Preview.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11392b5c..81492f48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - [#378](https://github.com/estruyf/vscode-front-matter/issues/378): Fix last modified update only to content in content folders - [#384](https://github.com/estruyf/vscode-front-matter/issues/384): Fix issue `title` field in sub-fields - [#393](https://github.com/estruyf/vscode-front-matter/issues/393): Fix Windows file path for retrieving the preview path +- [#396](https://github.com/estruyf/vscode-front-matter/issues/396): Fix for `index` and `_index` page previews ## [8.0.1] - 2022-07-13 diff --git a/src/commands/Preview.ts b/src/commands/Preview.ts index 1acf517e..9a077795 100644 --- a/src/commands/Preview.ts +++ b/src/commands/Preview.ts @@ -15,7 +15,7 @@ import { Folders } from './Folders'; export class Preview { - /**  + /** * Init the preview */ public static async init() { @@ -80,9 +80,14 @@ export class Preview { } catch (error) { slug = join(pathname, slug); } + } - // Make sure there are no backslashes in the slug - slug = parseWinPath(slug); + // Make sure there are no backslashes in the slug + slug = parseWinPath(slug); + + // Verify if the slug doesn't end with _index or index + if (slug.endsWith('_index') || slug.endsWith('index')) { + slug = slug.substring(0, slug.endsWith('_index') ? slug.length - 6 : slug.length - 5); } // Create the preview webview From f46fdb9fb09e83e7f3b3f5e33ffcca169b4df88c Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 7 Sep 2022 10:03:25 +0200 Subject: [PATCH 35/58] Preview tab title --- CHANGELOG.md | 1 + src/commands/Preview.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81492f48..3cdc67e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ ### ⚡️ Optimizations - Internal post message optimizations to the webviews +- Preview tab now shows the title of the page/content if present ### 🐞 Fixes diff --git a/src/commands/Preview.ts b/src/commands/Preview.ts index 9a077795..eb3b4d84 100644 --- a/src/commands/Preview.ts +++ b/src/commands/Preview.ts @@ -93,7 +93,7 @@ export class Preview { // Create the preview webview const webView = window.createWebviewPanel( 'frontMatterPreview', - 'FrontMatter Preview', + article?.data?.title ? `Preview: ${article?.data?.title}` : 'FrontMatter Preview', { viewColumn: ViewColumn.Beside, preserveFocus: true From 45285d3cf2195efbd0268387dd63f9374800e98e Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 7 Sep 2022 12:29:02 +0200 Subject: [PATCH 36/58] 8.1.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a81cda20..375eb46c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-front-matter-beta", - "version": "8.0.1", + "version": "8.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-front-matter-beta", - "version": "8.0.1", + "version": "8.1.0", "license": "MIT", "dependencies": { "node-fetch": "^2.6.7" diff --git a/package.json b/package.json index 0f30ebbd..100edcf9 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Front Matter", "description": "Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice like: Hugo, Jekyll, Hexo, NextJs, Gatsby, and many more...", "icon": "assets/frontmatter-teal-128x128.png", - "version": "8.0.1", + "version": "8.1.0", "preview": false, "publisher": "eliostruyf", "galleryBanner": { From 83d4427c0937f2c61c58b3f44dadf0171c15a451 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 7 Sep 2022 14:50:21 +0200 Subject: [PATCH 37/58] New titles for inputs --- src/commands/Content.ts | 1 + src/commands/Folders.ts | 6 ++++-- src/commands/Settings.ts | 5 +++-- src/commands/Template.ts | 5 ++++- src/commands/Wysiwyg.ts | 6 ++++-- src/helpers/ContentType.ts | 12 ++++++------ src/helpers/Questions.ts | 11 +++++++++-- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/commands/Content.ts b/src/commands/Content.ts index c3d982fe..1c048e93 100644 --- a/src/commands/Content.ts +++ b/src/commands/Content.ts @@ -20,6 +20,7 @@ export class Content { } as QuickPickItem]; const selectedOption = await window.showQuickPick(options, { + title: "Create content", placeHolder: `Select how you want to create your new content`, canPickMany: false, ignoreFocusOut: true diff --git a/src/commands/Folders.ts b/src/commands/Folders.ts index 5e9ccc04..b8678ef7 100644 --- a/src/commands/Folders.ts +++ b/src/commands/Folders.ts @@ -42,6 +42,7 @@ export class Folders { } const folderName = await window.showInputBox({ + title: `Add media folder`, prompt: `Which name would you like to give to your folder (use "/" to create multi-level folders)?`, value: startPath, ignoreFocusOut: true, @@ -96,7 +97,7 @@ export class Folders { /** * Register the new folder path - * @param folder + * @param folderInfo */ public static async register(folderInfo: { title: string, path: Uri } | Uri) { let folderName = folderInfo instanceof Uri ? undefined : folderInfo.title; @@ -115,7 +116,8 @@ export class Folders { } if (!folderName) { - folderName = await window.showInputBox({ + folderName = await window.showInputBox({ + title: `Register folder`, prompt: `Which name would you like to specify for this folder?`, placeHolder: `Folder name`, value: basename(folder.fsPath), diff --git a/src/commands/Settings.ts b/src/commands/Settings.ts index 89e93ac2..0c1438c2 100644 --- a/src/commands/Settings.ts +++ b/src/commands/Settings.ts @@ -14,7 +14,7 @@ export class Settings { * @param type */ public static async create(type: TaxonomyType) { - const newOption = await vscode.window.showInputBox({ + const newOption = await vscode.window.showInputBox({ prompt: `Insert the value of the ${type === TaxonomyType.Tag ? "tag" : "category"} that you want to add to your configuration.`, placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}`, ignoreFocusOut: true @@ -151,7 +151,8 @@ export class Settings { const taxType = await vscode.window.showQuickPick([ "Tag", "Category" - ], { + ], { + title: `Remap`, placeHolder: `What do you want to remap?`, canPickMany: false, ignoreFocusOut: true diff --git a/src/commands/Template.ts b/src/commands/Template.ts index e7428849..a43c56b0 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -62,7 +62,8 @@ export class Template { const article = ArticleHelper.getFrontMatter(editor); const clonedArticle = Object.assign({}, article); - const titleValue = await vscode.window.showInputBox({ + const titleValue = await vscode.window.showInputBox({ + title: `Template title`, prompt: `What name would you like to give your template?`, placeHolder: `article`, ignoreFocusOut: true @@ -76,6 +77,7 @@ export class Template { const keepContents = await vscode.window.showQuickPick( ["yes", "no"], { + title: `Keep contents`, canPickMany: false, placeHolder: `Do you want to keep the contents for the template?`, ignoreFocusOut: true @@ -132,6 +134,7 @@ export class Template { } const selectedTemplate = await vscode.window.showQuickPick(templates.map(t => path.basename(t.fsPath)), { + title: `Select a template`, placeHolder: `Select the content template to use`, ignoreFocusOut: true }); diff --git a/src/commands/Wysiwyg.ts b/src/commands/Wysiwyg.ts index a20de1cd..3792ca95 100644 --- a/src/commands/Wysiwyg.ts +++ b/src/commands/Wysiwyg.ts @@ -57,7 +57,8 @@ export class Wysiwyg { { label: "$(quote) Blockquote", detail: "Add a blockquote", alwaysShow: true }, ] - const option = await window.showQuickPick([ ...qpItems ], { + const option = await window.showQuickPick([ ...qpItems ], { + title: "WYSIWYG Options", placeHolder: "Which type of markup would you like to insert?", canPickMany: false, ignoreFocusOut: true @@ -159,7 +160,8 @@ export class Wysiwyg { "Heading 4", "Heading 5", "Heading 6" - ], { + ], { + title: "Heading Level", canPickMany: false, placeHolder: "Which heading level do you want to insert?", ignoreFocusOut: true diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 3a54d6fb..2911b8a6 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -116,9 +116,9 @@ export class ContentType { } const override = await window.showQuickPick(["Yes", "No"], { + title: "Override default content type", placeHolder: "Do you want to override the default content type?", - ignoreFocusOut: true, - title: "Override default content type" + ignoreFocusOut: true }); const overrideBool = override === "Yes"; @@ -127,10 +127,10 @@ export class ContentType { // Ask for the new content type name if (!overrideBool) { contentTypeName = await window.showInputBox({ - ignoreFocusOut: true, + title: "Generate Content Type", placeHolder: "Enter the name of the content type to generate", prompt: "Enter the name of the content type to generate", - title: "Generate Content Type", + ignoreFocusOut: true, validateInput: (value: string) => { if (!value) { return "Please enter a name for the content type"; @@ -156,9 +156,9 @@ export class ContentType { const fileName = filePath ? basename(filePath) : undefined; if (fileName?.startsWith(`index.`)) { const pageBundleAnswer = await window.showQuickPick(["Yes", "No"], { + title: "Use as page bundle", placeHolder: "Do you want to use this content type as a page bundle?", - ignoreFocusOut: true, - title: "Use as page bundle" + ignoreFocusOut: true }); pageBundle = pageBundleAnswer === "Yes"; } diff --git a/src/helpers/Questions.ts b/src/helpers/Questions.ts index a7283670..e936fd94 100644 --- a/src/helpers/Questions.ts +++ b/src/helpers/Questions.ts @@ -11,7 +11,11 @@ export class Questions { * @returns */ public static async yesOrNo(placeholder: string) { - const answer = await window.showQuickPick(["yes", "no"], { canPickMany: false, placeHolder: placeholder, ignoreFocusOut: true }); + const answer = await window.showQuickPick(["yes", "no"], { + placeHolder: placeholder, + canPickMany: false, + ignoreFocusOut: true + }); return answer === "yes"; } @@ -21,7 +25,8 @@ export class Questions { * @returns */ public static async ContentTitle(showWarning: boolean = true): Promise { - const title = await window.showInputBox({ + const title = await window.showInputBox({ + title: "Title", prompt: `What would you like to use as a title for the content to create?`, placeHolder: `Content title`, ignoreFocusOut: true @@ -46,6 +51,7 @@ export class Questions { let selectedFolder: string | undefined; if (folders.length > 1) { selectedFolder = await window.showQuickPick(folders.map(f => f.title), { + title: `Select a folder`, placeHolder: `Select where you want to create your content`, ignoreFocusOut: true }); @@ -82,6 +88,7 @@ export class Questions { })); const selectedOption = await window.showQuickPick(options, { + title: `Content type`, placeHolder: `Select the content type to create your new content`, canPickMany: false, ignoreFocusOut: true From 4d05c660c83a37544480fe30cee185340f025dae Mon Sep 17 00:00:00 2001 From: Elio Date: Thu, 8 Sep 2022 10:00:38 +0200 Subject: [PATCH 38/58] #398: Fix Windows folder path parsing in data folder retrieval --- CHANGELOG.md | 1 + src/commands/Folders.ts | 4 ++-- src/helpers/DashboardSettings.ts | 11 ++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cdc67e7..2fe24301 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ - [#384](https://github.com/estruyf/vscode-front-matter/issues/384): Fix issue `title` field in sub-fields - [#393](https://github.com/estruyf/vscode-front-matter/issues/393): Fix Windows file path for retrieving the preview path - [#396](https://github.com/estruyf/vscode-front-matter/issues/396): Fix for `index` and `_index` page previews +- [#398](https://github.com/estruyf/vscode-front-matter/issues/398): Fix Windows folder path parsing in data folder retrieval ## [8.0.1] - 2022-07-13 diff --git a/src/commands/Folders.ts b/src/commands/Folders.ts index b8678ef7..c12977fd 100644 --- a/src/commands/Folders.ts +++ b/src/commands/Folders.ts @@ -368,7 +368,7 @@ export class Folders { const isWindows = process.platform === 'win32'; let absPath = filePath.replace(WORKSPACE_PLACEHOLDER, parseWinPath(wsFolder?.fsPath || "")); absPath = isWindows ? absPath.split('/').join('\\') : absPath; - return absPath; + return parseWinPath(absPath); } /** @@ -381,7 +381,7 @@ export class Folders { const isWindows = process.platform === 'win32'; let absPath = folder.path.replace(WORKSPACE_PLACEHOLDER, parseWinPath(wsFolder?.fsPath || "")); absPath = isWindows ? absPath.split('/').join('\\') : absPath; - return absPath; + return parseWinPath(absPath); } /** diff --git a/src/helpers/DashboardSettings.ts b/src/helpers/DashboardSettings.ts index bf1aacc2..4afbcfc6 100644 --- a/src/helpers/DashboardSettings.ts +++ b/src/helpers/DashboardSettings.ts @@ -12,6 +12,7 @@ import { DataType } from "../models/DataType"; import { Extension } from "./Extension"; import { FrameworkDetector } from "./FrameworkDetector"; import { Settings } from "./SettingsHelper"; +import { parseWinPath } from './parseWinPath'; export class DashboardSettings { @@ -76,7 +77,7 @@ export class DashboardSettings { * @returns */ private static async getDataFiles(): Promise { - const wsPath = Folders.getWorkspaceFolder()?.fsPath; + const wsPath = parseWinPath(Folders.getWorkspaceFolder()?.fsPath); const files = Settings.get(SETTING_DATA_FILES); const folders = Settings.get(SETTING_DATA_FOLDERS); @@ -92,14 +93,14 @@ export class DashboardSettings { continue; } - let dataFolderPath = join(folderPath.replace((wsPath || ''), '')); + let dataFolderPath = parseWinPath(join(folderPath.replace((wsPath || ''), ''))); if (dataFolderPath.startsWith('/')) { dataFolderPath = dataFolderPath.substring(1); } - const dataJsonFiles = await workspace.findFiles(join(dataFolderPath, '*.json')); - const dataYmlFiles = await workspace.findFiles(join(dataFolderPath, '*.yml')); - const dataYamlFiles = await workspace.findFiles(join(dataFolderPath, '*.yaml')); + const dataJsonFiles = await workspace.findFiles(parseWinPath(join(dataFolderPath, '*.json'))); + const dataYmlFiles = await workspace.findFiles(parseWinPath(join(dataFolderPath, '*.yml'))); + const dataYamlFiles = await workspace.findFiles(parseWinPath(join(dataFolderPath, '*.yaml'))); const dataFiles = [...dataJsonFiles, ...dataYmlFiles, ...dataYamlFiles]; for (let dataFile of dataFiles) { From 23c5a7bc18ba2f97aeb8aae5f1f26f728975d644 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 8 Sep 2022 10:44:07 +0200 Subject: [PATCH 39/58] #400: Fix for draft/published grouping --- CHANGELOG.md | 1 + src/dashboardWebView/components/Contents/Overview.tsx | 11 ++++++++++- src/helpers/ContentType.ts | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fe24301..fafe24c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - [#393](https://github.com/estruyf/vscode-front-matter/issues/393): Fix Windows file path for retrieving the preview path - [#396](https://github.com/estruyf/vscode-front-matter/issues/396): Fix for `index` and `_index` page previews - [#398](https://github.com/estruyf/vscode-front-matter/issues/398): Fix Windows folder path parsing in data folder retrieval +- [#400](https://github.com/estruyf/vscode-front-matter/issues/400): Fix for draft/published content grouping ## [8.0.1] - 2022-07-13 diff --git a/src/dashboardWebView/components/Contents/Overview.tsx b/src/dashboardWebView/components/Contents/Overview.tsx index 3f84dd30..cb7637e6 100644 --- a/src/dashboardWebView/components/Contents/Overview.tsx +++ b/src/dashboardWebView/components/Contents/Overview.tsx @@ -1,6 +1,7 @@ import { Disclosure } from '@headlessui/react'; import {ChevronRightIcon} from '@heroicons/react/solid'; import * as React from 'react'; +import { useCallback } from 'react'; import { useRecoilValue } from 'recoil'; import { groupBy } from '../../../helpers/GroupBy'; import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon'; @@ -19,6 +20,14 @@ export interface IOverviewProps { export const Overview: React.FunctionComponent = ({pages, settings}: React.PropsWithChildren) => { const grouping = useRecoilValue(GroupingSelector); + const groupName = useCallback((groupId, groupedPages) => { + if (grouping === GroupOption.Draft) { + return `${groupId} (${groupedPages[groupId].length})`; + } + + return `${GroupOption[grouping]}: ${groupId} (${groupedPages[groupId].length})`; + }, [grouping]) + if (!pages || !pages.length) { return (
    @@ -58,7 +67,7 @@ export const Overview: React.FunctionComponent = ({pages, settin - {GroupOption[grouping]}: {groupId} ({groupedPages[groupId].length}) + { groupName(groupId, groupedPages) } diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 2911b8a6..4dffc537 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -48,7 +48,7 @@ export class ContentType { fieldValue = data[draftSetting.name]; } - if (draftSetting && fieldValue) { + if (draftSetting && fieldValue !== null) { if (draftSetting.type === "boolean") { return fieldValue ? "Draft" : "Published"; } else { From bf98ff9a1d12d74a4f7e6f725b35678d0f9bbb8f Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 8 Sep 2022 11:00:33 +0200 Subject: [PATCH 40/58] Disable popper --- src/dashboardWebView/components/ChoiceButton.tsx | 2 +- src/dashboardWebView/components/Header/Filter.tsx | 2 +- src/dashboardWebView/components/Header/Folders.tsx | 2 +- src/dashboardWebView/components/Header/Grouping.tsx | 2 +- src/dashboardWebView/components/Header/Sorting.tsx | 2 +- src/dashboardWebView/components/Menu/MenuItems.tsx | 5 +++-- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/dashboardWebView/components/ChoiceButton.tsx b/src/dashboardWebView/components/ChoiceButton.tsx index 7d8d6bb2..aa91543d 100644 --- a/src/dashboardWebView/components/ChoiceButton.tsx +++ b/src/dashboardWebView/components/ChoiceButton.tsx @@ -37,7 +37,7 @@ export const ChoiceButton: React.FunctionComponent = ({onCli