#377: Git sync actions added on panel and content dashboard

This commit is contained in:
Elio Struyf
2022-07-29 16:13:46 +02:00
parent 07ed95793c
commit 30dc33a859
30 changed files with 443 additions and 49 deletions
+6
View File
@@ -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
+2 -1
View File
@@ -41,7 +41,8 @@
}
.collapsible__body,
.ext_settings {
.ext_settings,
.git_actions {
padding: 1rem 1.25rem;
box-sizing: border-box;
}
+57
View File
@@ -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",
+12 -1
View File
@@ -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"
}
}
}
+2 -1
View File
@@ -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);
});
}
+3
View File
@@ -3,8 +3,11 @@
export const GeneralCommands = {
toWebview: {
setMode: "setMode",
gitSyncingStart: "gitSyncingStart",
gitSyncingEnd: "gitSyncingEnd",
},
toVSCode: {
openLink: "openLink",
gitSync: "gitSync",
}
};
+3
View File
@@ -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
*/
@@ -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<IHeaderProps> = ({header, totalPage
<div className={`flex items-center justify-end space-x-4 flex-1`}>
<Startup settings={settings} />
<SyncButton />
<ChoiceButton
title={`Create content`}
@@ -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 { useRecoilValue } from 'recoil';
import { GeneralCommands } from '../../../constants';
import { SettingsSelector } from '../../state';
export interface ISyncButtonProps {}
export const SyncButton: React.FunctionComponent<ISyncButtonProps> = (props: React.PropsWithChildren<ISyncButtonProps>) => {
const settings = useRecoilValue(SettingsSelector);
const [ isSyncing, setIsSyncing ] = useState(false);
const pull = () => {
Messenger.send(GeneralCommands.toVSCode.gitSync);
};
const messageListener = (message: MessageEvent<EventData<any>>) => {
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 (
<div className='git_actions'>
<button
type="button"
className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 focus:outline-none disabled:bg-gray-500"
onClick={pull}
disabled={isSyncing}
>
<RefreshIcon className={`w-4 h-4 mr-2 ${isSyncing ? 'animate-reverse-spin' : ''}`} aria-hidden="true" />
<span>Sync</span>
</button>
</div>
);
};
+8 -2
View File
@@ -18,7 +18,7 @@ export default function useMessages() {
const [, setView] = useRecoilState(DashboardViewAtom);
const [, setSearchReady] = useRecoilState(SearchReadyAtom);
Messenger.listen((event: MessageEvent<EventData<any>>) => {
const messageListener = (event: MessageEvent<EventData<any>>) => {
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 {
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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(() => {
+1 -11
View File
@@ -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;
};
};
+7 -1
View File
@@ -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<boolean>(SETTING_GIT_ACTIONS);
return {
git: {
isGitRepo: gitActions ? await GitListener.isGitRepository() : false,
actions: gitActions || false
},
beta: ext.isBetaVersion(),
wsFolder: wsFolder ? wsFolder.fsPath : '',
staticFolder: Folders.getStaticFolderRelativePath(),
+9
View File
@@ -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;
};
};
+8 -1
View File
@@ -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<IPanelSettings> {
const gitActions = Settings.get<boolean>(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,
+34 -24
View File
@@ -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;
}
}
+1
View File
@@ -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';
+109
View File
@@ -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<string>(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 });
}
}
+1
View File
@@ -1 +1,2 @@
export * from './ModeListener';
export * from './GitListener';
+5
View File
@@ -0,0 +1,5 @@
export interface GitSettings {
isGitRepo: boolean;
actions: boolean;
}
+2 -1
View File
@@ -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[];
+1
View File
@@ -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';
+3
View File
@@ -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<IViewPanelProps> = (props: React
return (
<div className="frontmatter">
<div className={`ext_actions`}>
<GitAction settings={settings} />
<FeatureFlag features={mode?.features || []} flag={FEATURE_FLAG.panel.globalSettings}>
<GlobalSettings settings={settings} />
</FeatureFlag>
+4 -2
View File
@@ -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<HTMLButtonElement>) => void;
@@ -10,7 +10,9 @@ export interface IActionButtonProps {
const ActionButton: React.FunctionComponent<IActionButtonProps> = ({className, onClick, disabled,title}: React.PropsWithChildren<IActionButtonProps>) => {
return (
<div className={`article__action`}>
<button onClick={onClick} className={className || ""} disabled={disabled}>{title}</button>
<button onClick={onClick} className={className || ""} disabled={disabled}>
{title}
</button>
</div>
);
};
+3
View File
@@ -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<IBaseViewProps> = ({settings, folderAndF
return (
<div className="frontmatter">
<div className={`ext_actions`}>
<GitAction settings={settings} />
<FeatureFlag features={mode?.features || []} flag={FEATURE_FLAG.panel.globalSettings}>
<GlobalSettings settings={settings} isBase />
</FeatureFlag>
@@ -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<IGitActionProps> = ({ settings }: React.PropsWithChildren<IGitActionProps>) => {
const [ isSyncing, setIsSyncing ] = useState(false);
const pull = () => {
Messenger.send(GeneralCommands.toVSCode.gitSync);
};
const messageListener = (message: MessageEvent<EventData<any>>) => {
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 (
<div className='git_actions'>
<ActionButton
onClick={pull}
title={(
<div className='git_actions__sync'>
<RefreshIcon className={isSyncing ? 'animate-spin' : ''} />
<span>Sync</span>
</div>
)} />
</div>
);
};
+8 -2
View File
@@ -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<any>({});
@@ -17,7 +18,7 @@ export default function useMessages() {
const [mediaSelecting, setMediaSelecting] = useState<DashboardData | undefined>(undefined);
const [mode, setMode] = useState<Mode | undefined>(undefined);
window.addEventListener('message', event => {
const messageListener = (event: MessageEvent<EventData<any>>) => {
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 {
+27
View File
@@ -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 {
+10
View File
@@ -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,