From c6ec07fa1747941945cf112e072784fbbcb9fb01 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 7 Sep 2023 16:25:52 +0200 Subject: [PATCH] #654 - Add the open on website action --- l10n/bundle.l10n.de.json | 3 +- l10n/bundle.l10n.fr.json | 3 +- l10n/bundle.l10n.it.json | 3 +- l10n/bundle.l10n.ja.json | 3 +- l10n/bundle.l10n.json | 1 + package.json | 4 ++ package.nls.de.json | 3 +- package.nls.ja.json | 3 +- package.nls.json | 3 +- src/commands/Preview.ts | 2 +- src/constants/GeneralCommands.ts | 3 +- src/constants/settings.ts | 2 + .../components/Contents/ContentActions.tsx | 42 ++++++++++++++++-- src/dashboardWebView/models/Settings.ts | 1 + src/helpers/DashboardSettings.ts | 6 ++- src/helpers/PanelSettings.ts | 5 ++- src/listeners/general/BaseListener.ts | 43 ++++++++++++++++++- src/localization/localization.enum.ts | 4 ++ src/models/PanelSettings.ts | 1 + src/panelWebView/components/Actions.tsx | 3 ++ .../Actions/OpenOnWebsiteAction.tsx | 33 ++++++++++++++ src/panelWebView/components/Actions/index.ts | 1 + 22 files changed, 154 insertions(+), 18 deletions(-) create mode 100644 src/panelWebView/components/Actions/OpenOnWebsiteAction.tsx create mode 100644 src/panelWebView/components/Actions/index.ts diff --git a/l10n/bundle.l10n.de.json b/l10n/bundle.l10n.de.json index f4ab5bc5..926f68bd 100644 --- a/l10n/bundle.l10n.de.json +++ b/l10n/bundle.l10n.de.json @@ -335,5 +335,6 @@ "dashboard.steps.stepsToGetStarted.assetsFolder.other.description": "Wenn Sie einen anderen Ordner konfigurieren möchten, können Sie dies manuell in der frontmatter.json-Datei tun.", "dashboard.steps.stepsToGetStarted.template.name": "Verwende eine Konfigurationsvorlage", "dashboard.steps.stepsToGetStarted.template.description": "Wählen Sie eine Vorlage aus, um die Datei frontmatter.json mit den empfohlenen Einstellungen vorzufüllen.", - "listeners.dashboard.settingsListener.triggerTemplate.notification": "Vorlagendateien kopiert." + "listeners.dashboard.settingsListener.triggerTemplate.notification": "Vorlagendateien kopiert.", + "common.openOnWebsite": "Auf der Website öffnen" } \ No newline at end of file diff --git a/l10n/bundle.l10n.fr.json b/l10n/bundle.l10n.fr.json index c502b183..bbb1e570 100644 --- a/l10n/bundle.l10n.fr.json +++ b/l10n/bundle.l10n.fr.json @@ -335,5 +335,6 @@ "panel.viewPanel.mediaInsert": "Continuer dans le tableau de bord des médias pour sélectionner l'image que vous voulez insérer.", "dashboard.steps.stepsToGetStarted.template.name": "Utiliser un modèle de configuration", "dashboard.steps.stepsToGetStarted.template.description": "Sélectionnez un modèle pour préremplir le fichier frontmatter.json avec les paramètres recommandés.", - "listeners.dashboard.settingsListener.triggerTemplate.notification": "Fichiers de modèle copiés." + "listeners.dashboard.settingsListener.triggerTemplate.notification": "Fichiers de modèle copiés.", + "common.openOnWebsite": "Ouvrir sur le site web" } \ No newline at end of file diff --git a/l10n/bundle.l10n.it.json b/l10n/bundle.l10n.it.json index c86a4b86..b35eba59 100644 --- a/l10n/bundle.l10n.it.json +++ b/l10n/bundle.l10n.it.json @@ -335,5 +335,6 @@ "panel.viewPanel.mediaInsert": "Continuare nella dashboard multimediale per selezionare l'immagine che si desidera inserire.", "dashboard.steps.stepsToGetStarted.template.name": "Usa un modello di configurazione", "dashboard.steps.stepsToGetStarted.template.description": "Seleziona un modello per riempire in anticipo il file frontmatter.json con le impostazioni consigliate.", - "listeners.dashboard.settingsListener.triggerTemplate.notification": "File del modello copiati." + "listeners.dashboard.settingsListener.triggerTemplate.notification": "File del modello copiati.", + "common.openOnWebsite": "Apri sul sito web" } \ No newline at end of file diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json index 9980d552..d9d1fc21 100644 --- a/l10n/bundle.l10n.ja.json +++ b/l10n/bundle.l10n.ja.json @@ -335,5 +335,6 @@ "dashboard.steps.stepsToGetStarted.assetsFolder.other.description": "別のフォルダを設定する場合は、frontmatter.jsonファイルで手動で行うことができます。", "dashboard.steps.stepsToGetStarted.template.name": "設定テンプレートを使用する", "dashboard.steps.stepsToGetStarted.template.description": "おすすめの設定でfrontmatter.jsonファイルを事前に埋めるテンプレートを選択します。", - "listeners.dashboard.settingsListener.triggerTemplate.notification": "テンプレートファイルがコピーされました。" + "listeners.dashboard.settingsListener.triggerTemplate.notification": "テンプレートファイルがコピーされました。", + "common.openOnWebsite": "ウェブサイトで開く" } \ No newline at end of file diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index 91813a03..e620f74b 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -21,6 +21,7 @@ "common.support": "Support", "common.remove.value": "Remove {0}", "common.error.message": "Sorry, something went wrong.", + "common.openOnWebsite": "Open on website", "developer.title": "Developer mode", "developer.reload.title": "Reload the dashboard", diff --git a/package.json b/package.json index efede6e8..862b993c 100644 --- a/package.json +++ b/package.json @@ -1753,6 +1753,10 @@ "default": "yyyy-MM-dd", "markdownDescription": "%setting.frontMatter.templates.prefix.markdownDescription%", "scope": "Templates" + }, + "frontMatter.website.host": { + "type": "string", + "markdownDescription": "%setting.frontMatter.website.host.markdownDescription%" } } }, diff --git a/package.nls.de.json b/package.nls.de.json index 30ff6592..97d31bde 100644 --- a/package.nls.de.json +++ b/package.nls.de.json @@ -240,5 +240,6 @@ "setting.frontMatter.taxonomy.dateField.deprecationMessage": "Diese Einstellung ist veraltet und wird in der nächsten Hauptversion entfernt. Bitte verwenden Sie stattdessen die neuen `isPublishDate`-Einstellungen in den Datumsfeldern Ihrer Content-Typen.", "setting.frontMatter.taxonomy.modifiedField.deprecationMessage": "Diese Einstellung ist veraltet und wird in der nächsten Hauptversion entfernt. Bitte verwenden Sie stattdessen die neuen `isModifiedDate`-Einstellungen in den Datumsfeldern Ihrer Content-Typen.", "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.customType.description": "🚧: Specify the name of the custom field type to use.", - "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "🚧: Specify if the empty values should be cleared." + "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "🚧: Specify if the empty values should be cleared.", + "setting.frontMatter.website.host.markdownDescription": "🚧: Specify the host URL of your website. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.website.url)" } \ No newline at end of file diff --git a/package.nls.ja.json b/package.nls.ja.json index 749c9bc5..6f43b1df 100644 --- a/package.nls.ja.json +++ b/package.nls.ja.json @@ -241,5 +241,6 @@ "setting.frontMatter.taxonomy.modifiedField.deprecationMessage": "🚧: This setting is deprecated and will be removed in the next major version. Please use the new `isModifiedDate` settings instead in your content types date fields.", "setting.frontMatter.global.disabledNotifications.markdownDescription": "🚧: This is an array with the notifications types that can be disabled for Front Matter CMS. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.global.disablednotifications)", "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.customType.description": "🚧: Specify the name of the custom field type to use.", - "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "🚧: Specify if the empty values should be cleared." + "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "🚧: Specify if the empty values should be cleared.", + "setting.frontMatter.website.host.markdownDescription": "🚧: Specify the host URL of your website. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.website.url)" } \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index a972a490..2a958382 100644 --- a/package.nls.json +++ b/package.nls.json @@ -240,5 +240,6 @@ "setting.frontMatter.taxonomy.dateField.deprecationMessage": "This setting is deprecated and will be removed in the next major version. Please use the new `isPublishDate` settings instead in your content types date fields.", "setting.frontMatter.taxonomy.modifiedField.deprecationMessage": "This setting is deprecated and will be removed in the next major version. Please use the new `isModifiedDate` settings instead in your content types date fields.", "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.customType.description": "Specify the name of the custom field type to use.", - "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "Specify if the empty values should be cleared." + "setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "Specify if the empty values should be cleared.", + "setting.frontMatter.website.host.markdownDescription": "Specify the host URL of your website. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.website.url)" } \ No newline at end of file diff --git a/src/commands/Preview.ts b/src/commands/Preview.ts index 1016e46f..89b3454e 100644 --- a/src/commands/Preview.ts +++ b/src/commands/Preview.ts @@ -221,7 +221,7 @@ export class Preview { * @param filePath * @returns */ - private static async getContentSlug( + public static async getContentSlug( article: ParsedFrontMatter | null, filePath?: string ): Promise { diff --git a/src/constants/GeneralCommands.ts b/src/constants/GeneralCommands.ts index af8e0256..ccb77129 100644 --- a/src/constants/GeneralCommands.ts +++ b/src/constants/GeneralCommands.ts @@ -8,6 +8,7 @@ export const GeneralCommands = { toVSCode: { openLink: 'openLink', gitSync: 'gitSync', - getLocalization: 'getLocalization' + getLocalization: 'getLocalization', + openOnWebsite: 'openOnWebsite' } }; diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 29b1efc2..fecbae26 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -103,6 +103,8 @@ export const SETTING_GIT_SUBMODULE_FOLDER = 'git.submodule.folder'; export const SETTING_SNIPPETS_WRAPPER = 'snippets.wrapper.enabled'; +export const SETTING_WEBSITE_URL = 'website.host'; + /** * Sponsors only settings */ diff --git a/src/dashboardWebView/components/Contents/ContentActions.tsx b/src/dashboardWebView/components/Contents/ContentActions.tsx index d6daa6a7..0cc59cd0 100644 --- a/src/dashboardWebView/components/Contents/ContentActions.tsx +++ b/src/dashboardWebView/components/Contents/ContentActions.tsx @@ -1,6 +1,6 @@ import { Messenger } from '@estruyf/vscode/dist/client'; import { Menu } from '@headlessui/react'; -import { EyeIcon, TerminalIcon, TrashIcon } from '@heroicons/react/outline'; +import { EyeIcon, GlobeIcon, TerminalIcon, TrashIcon } from '@heroicons/react/outline'; import * as React from 'react'; import { CustomScript, ScriptType } from '../../../models'; import { DashboardMessage } from '../../DashboardMessage'; @@ -11,6 +11,9 @@ import { useState } from 'react'; import useThemeColors from '../../hooks/useThemeColors'; import * as l10n from '@vscode/l10n'; import { LocalizationKey } from '../../../localization'; +import { useRecoilValue } from 'recoil'; +import { SettingsSelector } from '../../state'; +import { GeneralCommands } from '../../../constants'; export interface IContentActionsProps { title: string; @@ -29,6 +32,7 @@ export const ContentActions: React.FunctionComponent = ({ }: React.PropsWithChildren) => { const [showDeletionAlert, setShowDeletionAlert] = React.useState(false); const { getColors } = useThemeColors(); + const settings = useRecoilValue(SettingsSelector); const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); @@ -54,6 +58,16 @@ export const ContentActions: React.FunctionComponent = ({ setShowDeletionAlert(false); }; + const openOnWebsite = React.useCallback((e: React.MouseEvent) => { + e.stopPropagation(); + if (settings?.websiteUrl && path) { + Messenger.send(GeneralCommands.toVSCode.openOnWebsite, { + websiteUrl: settings.websiteUrl, + filePath: path + }); + } + }, [settings?.websiteUrl, path]); + const runCustomScript = React.useCallback( (e: React.MouseEvent, script: CustomScript) => { e.stopPropagation(); @@ -101,11 +115,19 @@ export const ContentActions: React.FunctionComponent = ({ {!listView && (
- + - + { + settings?.websiteUrl && ( + + + ) + } + +
@@ -136,6 +158,20 @@ export const ContentActions: React.FunctionComponent = ({ onClick={(_, e) => onView(e)} /> + { + settings?.websiteUrl && ( + + {' '} + {l10n.t(LocalizationKey.commonOpenOnWebsite)} + + } + onClick={(_, e) => openOnWebsite(e)} + /> + ) + } + {customScriptActions} (SETTING_DATA_TYPES), snippets: Settings.get(SETTING_CONTENT_SNIPPETS), snippetsWrapper: Settings.get(SETTING_SNIPPETS_WRAPPER), - isBacker: await ext.getState(CONTEXT.backer, 'global') + isBacker: await ext.getState(CONTEXT.backer, 'global'), + websiteUrl: Settings.get(SETTING_WEBSITE_URL) } as ISettings; return settings; diff --git a/src/helpers/PanelSettings.ts b/src/helpers/PanelSettings.ts index dd36ed14..f60c634f 100644 --- a/src/helpers/PanelSettings.ts +++ b/src/helpers/PanelSettings.ts @@ -1,4 +1,4 @@ -import { SETTING_SPONSORS_AI_ENABLED } from './../constants/settings'; +import { SETTING_SPONSORS_AI_ENABLED, SETTING_WEBSITE_URL } from './../constants/settings'; import { workspace } from 'vscode'; import { Extension, Settings, TaxonomyHelper } from '.'; import { Dashboard } from '../commands/Dashboard'; @@ -96,7 +96,8 @@ export class PanelSettings { }, dataTypes: Settings.get(SETTING_DATA_TYPES), fieldGroups: Settings.get(SETTING_TAXONOMY_FIELD_GROUPS), - contentFolders: Folders.get() + contentFolders: Folders.get(), + websiteUrl: Settings.get(SETTING_WEBSITE_URL) || '' }; } diff --git a/src/listeners/general/BaseListener.ts b/src/listeners/general/BaseListener.ts index b459e23b..a2564fd5 100644 --- a/src/listeners/general/BaseListener.ts +++ b/src/listeners/general/BaseListener.ts @@ -1,10 +1,12 @@ import { GeneralCommands } from './../../constants/GeneralCommands'; import { Dashboard } from '../../commands/Dashboard'; import { PanelProvider } from '../../panelWebView/PanelProvider'; -import { Extension } from '../../helpers'; +import { ArticleHelper, Extension } from '../../helpers'; import { Logger } from '../../helpers/Logger'; -import { commands, Uri } from 'vscode'; +import { commands, Uri, window } from 'vscode'; import { PostMessageData } from '../../models'; +import { Preview } from '../../commands'; +import { urlJoin } from 'url-join-ts'; export abstract class BaseListener { public static process(msg: PostMessageData) { @@ -14,6 +16,9 @@ export abstract class BaseListener { commands.executeCommand('vscode.open', Uri.parse(msg.payload)); } break; + case GeneralCommands.toVSCode.openOnWebsite: + this.openOnWebsite(msg.payload); + break; } } @@ -32,4 +37,38 @@ export abstract class BaseListener { Dashboard.postWebviewMessage({ command: command as any, payload }); } + + /** + * Open the page on the website + * @param param0 + * @returns + */ + private static async openOnWebsite({ + websiteUrl, + filePath + }: { + websiteUrl: string; + filePath?: string; + }) { + if (websiteUrl) { + const article = filePath + ? await ArticleHelper.getFrontMatterByPath(filePath) + : ArticleHelper.getCurrent(); + if (article) { + if (!filePath) { + const editor = window.activeTextEditor; + if (!editor) { + return; + } + + filePath = editor.document.uri.fsPath; + } + + const slug = await Preview.getContentSlug(article, filePath); + + const fullUrl = urlJoin(websiteUrl, slug); + commands.executeCommand('vscode.open', fullUrl); + } + } + } } diff --git a/src/localization/localization.enum.ts b/src/localization/localization.enum.ts index a47f1b12..7699122d 100644 --- a/src/localization/localization.enum.ts +++ b/src/localization/localization.enum.ts @@ -87,6 +87,10 @@ export enum LocalizationKey { * Sorry, something went wrong. */ commonErrorMessage = 'common.error.message', + /** + * Open on website + */ + commonOpenOnWebsite = 'common.openOnWebsite', /** * Developer mode */ diff --git a/src/models/PanelSettings.ts b/src/models/PanelSettings.ts index 16939371..c0a084a8 100644 --- a/src/models/PanelSettings.ts +++ b/src/models/PanelSettings.ts @@ -30,6 +30,7 @@ export interface PanelSettings { commaSeparatedFields: string[]; aiEnabled: boolean; contentFolders: ContentFolder[]; + websiteUrl: string; } export interface FieldGroup { diff --git a/src/panelWebView/components/Actions.tsx b/src/panelWebView/components/Actions.tsx index e6422e8b..09a1fd90 100644 --- a/src/panelWebView/components/Actions.tsx +++ b/src/panelWebView/components/Actions.tsx @@ -7,6 +7,7 @@ import { SlugAction } from './SlugAction'; import { StartServerButton } from './StartServerButton'; import * as l10n from '@vscode/l10n'; import { LocalizationKey } from '../../localization'; +import { OpenOnWebsiteAction } from './Actions/OpenOnWebsiteAction'; export interface IActionsProps { metadata: any; @@ -28,6 +29,8 @@ const Actions: React.FunctionComponent = ({ {settings?.preview?.host && } + + {settings && settings.scripts && settings.scripts.length > 0 && ( diff --git a/src/panelWebView/components/Actions/OpenOnWebsiteAction.tsx b/src/panelWebView/components/Actions/OpenOnWebsiteAction.tsx new file mode 100644 index 00000000..1d3dc3a0 --- /dev/null +++ b/src/panelWebView/components/Actions/OpenOnWebsiteAction.tsx @@ -0,0 +1,33 @@ +import { messageHandler } from '@estruyf/vscode/dist/client'; +import * as React from 'react'; +import { ActionButton } from '../ActionButton'; +import * as l10n from "@vscode/l10n" +import { LocalizationKey } from '../../../localization'; +import { GeneralCommands } from '../../../constants'; + +export interface IOpenOnWebsiteActionProps { + baseUrl: string; + slug: string; +} + +export const OpenOnWebsiteAction: React.FunctionComponent = ({ + baseUrl, + slug +}: React.PropsWithChildren) => { + + const open = () => { + messageHandler.send(GeneralCommands.toVSCode.openOnWebsite, { + websiteUrl: baseUrl, + }); + }; + + if (!baseUrl || !slug) { + return null; + } + + return ( + + ); +}; \ No newline at end of file diff --git a/src/panelWebView/components/Actions/index.ts b/src/panelWebView/components/Actions/index.ts new file mode 100644 index 00000000..a80af302 --- /dev/null +++ b/src/panelWebView/components/Actions/index.ts @@ -0,0 +1 @@ +export * from './OpenOnWebsiteAction';