Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dev): refactor settings #100

Merged
merged 8 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module.exports = {
moduleFileExtensions: ["ts", "js", "json", "node"],
moduleNameMapper: {
"^@templates/(.*)$": "<rootDir>/src/$1",
"^api$": "<rootDir>/tests/mock-joplin-api.ts"
"^api$": "<rootDir>/tests/mock-joplin-api.ts",
"^api/types$": "<rootDir>/api/types.ts"
},
globalSetup: "./tests/jest-setup.js",
collectCoverageFrom: ["src/**/*.{js,ts}"]
Expand Down
3 changes: 2 additions & 1 deletion src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import joplin from "api";
import { NewNote } from "./parser";
import { getSelectedFolder } from "./utils/folders";
import { applyTagToNote, getAnyTagWithTitle } from "./utils/tags";
import { ApplyTagsWhileInsertingSetting } from "./settings";

export enum TemplateAction {
NewNote = "newNote",
Expand All @@ -12,7 +13,7 @@ export enum TemplateAction {
const performInsertTextAction = async (template: NewNote) => {
await joplin.commands.execute("insertText", template.body);

const applyTags = await joplin.settings.value("applyTagsWhileInserting")
const applyTags = await ApplyTagsWhileInsertingSetting.get()
if (applyTags) {
const noteId = (await joplin.workspace.selectedNote()).id;
for (const tag of template.tags) {
Expand Down
83 changes: 20 additions & 63 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,36 @@
import joplin from "api";
import { MenuItemLocation, SettingItemType } from "api/types";
import { MenuItemLocation } from "api/types";
import { Parser } from "./parser";
import { DateAndTimeUtils } from "./utils/dateAndTime";
import { getFolderFromId, getSelectedFolder, getUserFolderSelection, Folder } from "./utils/folders";
import { clearDefaultTemplates, getNotebookDefaultTemplatesConfig, getUserDefaultTemplateTypeSelection, setDefaultTemplate, DefaultTemplatesConfigSetting } from "./utils/defaultTemplates";
import { getUserDefaultTemplateTypeSelection, setDefaultTemplate } from "./utils/defaultTemplates";
import { getTemplateFromId, getUserTemplateSelection, Note } from "./utils/templates";
import { setDefaultTemplatesView, DefaultTemplatesDisplayData, NotebookDefaultTemplatesDisplayData } from "./views/defaultTemplates";
import { TemplateAction, performAction } from "./actions";
import { loadLegacyTemplates } from "./legacyTemplates";
import * as open from "open";
import { Logger } from "./logger";
import { PromiseGroup } from "./utils/promises";
import { PluginSettingsRegistry, DefaultNoteTemplateIdSetting, DefaultTodoTemplateIdSetting, DefaultTemplatesConfigSetting } from "./settings";
import { LocaleGlobalSetting, DateFormatGlobalSetting, TimeFormatGlobalSetting, ProfileDirGlobalSetting } from "./settings/global";
import { DefaultTemplatesConfig } from "./settings/defaultTemplatesConfig";

const DOCUMENTATION_URL = "https://github.com/joplin/plugin-templates#readme";

joplin.plugins.register({
onStart: async function() {
// Register setting section
await joplin.settings.registerSection("templatesPlugin", {
label: "Templates",
});


// Register all settings
await joplin.settings.registerSettings({
"defaultNoteTemplateId": {
public: false,
type: SettingItemType.String,
value: null,
label: "Default note template ID"
},
"defaultTodoTemplateId": {
public: false,
type: SettingItemType.String,
value: null,
label: "Default to-do template ID"
},
"defaultTemplatesConfig": {
public: false,
type: SettingItemType.Object,
value: null,
label: "Default templates config"
},
"applyTagsWhileInserting": {
public: true,
type: SettingItemType.Bool,
value: true,
label: "Apply tags while inserting template",
description: "Apply tags using 'template_tags' variable while inserting template to notes/to-dos.",
section: "templatesPlugin"
},
"templatesSource": {
public: true,
type: SettingItemType.String,
isEnum: true,
value: "tag",
options: {
"tag": "Tag",
"notebook": "Notebook"
},
label: "Are templates set with tags or stored in a notebook?",
description: "If set to 'Tag', any note/to-do with a 'template' tag is considered a template. If set to 'Notebook', any note/todo stored in a notebook titled 'Templates' is considered a template.",
section: "templatesPlugin"
},
});
await PluginSettingsRegistry.registerSettings();


// Global variables
const joplinGlobalApis = new PromiseGroup();

joplinGlobalApis.set("dialogViewHandle", joplin.views.dialogs.create("dialog"));
joplinGlobalApis.set("userLocale", joplin.settings.globalValue("locale"));
joplinGlobalApis.set("userDateFormat", joplin.settings.globalValue("dateFormat"));
joplinGlobalApis.set("userTimeFormat", joplin.settings.globalValue("timeFormat"));
joplinGlobalApis.set("profileDir", joplin.settings.globalValue("profileDir"));
joplinGlobalApis.set("userLocale", LocaleGlobalSetting.get());
joplinGlobalApis.set("userDateFormat", DateFormatGlobalSetting.get());
joplinGlobalApis.set("userTimeFormat", TimeFormatGlobalSetting.get());
joplinGlobalApis.set("profileDir", ProfileDirGlobalSetting.get());

const {
dialogViewHandle, userLocale, userDateFormat,
Expand Down Expand Up @@ -102,7 +59,7 @@ joplin.plugins.register({
await performActionWithParsedTemplate(action, template);
}

const getNotebookDefaultTemplatesDisplayData = async (settings: DefaultTemplatesConfigSetting): Promise<NotebookDefaultTemplatesDisplayData[]> => {
const getNotebookDefaultTemplatesDisplayData = async (settings: DefaultTemplatesConfig): Promise<NotebookDefaultTemplatesDisplayData[]> => {
const getDisplayDataForNotebook = async (notebookId: string, defaultTemplateNoteId: string | null, defaultTemplateTodoId: string | null): Promise<NotebookDefaultTemplatesDisplayData | null> => {
const promiseGroup = new PromiseGroup();
promiseGroup.set("notebook", getFolderFromId(notebookId));
Expand All @@ -112,7 +69,7 @@ joplin.plugins.register({

if (notebook === null || (noteTemplate === null && todoTemplate === null)) {
// Async remove of the obsolete config
clearDefaultTemplates(notebookId);
DefaultTemplatesConfigSetting.clearDefaultTemplates(notebookId);
return null;
}
return {
Expand Down Expand Up @@ -162,9 +119,9 @@ joplin.plugins.register({
name: "showDefaultTemplates",
label: "Show default templates",
execute: async () => {
const noteTemplate = await getTemplateFromId(await joplin.settings.value("defaultNoteTemplateId"));
const todoTemplate = await getTemplateFromId(await joplin.settings.value("defaultTodoTemplateId"));
const defaultTemplatesConfig = await getNotebookDefaultTemplatesConfig();
const noteTemplate = await getTemplateFromId(await DefaultNoteTemplateIdSetting.get());
const todoTemplate = await getTemplateFromId(await DefaultTodoTemplateIdSetting.get());
const defaultTemplatesConfig = await DefaultTemplatesConfigSetting.get();

const globalDefaultTemplates: DefaultTemplatesDisplayData = {
defaultNoteTemplateTitle: noteTemplate ? noteTemplate.title : null,
Expand Down Expand Up @@ -217,7 +174,7 @@ joplin.plugins.register({
const folder: Folder | null = JSON.parse(await getUserFolderSelection() || "null");
if (folder === null) return;

await clearDefaultTemplates(folder.id);
await DefaultTemplatesConfigSetting.clearDefaultTemplates(folder.id);
await joplin.views.dialogs.showMessageBox(`Default templates for "${folder.title}" cleared successfully!`);
}
}));
Expand All @@ -228,15 +185,15 @@ joplin.plugins.register({
execute: async () => {
let defaultTemplate: Note | null = null;

const defaultTemplatesConfig = await getNotebookDefaultTemplatesConfig();
const defaultTemplatesConfig = await DefaultTemplatesConfigSetting.get();
const currentFolderId = await getSelectedFolder();

if (currentFolderId in defaultTemplatesConfig) {
defaultTemplate = await getTemplateFromId(defaultTemplatesConfig[currentFolderId].defaultNoteTemplateId);
}

if (defaultTemplate === null) {
defaultTemplate = await getTemplateFromId(await joplin.settings.value("defaultNoteTemplateId"));
defaultTemplate = await getTemplateFromId(await DefaultNoteTemplateIdSetting.get());
}

if (defaultTemplate) {
Expand All @@ -252,15 +209,15 @@ joplin.plugins.register({
execute: async () => {
let defaultTemplate: Note | null = null;

const defaultTemplatesConfig = await getNotebookDefaultTemplatesConfig();
const defaultTemplatesConfig = await DefaultTemplatesConfigSetting.get();
const currentFolderId = await getSelectedFolder();

if (currentFolderId in defaultTemplatesConfig) {
defaultTemplate = await getTemplateFromId(defaultTemplatesConfig[currentFolderId].defaultTodoTemplateId);
}

if (defaultTemplate === null) {
defaultTemplate = await getTemplateFromId(await joplin.settings.value("defaultTodoTemplateId"));
defaultTemplate = await getTemplateFromId(await DefaultTodoTemplateIdSetting.get());
}

if (defaultTemplate) {
Expand Down
11 changes: 11 additions & 0 deletions src/settings/applyTagsWhileInserting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SettingItemType } from "api/types";
import { createSimpleSetting } from "./base";

export const ApplyTagsWhileInsertingSetting = createSimpleSetting<boolean>("applyTagsWhileInserting", {
public: true,
type: SettingItemType.Bool,
value: true,
label: "Apply tags while inserting template",
description: "Apply tags using 'template_tags' variable while inserting template to notes/to-dos.",
section: "templatesPlugin"
});
46 changes: 46 additions & 0 deletions src/settings/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import joplin from "api";
import { SettingItem } from "api/types";

export interface PluginSetting<T> {
id: string;
manifest: SettingItem;

get(): Promise<T>;
set(newValue: T): Promise<void>;
}

export const createSimpleSetting = <T>(id: string, manifest: SettingItem): PluginSetting<T> => {
return class {
static id = id;
static manifest = manifest;

static async get(): Promise<T> {
return await joplin.settings.value(id);
}

static async set(newValue: T): Promise<void> {
await joplin.settings.setValue(id, newValue);
}
}
}

/**
* This considers that the original setting is of type `string`. On `set` if no original value
* can be traced back, the setting is set to an empty string.
*/
export const createMappedSetting = <T>(id: string, manifest: SettingItem, valueMap: Record<string, T>, defaultValue: T): PluginSetting<T> => {
return class {
static id = id;
static manifest = manifest;

static async get(): Promise<T> {
const value: string = await joplin.settings.value(id);
return value in valueMap ? valueMap[value] : defaultValue;
}

static async set(newValue: T): Promise<void> {
const potentialValues = Object.entries(valueMap).filter((entry) => entry[1] === newValue);
await joplin.settings.setValue(id, potentialValues.length ? potentialValues[0][0] : "" );
}
}
}
9 changes: 9 additions & 0 deletions src/settings/defaultNoteTemplateId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { SettingItemType } from "api/types";
import { createSimpleSetting } from "./base";

export const DefaultNoteTemplateIdSetting = createSimpleSetting<string | null>("defaultNoteTemplateId", {
public: false,
type: SettingItemType.String,
value: null,
label: "Default note template ID"
});
71 changes: 71 additions & 0 deletions src/settings/defaultTemplatesConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import joplin from "api";
import { SettingItemType } from "api/types";

export interface DefaultTemplatesConfig {
[notebookId: string]: {
defaultNoteTemplateId: string | null;
defaultTodoTemplateId: string | null;
}
}

enum DefaultType {
Both,
Note,
Todo,
}

export const DefaultTemplatesConfigSetting = class {
static readonly DefaultType = DefaultType;

static id = "defaultTemplatesConfig";

static manifest = {
public: false,
type: SettingItemType.Object,
value: null,
label: "Default templates config"
};

static async get(): Promise<DefaultTemplatesConfig> {
const defaultTemplatesConfig: DefaultTemplatesConfig | null = await joplin.settings.value(DefaultTemplatesConfigSetting.id);
return defaultTemplatesConfig ? defaultTemplatesConfig : {};
}

static async set(newValue: DefaultTemplatesConfig): Promise<void> {
await joplin.settings.setValue(DefaultTemplatesConfigSetting.id, newValue);
}

static async setDefaultTempalte(notebookId: string, templateId: string, defaultType: DefaultType): Promise<void> {
const defaultTemplatesConfig = await this.get();

if (!(notebookId in defaultTemplatesConfig)) {
defaultTemplatesConfig[notebookId] = {
defaultNoteTemplateId: null,
defaultTodoTemplateId: null
};
}

switch (defaultType) {
case DefaultType.Note:
defaultTemplatesConfig[notebookId].defaultNoteTemplateId = templateId;
break;
case DefaultType.Todo:
defaultTemplatesConfig[notebookId].defaultTodoTemplateId = templateId;
break;
case DefaultType.Both:
defaultTemplatesConfig[notebookId].defaultNoteTemplateId = templateId;
defaultTemplatesConfig[notebookId].defaultTodoTemplateId = templateId;
break;
default:
break;
}

await this.set(defaultTemplatesConfig);
}

static async clearDefaultTemplates(notebookId: string): Promise<void> {
const defaultTemplatesConfig = await this.get();
delete defaultTemplatesConfig[notebookId];
await this.set(defaultTemplatesConfig);
}
}
9 changes: 9 additions & 0 deletions src/settings/defaultTodoTemplateId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { SettingItemType } from "api/types";
import { createSimpleSetting } from "./base";

export const DefaultTodoTemplateIdSetting = createSimpleSetting<string | null>("defaultTodoTemplateId", {
public: false,
type: SettingItemType.String,
value: null,
label: "Default to-do template ID"
});
16 changes: 16 additions & 0 deletions src/settings/global/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import joplin from "api";

export interface GlobalSetting<T> {
id: string;
get(): Promise<T>;
}

export const createGlobalSetting = <T>(id: string): GlobalSetting<T> => {
return class {
static id = id;

static async get(): Promise<T> {
return await joplin.settings.globalValue(id);
}
}
}
9 changes: 9 additions & 0 deletions src/settings/global/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createGlobalSetting } from "./base";

export const LocaleGlobalSetting = createGlobalSetting<string>("locale");

export const DateFormatGlobalSetting = createGlobalSetting<string>("dateFormat");

export const TimeFormatGlobalSetting = createGlobalSetting<string>("timeFormat");

export const ProfileDirGlobalSetting = createGlobalSetting<string>("profileDir");
9 changes: 9 additions & 0 deletions src/settings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Export all individual settings
export { ApplyTagsWhileInsertingSetting } from "./applyTagsWhileInserting";
export { DefaultNoteTemplateIdSetting } from "./defaultNoteTemplateId";
export { DefaultTemplatesConfigSetting } from "./defaultTemplatesConfig";
export { DefaultTodoTemplateIdSetting } from "./defaultTodoTemplateId";
export { TemplatesSourceSetting } from "./templatesSource";

// Export registry
export { PluginSettingsRegistry } from "./registry";
Loading
Loading