Implementation of the project selector

This commit is contained in:
Elio Struyf
2023-03-30 18:28:04 +02:00
parent 30df5c6233
commit 6bb9831542
15 changed files with 227 additions and 20 deletions
+23
View File
@@ -94,8 +94,31 @@
}]
},
"configuration": {
"$id": "#gobalconfiguration",
"title": "Front Matter: use frontmatter.json for shared team settings",
"type": "object",
"properties": {
"frontMatter.projects": {
"type": "array",
"markdownDescription": "Specify the list of projects to load in the Front Matter CMS. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.projects)",
"default": [],
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"markdownDescription": "Specify the name of the project."
},
"default": {
"type": "boolean",
"markdownDescription": "Specify if this project is the default project to load."
},
"configuration": {
"$ref": "#gobalconfiguration"
}
}
}
},
"frontMatter.sponsors.ai.enabled": {
"type": "boolean",
"default": false,
+4 -2
View File
@@ -20,13 +20,15 @@ export class Cache {
await Extension.getInstance().setState(key, data, type);
}
private static async clear() {
public static async clear(showNotification: boolean = true) {
const ext = Extension.getInstance();
await ext.setState(ExtensionState.Dashboard.Pages.Cache, undefined, 'workspace', true);
await ext.setState(ExtensionState.Dashboard.Pages.Index, undefined, 'workspace', true);
await ext.setState(ExtensionState.Settings.Extends, undefined, 'workspace', true);
Notifications.info('Cache cleared');
if (showNotification) {
Notifications.info('Cache cleared');
}
}
}
+4
View File
@@ -5,6 +5,10 @@ export const ExtensionState = {
SettingPromoted: `frontMatter:Settings:Promoted`,
MoveTemplatesFolder: `frontMatter:Templates:Move`,
Project: {
current: `frontMatter:Project:current`
},
Dashboard: {
Contents: {
Sorting: `frontMatter:Dashboard:Contents:Sorting`
+5
View File
@@ -99,6 +99,11 @@ export const SETTING_GIT_SUBMODULE_FOLDER = 'git.submodule.folder';
*/
export const SETTING_SPONSORS_AI_ENABLED = 'sponsors.ai.enabled';
/**
* Project override support
*/
export const SETTING_PROJECTS = 'projects';
/**
* @deprecated
*/
+3
View File
@@ -5,6 +5,9 @@ export enum DashboardMessage {
getMode = 'getMode',
showWarning = 'showWarning',
// Project switching
switchProject = 'switchProject',
// Welcome view
initializeProject = 'initializeProject',
setFramework = 'setFramework',
@@ -28,6 +28,7 @@ import { PaginationStatus } from './PaginationStatus';
import useThemeColors from '../../hooks/useThemeColors';
import { Startup } from './Startup';
import { Navigation } from './Navigation';
import { ProjectSwitcher } from './ProjectSwitcher';
export interface IHeaderProps {
header?: React.ReactNode;
@@ -146,12 +147,14 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({
`bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)]`
)
}`}>
<div className={`mb-0 border-b ${getColors(
<div className={`mb-0 border-b flex justify-between ${getColors(
`bg-gray-100 dark:bg-vulcan-500 border-gray-200 dark:border-vulcan-300`,
`bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)] border-[var(--vscode-editorWidget-border)]`
)
}`}>
<Tabs onNavigate={updateView} />
<ProjectSwitcher />
</div>
{location.pathname === routePaths.contents && (
@@ -0,0 +1,58 @@
import { messageHandler } from '@estruyf/vscode/dist/client';
import { Menu } from '@headlessui/react';
import { GlobeAltIcon } from '@heroicons/react/outline';
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import { DashboardMessage } from '../../DashboardMessage';
import { SettingsSelector } from '../../state';
import { MenuButton, MenuItem, MenuItems } from '../Menu';
export interface IProjectSwitcherProps { }
export const ProjectSwitcher: React.FunctionComponent<IProjectSwitcherProps> = (props: React.PropsWithChildren<IProjectSwitcherProps>) => {
const [crntProject, setCrntProject] = React.useState<string | undefined>(undefined);
const settings = useRecoilValue(SettingsSelector);
const project = settings?.project;
const projects = settings?.projects || [];
const setProject = (value: string) => {
setCrntProject(value);
messageHandler.send(DashboardMessage.switchProject, value)
}
React.useEffect(() => {
setCrntProject(project?.name);
}, [project]);
if (projects.length <= 1 || !crntProject) {
return null;
}
return (
<div className="flex items-center mr-4 z-[51]">
<Menu as="div" className="relative z-10 inline-block text-left">
<MenuButton
label={(
<div className="inline-flex items-center">
<GlobeAltIcon className="h-4 w-4 mr-2" />
<span>project</span>
</div>
)}
title={crntProject} />
<MenuItems disablePopper>
{projects.map((p) => (
<MenuItem
key={p.name}
title={p.name}
value={p.name}
isCurrent={p.name === crntProject}
onClick={(value) => setProject(p.name)}
/>
))}
</MenuItems>
</Menu>
</div>
);
};
@@ -15,28 +15,26 @@ export const MenuButton: React.FunctionComponent<IMenuButtonProps> = ({
disabled
}: React.PropsWithChildren<IMenuButtonProps>) => {
const { getColors } = useThemeColors();
return (
<div className={`groupinline-flex items-center ${disabled ? 'opacity-50' : ''}`}>
<span className={`mr-2 font-medium ${getColors('text-gray-500 dark:text-whisper-700', 'text-[var(--vscode-tab-inactiveForeground)]')}`}>{label}:</span>
<div className={`group inline-flex items-center ${disabled ? 'opacity-50' : ''}`}>
<div className={`mr-2 font-medium flex items-center ${getColors('text-gray-500 dark:text-whisper-700', 'text-[var(--vscode-tab-inactiveForeground)]')}`}>{label}:</div>
<Menu.Button
disabled={disabled}
className={`group inline-flex justify-center text-sm font-medium ${
getColors(
'text-vulcan-500 hover:text-vulcan-600 dark:text-whisper-500 dark:hover:text-whisper-600',
'text-[var(--vscode-list-activeSelectionForeground)] hover:text-[var(--vscode-list-highlightForeground)]'
)
}`}
className={`group inline-flex justify-center text-sm font-medium ${getColors(
'text-vulcan-500 hover:text-vulcan-600 dark:text-whisper-500 dark:hover:text-whisper-600',
'text-[var(--vscode-list-activeSelectionForeground)] hover:text-[var(--vscode-list-highlightForeground)]'
)
}`}
>
{title}
<ChevronDownIcon
className={`flex-shrink-0 -mr-1 ml-1 h-5 w-5 ${
getColors(
'text-gray-400 group-hover:text-gray-500 dark:text-whisper-600 dark:group-hover:text-whisper-700',
'text-[var(--vscode-list-activeSelectionForeground)] group-hover:text-[var(--vscode-list-highlightForeground)]'
)
}`}
className={`flex-shrink-0 -mr-1 ml-1 h-5 w-5 ${getColors(
'text-gray-400 group-hover:text-gray-500 dark:text-whisper-600 dark:group-hover:text-whisper-700',
'text-[var(--vscode-list-activeSelectionForeground)] group-hover:text-[var(--vscode-list-highlightForeground)]'
)
}`}
aria-hidden="true"
/>
</Menu.Button>
+3
View File
@@ -8,6 +8,7 @@ import {
DraftField,
Framework,
GitSettings,
Project,
Snippets,
SortingSetting
} from '../../models';
@@ -16,6 +17,8 @@ import { DashboardViewType } from '.';
import { DataFile } from '../../models/DataFile';
export interface Settings {
projects: Project[];
project: Project;
git: GitSettings;
beta: boolean;
initialized: boolean;
+2
View File
@@ -59,6 +59,8 @@ export class DashboardSettings {
const pagination = Settings.get<boolean | number>(SETTING_DASHBOARD_CONTENT_PAGINATION);
const settings = {
projects: Settings.getProjects(),
project: Settings.getProject(),
git: {
isGitRepo: gitActions ? await GitListener.isGitRepository() : false,
actions: gitActions || false
+71 -2
View File
@@ -1,10 +1,10 @@
import { SETTING_EXTENSIBILITY_SCRIPTS } from './../constants/settings';
import { SETTING_EXTENSIBILITY_SCRIPTS, SETTING_PROJECTS } from './../constants/settings';
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 { ContentType, CustomTaxonomy, Project, TaxonomyType } from '../models';
import {
SETTING_TAXONOMY_TAGS,
SETTING_TAXONOMY_CATEGORIES,
@@ -53,10 +53,32 @@ export class Settings {
private static listeners: any[] = [];
private static fileCreationWatcher: vscode.FileSystemWatcher | undefined;
private static readConfigPromise: Promise<void> | undefined = undefined;
private static project: Project | undefined = undefined;
public static async init() {
await Settings.readConfig();
const projects = Settings.getProjects();
const crntProject = await Extension.getInstance().getState<string | undefined>(
ExtensionState.Project.current,
'workspace'
);
if (projects.length > 0) {
// Get the default project
const defaultProject = projects.find((p) => {
if (crntProject) {
return p.name === crntProject;
}
return p.default;
});
if (defaultProject) {
Settings.project = defaultProject;
} else {
Settings.project = projects[0];
}
}
Settings.listeners = [];
if (!Settings.isInitialized) {
@@ -72,6 +94,39 @@ export class Settings {
});
}
/**
* Get the current project
* @returns
*/
public static getProject() {
return Settings.project;
}
/**
* Set the project
* @param value
*/
public static setProject(value: string) {
Extension.getInstance().setState(ExtensionState.Project.current, value, 'workspace');
Settings.project = Settings.getProjects().find((p) => p.name === value);
console.log('setProject', Settings.project);
}
/**
* Fetch all the projects
* @returns
*/
public static getProjects(): Project[] {
const settingKey = `${CONFIG_KEY}.${SETTING_PROJECTS}`;
let projects = [];
if (Settings.globalConfig && typeof Settings.globalConfig[settingKey] !== 'undefined') {
projects = Settings.globalConfig[settingKey];
}
return projects;
}
/**
* Check if the setting is present in the workspace and ask to promote them to the global settings
*/
@@ -195,6 +250,16 @@ export class Settings {
let setting = undefined;
const settingKey = `${CONFIG_KEY}.${name}`;
if (Settings.project) {
if (
typeof Settings.project.configuration !== 'undefined' &&
typeof Settings.project.configuration[settingKey] !== 'undefined'
) {
setting = Settings.project.configuration[settingKey];
return setting;
}
}
if (Settings.globalConfig && typeof Settings.globalConfig[settingKey] !== 'undefined') {
setting = Settings.globalConfig[settingKey];
}
@@ -699,6 +764,10 @@ export class Settings {
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_TAXONOMY_CUSTOM)) {
Settings.updateGlobalConfigArraySetting(SETTING_TAXONOMY_CUSTOM, 'id', configJson);
}
// Projects
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_PROJECTS)) {
Settings.updateGlobalConfigArraySetting(SETTING_PROJECTS, 'name', configJson);
}
// Snippets
else if (
Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_SNIPPETS) &&
+1
View File
@@ -176,6 +176,7 @@ export class PagesListener extends BaseListener {
this.sendMsg(DashboardCommand.searchReady, true);
await this.createSearchIndex(pages);
this.sendMsg(DashboardCommand.loading, false);
});
}
@@ -13,6 +13,13 @@ import { DashboardSettings, Settings } from '../../helpers';
import { FrameworkDetector } from '../../helpers/FrameworkDetector';
import { Framework, PostMessageData } from '../../models';
import { BaseListener } from './BaseListener';
import { Cache } from '../../commands/Cache';
import { Preview } from '../../commands';
import { GitListener } from '../general';
import { DataListener } from '../panel';
import { MarkdownFoldingProvider } from '../../providers/MarkdownFoldingProvider';
import { ModeSwitch } from '../../services/ModeSwitch';
import { PagesListener } from './PagesListener';
export class SettingsListener extends BaseListener {
/**
@@ -35,6 +42,29 @@ export class SettingsListener extends BaseListener {
case DashboardMessage.addFolder:
this.addFolder(msg?.payload);
break;
case DashboardMessage.switchProject:
this.switchProject(msg.payload);
break;
}
}
private static async switchProject(project: string) {
if (project) {
this.sendMsg(DashboardCommand.loading, true);
Settings.setProject(project);
await Cache.clear(false);
Preview.init();
GitListener.init();
SettingsListener.getSettings(true);
DataListener.getFoldersAndFiles();
MarkdownFoldingProvider.triggerHighlighting(true);
ModeSwitch.register();
// Update pages
PagesListener.startWatchers();
PagesListener.refresh();
}
}
+5
View File
@@ -0,0 +1,5 @@
export interface Project {
name: string;
default?: boolean;
configuration: any;
}
+1
View File
@@ -16,6 +16,7 @@ export * from './MediaPaths';
export * from './Mode';
export * from './PanelSettings';
export * from './PostMessageData';
export * from './Project';
export * from './Snippets';
export * from './SortOrder';
export * from './SortType';