mirror of
https://github.com/sorinmircea/obsidian-forms-plugin.git
synced 2026-07-22 12:00:30 +00:00
initial commit
This commit is contained in:
commit
83bfabfbdb
21 changed files with 3077 additions and 0 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
3
.eslintignore
Normal file
3
.eslintignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
|
||||
main.js
|
||||
23
.eslintrc
Normal file
23
.eslintrc
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Don't include the compiled main.js file in the repo.
|
||||
# They should be uploaded to GitHub releases instead.
|
||||
main.js
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
1
.npmrc
Normal file
1
.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
tag-version-prefix=""
|
||||
2
LICENSE
Normal file
2
LICENSE
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Copyright 2025 Sorin-Sebastian Mircea
|
||||
All rights reserved. This source code may not be used, copied, modified, or distributed without prior written consent.
|
||||
94
README.md
Normal file
94
README.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# Obsidian Sample Plugin
|
||||
|
||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
||||
|
||||
This project uses TypeScript to provide type checking and documentation.
|
||||
The repo depends on the latest plugin API (obsidian.d.ts) in TypeScript Definition format, which contains TSDoc comments describing what it does.
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
|
||||
## First time developing plugins?
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
|
||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
|
||||
## Releasing new releases
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
|
||||
## Adding your plugin to the community plugin list
|
||||
|
||||
- Check the [plugin guidelines](https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines).
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
|
||||
## How to use
|
||||
|
||||
- Clone this repo.
|
||||
- Make sure your NodeJS is at least v16 (`node --version`).
|
||||
- `npm i` or `yarn` to install dependencies.
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
|
||||
## Manually installing the plugin
|
||||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
|
||||
## Improve code quality with eslint (optional)
|
||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
||||
- To use eslint with this project, make sure to install eslint from terminal:
|
||||
- `npm install -g eslint`
|
||||
- To use eslint to analyze this project use this command:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
|
||||
## Funding URL
|
||||
|
||||
You can include funding URLs where people who use your plugin can financially support it.
|
||||
|
||||
The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": "https://buymeacoffee.com"
|
||||
}
|
||||
```
|
||||
|
||||
If you have multiple URLs, you can also do:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": {
|
||||
"Buy Me a Coffee": "https://buymeacoffee.com",
|
||||
"GitHub Sponsor": "https://github.com/sponsors",
|
||||
"Patreon": "https://www.patreon.com/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
2
constants.ts
Normal file
2
constants.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export const API_BASE_URL = "https://formsidian.com";
|
||||
export const FORMS_POST_ENDPOINT = `${API_BASE_URL}/api/forms`;
|
||||
49
esbuild.config.mjs
Normal file
49
esbuild.config.mjs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === "production");
|
||||
|
||||
const context = await esbuild.context({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ["main.ts"],
|
||||
bundle: true,
|
||||
external: [
|
||||
"obsidian",
|
||||
"electron",
|
||||
"@codemirror/autocomplete",
|
||||
"@codemirror/collab",
|
||||
"@codemirror/commands",
|
||||
"@codemirror/language",
|
||||
"@codemirror/lint",
|
||||
"@codemirror/search",
|
||||
"@codemirror/state",
|
||||
"@codemirror/view",
|
||||
"@lezer/common",
|
||||
"@lezer/highlight",
|
||||
"@lezer/lr",
|
||||
...builtins],
|
||||
format: "cjs",
|
||||
target: "es2018",
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : "inline",
|
||||
treeShaking: true,
|
||||
outfile: "main.js",
|
||||
minify: prod,
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
await context.rebuild();
|
||||
process.exit(0);
|
||||
} else {
|
||||
await context.watch();
|
||||
}
|
||||
39
main.ts
Normal file
39
main.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import FormManagementModal from "ui/FormManagementModal";
|
||||
import {
|
||||
Notice,
|
||||
Plugin,
|
||||
} from "obsidian";
|
||||
import APIManager from "managers/APIManager";
|
||||
|
||||
export default class Formsidian extends Plugin {
|
||||
apiManager: APIManager;
|
||||
|
||||
async onload() {
|
||||
this.apiManager = new APIManager(this);
|
||||
|
||||
// Add ribbon icon
|
||||
this.addRibbonIcon("book-copy", "Formsidian dashboard", (evt: MouseEvent) => {
|
||||
new FormManagementModal(this.app, this).open();
|
||||
});
|
||||
|
||||
// Add shortcut to force resync
|
||||
this.addCommand({
|
||||
id: "sync-formsidian",
|
||||
name: "Sync forms",
|
||||
callback: () => {
|
||||
this.apiManager.fetchFormData().then(() => {
|
||||
new Notice(`Formsidian successfully synced`);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Silently sync with formsidian server once per hour
|
||||
this.registerInterval(
|
||||
window.setInterval(() => {
|
||||
this.apiManager.fetchFormData().then(() => {});
|
||||
}, 60 * 60 * 1000)
|
||||
);
|
||||
}
|
||||
|
||||
onunload() {}
|
||||
}
|
||||
128
managers/APIManager.ts
Normal file
128
managers/APIManager.ts
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
import { FORMS_POST_ENDPOINT } from "../constants";
|
||||
import { Notice, requestUrl } from "obsidian";
|
||||
|
||||
interface APIManagerCreateFormRes {
|
||||
public_url: string;
|
||||
mount_dir: string;
|
||||
edit_url: string;
|
||||
api_url: string;
|
||||
management_secret:string;
|
||||
}
|
||||
|
||||
interface Value {
|
||||
label: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface ResponseItem {
|
||||
response_id: number;
|
||||
submitted_at: string;
|
||||
submitted_by: string | null;
|
||||
values: Value[];
|
||||
}
|
||||
|
||||
export default class APIManager {
|
||||
private plugin: any;
|
||||
private data: Record<string, APIManagerCreateFormRes>;
|
||||
|
||||
constructor(plugin: any) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
async createForm(
|
||||
vault_name: string,
|
||||
mount_dir: string
|
||||
): Promise<APIManagerCreateFormRes | undefined> {
|
||||
try {
|
||||
const response = await fetch(FORMS_POST_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ vault_name, mount_dir }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
new Notice(
|
||||
`Failed to create form: ${
|
||||
errorData.error || response.statusText
|
||||
}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch (error) {
|
||||
new Notice("Failed to create form. Check console for details.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public async fetchFormData(): Promise<void> {
|
||||
// Load stored data which maps directory to the URL
|
||||
this.data = await this.plugin.loadData();
|
||||
|
||||
// For each mount configuration
|
||||
for (const key in this.data) {
|
||||
const { mount_dir, api_url } = this.data[key];
|
||||
// Fetch the data from the API
|
||||
const responses = await this.fetchResponses(api_url);
|
||||
|
||||
// For each response item, create a note
|
||||
for (const responseItem of responses) {
|
||||
await this.createNoteFromResponse(mount_dir, responseItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchResponses(url: string): Promise<ResponseItem[]> {
|
||||
const response = await requestUrl({ url });
|
||||
if (!response.json || !Array.isArray(response.json)) {
|
||||
return [];
|
||||
}
|
||||
return response.json as ResponseItem[];
|
||||
}
|
||||
|
||||
private async createNoteFromResponse(
|
||||
mountDir: string,
|
||||
response: ResponseItem
|
||||
): Promise<void> {
|
||||
// Construct a note filename based on the response (e.g., response_id)
|
||||
const fileNameBase = `response_${response.response_id}`;
|
||||
const fileName = `${mountDir}/${fileNameBase}.md`;
|
||||
|
||||
// Map values into YAML frontmatter and body
|
||||
const frontmatterEntries = response.values
|
||||
.map((v) => `${v.label}: "${v.content}"`)
|
||||
.join("\n");
|
||||
const submittedAt = `submitted_at: "${response.submitted_at}"`;
|
||||
const submittedBy = `submitted_by: ${
|
||||
response.submitted_by !== null
|
||||
? `"${response.submitted_by}"`
|
||||
: "null"
|
||||
}`;
|
||||
|
||||
// Prepare the note content
|
||||
const noteContent = `---
|
||||
${submittedAt}
|
||||
${frontmatterEntries}
|
||||
---
|
||||
`;
|
||||
|
||||
// Ensure the directory exists
|
||||
await this.ensureFolderExists(mountDir);
|
||||
|
||||
// Create or overwrite the note file
|
||||
await this.plugin.app.vault.adapter.write(fileName, noteContent);
|
||||
}
|
||||
|
||||
private async ensureFolderExists(folderPath: string) {
|
||||
const adapter = this.plugin.app.vault.adapter;
|
||||
const folderExists = await adapter.exists(folderPath);
|
||||
if (!folderExists) {
|
||||
await adapter.mkdir(folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
managers/ContentManager.ts
Normal file
65
managers/ContentManager.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { App, TFile, Notice } from "obsidian";
|
||||
|
||||
export default class ContentManager {
|
||||
private app: App;
|
||||
|
||||
constructor(app: App) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new document at the specified path.
|
||||
*/
|
||||
async createDocument(path: string, content: string): Promise<void> {
|
||||
try {
|
||||
// Check if file already exists
|
||||
const existingFile = this.app.vault.getAbstractFileByPath(path);
|
||||
if (existingFile instanceof TFile) {
|
||||
new Notice(`A file already exists at ${path}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the file with the content
|
||||
await this.app.vault.create(path, content);
|
||||
new Notice(`Document created at ${path}`);
|
||||
} catch (error) {
|
||||
new Notice(
|
||||
"Failed to create document."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getAllFolders(): string[] {
|
||||
const folders = new Set<string>();
|
||||
folders.add("/");
|
||||
this.app.vault.getAllFolders().forEach((folder) => {
|
||||
folders.add(folder.path);
|
||||
});
|
||||
return Array.from(folders).sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates properties for the document.
|
||||
*/
|
||||
generateMockProperties(): string {
|
||||
const Data = {
|
||||
title: " Title",
|
||||
dateCreated: new Date().toISOString(),
|
||||
tags: ["", "example"],
|
||||
content: "This is a document created by the FileManager.",
|
||||
};
|
||||
|
||||
// Convert the data to Markdown format
|
||||
return `---
|
||||
${Object.entries(Data)
|
||||
.map(([key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
return `${key}: [${value.join(", ")}]`;
|
||||
}
|
||||
return `${key}: ${value}`;
|
||||
})
|
||||
.join("\n")}
|
||||
---
|
||||
${Data.content}`;
|
||||
}
|
||||
}
|
||||
11
manifest.json
Normal file
11
manifest.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"id": "formsidian",
|
||||
"name": "Formsidian",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Forms for obsidian.",
|
||||
"author": "Sorin Mircea",
|
||||
"authorUrl": "https://sorinmircea.com",
|
||||
"fundingUrl": "https://formsidian.com",
|
||||
"isDesktopOnly": true
|
||||
}
|
||||
2348
package-lock.json
generated
Normal file
2348
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
27
package.json
Normal file
27
package.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.17.3",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.47.7"
|
||||
}
|
||||
}
|
||||
8
styles.css
Normal file
8
styles.css
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
|
||||
*/
|
||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"strictNullChecks": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
21
types/FormData.ts
Normal file
21
types/FormData.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export default class FormData {
|
||||
mount_dir: string;
|
||||
public_url: string;
|
||||
edit_url: string;
|
||||
api_url: string;
|
||||
management_secret: string;
|
||||
|
||||
constructor(
|
||||
mount_dir: string,
|
||||
public_url: string,
|
||||
edit_url: string,
|
||||
api_url: string,
|
||||
management_secret: string
|
||||
) {
|
||||
this.mount_dir = mount_dir;
|
||||
this.public_url = public_url;
|
||||
this.edit_url = edit_url;
|
||||
this.api_url = api_url;
|
||||
this.management_secret = management_secret;
|
||||
}
|
||||
}
|
||||
183
ui/FormManagementModal.ts
Normal file
183
ui/FormManagementModal.ts
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
import { App, Modal, Notice, Plugin, Setting, FileManager } from "obsidian";
|
||||
import FormData from "types/FormData";
|
||||
import ContentManager from "managers/ContentManager";
|
||||
import APIManager from "managers/APIManager";
|
||||
|
||||
export default class FormManagementModal extends Modal {
|
||||
currentFolder: string;
|
||||
allFolders: string[];
|
||||
forms: Map<string, FormData>;
|
||||
plugin: Plugin;
|
||||
|
||||
contentManager: ContentManager;
|
||||
apiManager: APIManager;
|
||||
|
||||
constructor(app: App, plugin: Plugin) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.contentManager = new ContentManager(app);
|
||||
this.apiManager = new APIManager(plugin);
|
||||
|
||||
const activeFile = this.app.workspace.getActiveFile();
|
||||
this.allFolders = this.contentManager.getAllFolders();
|
||||
this.forms = new Map();
|
||||
|
||||
if (activeFile) {
|
||||
const filePath = activeFile.path;
|
||||
this.currentFolder = filePath.substring(
|
||||
0,
|
||||
filePath.lastIndexOf("/")
|
||||
);
|
||||
} else {
|
||||
this.currentFolder = "No active folder";
|
||||
}
|
||||
}
|
||||
|
||||
async loadForms() {
|
||||
const savedForms = (await this.plugin.loadData()) || {};
|
||||
for (const [key, value] of Object.entries(savedForms)) {
|
||||
let formValue = value as FormData;
|
||||
this.forms.set(
|
||||
key,
|
||||
new FormData(
|
||||
formValue.mount_dir,
|
||||
formValue.public_url,
|
||||
formValue.edit_url,
|
||||
formValue.api_url,
|
||||
formValue.management_secret
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async saveForms() {
|
||||
const data: Record<string, FormData> = {};
|
||||
this.forms.forEach((formData, key) => {
|
||||
data[key] = {
|
||||
mount_dir: formData.mount_dir,
|
||||
public_url: formData.public_url,
|
||||
edit_url: formData.edit_url,
|
||||
api_url: formData.api_url,
|
||||
management_secret: formData.management_secret,
|
||||
};
|
||||
});
|
||||
await this.plugin.saveData(data);
|
||||
}
|
||||
|
||||
async onOpen() {
|
||||
await this.loadForms();
|
||||
|
||||
const { contentEl } = this;
|
||||
contentEl.empty(); // Clear the modal content to ensure updates are reflected
|
||||
|
||||
// Modal title
|
||||
contentEl.createEl("h3", { text: "New Form" });
|
||||
|
||||
// Add button to sync the currently selected folder
|
||||
new Setting(contentEl)
|
||||
.setName("Folder path")
|
||||
.setDesc("Root folder for the form.")
|
||||
.addDropdown((dropdown) => {
|
||||
this.allFolders.forEach((folder) => {
|
||||
dropdown.addOption(folder, folder);
|
||||
});
|
||||
dropdown
|
||||
.setValue(this.currentFolder) // Prepopulate with the current folder
|
||||
.onChange((value) => {
|
||||
this.currentFolder = value;
|
||||
});
|
||||
})
|
||||
.addButton((button) => {
|
||||
button
|
||||
.setButtonText("Add Folder")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
if (!this.forms.has(this.currentFolder)) {
|
||||
new Notice(`Linking folder...`);
|
||||
|
||||
// Call Server
|
||||
let serverResponse =
|
||||
await this.apiManager.createForm(
|
||||
this.app.vault.getName(),
|
||||
this.currentFolder
|
||||
);
|
||||
|
||||
// Save locally
|
||||
if (serverResponse) {
|
||||
this.forms.set(
|
||||
this.currentFolder,
|
||||
new FormData(
|
||||
this.currentFolder,
|
||||
serverResponse.public_url,
|
||||
serverResponse.edit_url,
|
||||
serverResponse.api_url,
|
||||
serverResponse.management_secret
|
||||
)
|
||||
);
|
||||
this.saveForms();
|
||||
new Notice(
|
||||
`${this.currentFolder} linked to Formsidian`
|
||||
);
|
||||
} else {
|
||||
new Notice(`Failed connecting to the server`);
|
||||
}
|
||||
|
||||
this.onOpen(); // Refresh to update the synced folders list
|
||||
} else {
|
||||
new Notice(
|
||||
`${this.currentFolder} is already added`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// List all synced folders with configure and delete options
|
||||
contentEl.createEl("br");
|
||||
contentEl.createEl("h3", { text: "Forms" });
|
||||
Array.from(this.forms.entries()).forEach(([folder, formData]) => {
|
||||
const folderSetting = new Setting(contentEl).setName(folder);
|
||||
|
||||
folderSetting
|
||||
.addButton((button) => {
|
||||
button
|
||||
.setButtonText("Configure")
|
||||
.setCta()
|
||||
.setTooltip("Configure form questions")
|
||||
.onClick(() => {
|
||||
new Notice(`Configuring sync for ${folder}...`);
|
||||
window.open(
|
||||
`${formData.edit_url}?secret=${formData.management_secret}`,
|
||||
"_blank"
|
||||
);
|
||||
});
|
||||
})
|
||||
.addButton((button) => {
|
||||
button
|
||||
.setIcon("sync")
|
||||
.setCta()
|
||||
.setTooltip("Fetch filled forms")
|
||||
.onClick(() => {
|
||||
this.apiManager.fetchFormData().then(() => {
|
||||
new Notice(`Formsidian successfully synced`);
|
||||
});
|
||||
});
|
||||
})
|
||||
.addButton((button) => {
|
||||
button
|
||||
.setIcon("cross")
|
||||
.setWarning()
|
||||
.onClick(() => {
|
||||
this.forms.delete(folder);
|
||||
this.saveForms();
|
||||
new Notice(`${folder} unlinked`);
|
||||
this.onOpen(); // Refresh the modal
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
14
version-bump.mjs
Normal file
14
version-bump.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
3
versions.json
Normal file
3
versions.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
Loading…
Reference in a new issue