mirror of
https://github.com/qf3l3k/obsidian-data-fetcher.git
synced 2026-07-22 05:43:10 +00:00
release: 1.1.1
This commit is contained in:
parent
c1e004818d
commit
70f472f631
10 changed files with 562 additions and 116 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.1] - 2026-03-03
|
||||
|
||||
### Added
|
||||
- Added compact endpoint list view in settings with columns for name, type, URL, headers count, and row actions.
|
||||
- Added endpoint editor modal for create/edit flows to keep advanced endpoint details out of the main settings list.
|
||||
- Added endpoint row actions: Edit, Duplicate, and Delete.
|
||||
|
||||
### Changed
|
||||
- Updated endpoint settings layout for better readability when many aliases exist.
|
||||
- Reduced endpoint list font size and tightened spacing to better match Obsidian settings styling and avoid clipped action buttons.
|
||||
|
||||
## [1.1.0] - 2026-03-02
|
||||
|
||||
### Added
|
||||
|
|
|
|||
110
RELEASE_CHECKLIST.md
Normal file
110
RELEASE_CHECKLIST.md
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
# Release Checklist (Public GitHub)
|
||||
|
||||
Use this flow when publishing `1.0.7`, `1.0.8`, `1.0.9`, etc. to the public repo without force-pushing `main`.
|
||||
|
||||
## 1) Pick release version
|
||||
|
||||
- Set a target version, for example: `1.0.7`.
|
||||
- Ensure these files match that version:
|
||||
- `manifest.json`
|
||||
- `versions.json` (must include the target entry)
|
||||
- `package.json`
|
||||
- `package-lock.json`
|
||||
|
||||
## 2) Validate locally
|
||||
|
||||
```powershell
|
||||
cmd /c npx tsc -noEmit -skipLibCheck
|
||||
cmd /c npm run build
|
||||
```
|
||||
|
||||
## 3) Create release commit/tag on internal main
|
||||
|
||||
```powershell
|
||||
git checkout main
|
||||
git pull origin main
|
||||
git status --short
|
||||
git add manifest.json versions.json package.json package-lock.json CHANGELOG.md README.md
|
||||
git commit -m "release: 1.0.7"
|
||||
git tag 1.0.7
|
||||
git push origin main --tags
|
||||
```
|
||||
|
||||
## 4) Prepare public PR branch from `public/main`
|
||||
|
||||
```powershell
|
||||
git fetch public --tags
|
||||
git checkout -B public-fix-1.0.7 public/main
|
||||
```
|
||||
|
||||
## 5) Copy release metadata from tag to PR branch
|
||||
|
||||
```powershell
|
||||
git checkout 1.0.7 -- manifest.json versions.json package.json package-lock.json
|
||||
```
|
||||
|
||||
## 6) Sanity check diff (must be version metadata only)
|
||||
|
||||
```powershell
|
||||
git diff -- manifest.json versions.json package.json package-lock.json
|
||||
git status --short
|
||||
```
|
||||
|
||||
## 7) Commit and push PR branch
|
||||
|
||||
```powershell
|
||||
git add manifest.json versions.json package.json package-lock.json
|
||||
git commit -m "public: bump release metadata to 1.0.7"
|
||||
git push public public-fix-1.0.7
|
||||
```
|
||||
|
||||
## 8) Open and merge PR
|
||||
|
||||
- Open:
|
||||
- `https://github.com/qf3l3k/obsidian-data-fetcher/pull/new/public-fix-1.0.7`
|
||||
- Merge into `public/main`.
|
||||
|
||||
## 9) Publish GitHub release assets for tag `1.0.7`
|
||||
|
||||
- Upload files built from the same tag:
|
||||
- `manifest.json`
|
||||
- `main.js`
|
||||
- `styles.css`
|
||||
|
||||
## 10) Verify end-user update path
|
||||
|
||||
- In Obsidian:
|
||||
- Check plugin version visible in Community Plugins.
|
||||
- Run update from previous version and confirm it upgrades to target.
|
||||
|
||||
---
|
||||
|
||||
## Quick Command Template
|
||||
|
||||
Replace `1.0.7` with your target version before running:
|
||||
|
||||
```powershell
|
||||
# 0) Variables
|
||||
$V = "1.0.7"
|
||||
|
||||
# 1) Internal release
|
||||
git checkout main
|
||||
git pull origin main
|
||||
cmd /c npx tsc -noEmit -skipLibCheck
|
||||
cmd /c npm run build
|
||||
git add manifest.json versions.json package.json package-lock.json CHANGELOG.md README.md
|
||||
git commit -m "release: $V"
|
||||
git tag $V
|
||||
git push origin main --tags
|
||||
|
||||
# 2) Public PR branch
|
||||
git fetch public --tags
|
||||
git checkout -B "public-fix-$V" public/main
|
||||
git checkout $V -- manifest.json versions.json package.json package-lock.json
|
||||
git add manifest.json versions.json package.json package-lock.json
|
||||
git commit -m "public: bump release metadata to $V"
|
||||
git push public "public-fix-$V"
|
||||
|
||||
# 3) Open PR URL manually
|
||||
Write-Output "Open: https://github.com/qf3l3k/obsidian-data-fetcher/pull/new/public-fix-$V"
|
||||
```
|
||||
347
main.ts
347
main.ts
|
|
@ -1,5 +1,5 @@
|
|||
import { App, Editor, EventRef, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TFile } from 'obsidian';
|
||||
import { DataFetcherSettings, DEFAULT_SETTINGS } from './src/settings';
|
||||
import { DataFetcherSettings, DEFAULT_SETTINGS, EndpointConfig } from './src/settings';
|
||||
import { parseDataQuery, executeQuery, QueryParams, QueryResult } from './src/queryEngine';
|
||||
import { CacheManager } from './src/cacheManager';
|
||||
|
||||
|
|
@ -827,113 +827,117 @@ class DataFetcherSettingTab extends PluginSettingTab {
|
|||
new Setting(containerEl)
|
||||
.setName('Endpoint aliases')
|
||||
.setHeading();
|
||||
|
||||
const endpointList = containerEl.createEl('div', {cls: 'endpoint-list'});
|
||||
|
||||
// Create UI for each existing endpoint
|
||||
this.plugin.settings.endpoints.forEach((endpoint, index) => {
|
||||
this.createEndpointSetting(endpointList, endpoint, index);
|
||||
});
|
||||
|
||||
// Add new endpoint button
|
||||
|
||||
this.renderEndpointTable(containerEl);
|
||||
|
||||
new Setting(containerEl)
|
||||
.addButton(button => button
|
||||
.setButtonText('Add endpoint')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.endpoints.push({
|
||||
alias: '',
|
||||
url: '',
|
||||
method: 'GET',
|
||||
type: 'rest',
|
||||
headers: {}
|
||||
});
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
}));
|
||||
}
|
||||
|
||||
createEndpointSetting(container: HTMLElement, endpoint: any, index: number) {
|
||||
const endpointEl = container.createEl('div', {cls: 'endpoint-item'});
|
||||
|
||||
new Setting(endpointEl)
|
||||
.setName('Alias')
|
||||
.addText(text => text
|
||||
.setPlaceholder('api-name')
|
||||
.setValue(endpoint.alias)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.endpoints[index].alias = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(endpointEl)
|
||||
.setName('Type')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('rest', 'REST')
|
||||
.addOption('graphql', 'GraphQL')
|
||||
.addOption('grpc', 'gRPC')
|
||||
.addOption('rpc', 'RPC')
|
||||
.setValue(endpoint.type)
|
||||
.onChange(async (value) => {
|
||||
const validTypes = ["rest", "graphql", "grpc", "rpc"];
|
||||
if (validTypes.includes(value)) {
|
||||
this.plugin.settings.endpoints[index].type = value as "rest" | "graphql" | "grpc" | "rpc";
|
||||
} else {
|
||||
// Default to REST if invalid type
|
||||
this.plugin.settings.endpoints[index].type = "rest";
|
||||
}
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
}));
|
||||
|
||||
new Setting(endpointEl)
|
||||
.setName('URL')
|
||||
.addText(text => text
|
||||
.setPlaceholder('https://api.example.com')
|
||||
.setValue(endpoint.url)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.endpoints[index].url = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// Add different fields based on endpoint type
|
||||
if (endpoint.type === 'rest' || endpoint.type === 'rpc') {
|
||||
new Setting(endpointEl)
|
||||
.setName('Method')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('GET', 'GET')
|
||||
.addOption('POST', 'POST')
|
||||
.addOption('PUT', 'PUT')
|
||||
.addOption('DELETE', 'DELETE')
|
||||
.setValue(endpoint.method)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.endpoints[index].method = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
|
||||
// Add headers section
|
||||
new Setting(endpointEl)
|
||||
.setName('Headers')
|
||||
.setDesc('Add headers for this endpoint')
|
||||
.addButton(button => button
|
||||
.setButtonText('Manage headers')
|
||||
.setCta()
|
||||
.onClick(() => {
|
||||
new HeadersModal(this.app, endpoint.headers, async (headers) => {
|
||||
this.plugin.settings.endpoints[index].headers = headers;
|
||||
const newEndpoint = this.buildDefaultEndpoint();
|
||||
new EndpointEditorModal(this.app, newEndpoint, async (savedEndpoint) => {
|
||||
this.plugin.settings.endpoints.push(savedEndpoint);
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
}).open();
|
||||
}));
|
||||
|
||||
// Delete button
|
||||
new Setting(endpointEl)
|
||||
.addButton(button => button
|
||||
.setButtonText('Delete')
|
||||
.setClass('data-fetcher-delete-btn')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.endpoints.splice(index, 1);
|
||||
}
|
||||
|
||||
private buildDefaultEndpoint(): EndpointConfig {
|
||||
return {
|
||||
alias: '',
|
||||
url: '',
|
||||
method: 'GET',
|
||||
type: 'rest',
|
||||
headers: {}
|
||||
};
|
||||
}
|
||||
|
||||
private endpointTypeLabel(type: EndpointConfig['type']): string {
|
||||
if (type === 'rest') return 'REST';
|
||||
if (type === 'graphql') return 'GraphQL';
|
||||
if (type === 'grpc') return 'gRPC';
|
||||
return 'RPC';
|
||||
}
|
||||
|
||||
private truncateUrl(url: string, maxLen = 72): string {
|
||||
if (!url) return '-';
|
||||
if (url.length <= maxLen) return url;
|
||||
return `${url.substring(0, maxLen - 1)}...`;
|
||||
}
|
||||
|
||||
private renderEndpointTable(containerEl: HTMLElement): void {
|
||||
const table = containerEl.createEl('div', { cls: 'data-fetcher-endpoint-table' });
|
||||
const header = table.createEl('div', { cls: 'data-fetcher-endpoint-row data-fetcher-endpoint-row-header' });
|
||||
header.createEl('div', { text: 'Name', cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-alias' });
|
||||
header.createEl('div', { text: 'Type', cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-type' });
|
||||
header.createEl('div', { text: 'URL', cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-url' });
|
||||
header.createEl('div', { text: 'Headers', cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-headers' });
|
||||
header.createEl('div', { text: 'Actions', cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-actions' });
|
||||
|
||||
if (this.plugin.settings.endpoints.length === 0) {
|
||||
const empty = table.createEl('div', { cls: 'data-fetcher-endpoint-empty' });
|
||||
empty.setText('No endpoints configured yet.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.plugin.settings.endpoints.forEach((endpoint, index) => {
|
||||
const row = table.createEl('div', { cls: 'data-fetcher-endpoint-row' });
|
||||
row.createEl('div', {
|
||||
text: endpoint.alias?.trim() || '(unnamed)',
|
||||
cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-alias'
|
||||
});
|
||||
row.createEl('div', {
|
||||
text: this.endpointTypeLabel(endpoint.type),
|
||||
cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-type'
|
||||
});
|
||||
row.createEl('div', {
|
||||
text: this.truncateUrl(endpoint.url),
|
||||
cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-url'
|
||||
});
|
||||
row.createEl('div', {
|
||||
text: String(Object.keys(endpoint.headers || {}).length),
|
||||
cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-headers'
|
||||
});
|
||||
const actions = row.createEl('div', {
|
||||
cls: 'data-fetcher-endpoint-col data-fetcher-endpoint-col-actions data-fetcher-endpoint-actions'
|
||||
});
|
||||
|
||||
actions.createEl('button', { text: 'Edit' }).addEventListener('click', () => {
|
||||
const draft = { ...endpoint, headers: { ...(endpoint.headers || {}) } };
|
||||
new EndpointEditorModal(this.app, draft, async (savedEndpoint) => {
|
||||
this.plugin.settings.endpoints[index] = savedEndpoint;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
}));
|
||||
}).open();
|
||||
});
|
||||
|
||||
actions.createEl('button', { text: 'Duplicate' }).addEventListener('click', () => {
|
||||
const duplicateAlias = endpoint.alias ? `${endpoint.alias}-copy` : '';
|
||||
const draft: EndpointConfig = {
|
||||
...endpoint,
|
||||
alias: duplicateAlias,
|
||||
headers: { ...(endpoint.headers || {}) }
|
||||
};
|
||||
new EndpointEditorModal(this.app, draft, async (savedEndpoint) => {
|
||||
this.plugin.settings.endpoints.push(savedEndpoint);
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
}).open();
|
||||
});
|
||||
|
||||
actions.createEl('button', { text: 'Delete', cls: 'mod-warning' }).addEventListener('click', async () => {
|
||||
const alias = endpoint.alias?.trim() || 'this endpoint';
|
||||
const shouldDelete = window.confirm(`Delete ${alias}?`);
|
||||
if (!shouldDelete) {
|
||||
return;
|
||||
}
|
||||
this.plugin.settings.endpoints.splice(index, 1);
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async updateCacheInfo(containerEl: HTMLElement) {
|
||||
|
|
@ -952,6 +956,151 @@ class DataFetcherSettingTab extends PluginSettingTab {
|
|||
}
|
||||
}
|
||||
|
||||
class EndpointEditorModal extends Modal {
|
||||
private endpoint: EndpointConfig;
|
||||
private onSubmit: (endpoint: EndpointConfig) => void;
|
||||
private methodSettingEl: HTMLElement | null = null;
|
||||
private headersSummaryEl: HTMLElement | null = null;
|
||||
|
||||
constructor(app: App, endpoint: EndpointConfig, onSubmit: (endpoint: EndpointConfig) => void) {
|
||||
super(app);
|
||||
this.endpoint = {
|
||||
...endpoint,
|
||||
headers: { ...(endpoint.headers || {}) },
|
||||
method: endpoint.method || 'GET'
|
||||
};
|
||||
this.onSubmit = onSubmit;
|
||||
}
|
||||
|
||||
private updateHeadersSummary(): void {
|
||||
if (!this.headersSummaryEl) {
|
||||
return;
|
||||
}
|
||||
const count = Object.keys(this.endpoint.headers || {}).length;
|
||||
this.headersSummaryEl.setText(`${count} header${count === 1 ? '' : 's'} configured`);
|
||||
}
|
||||
|
||||
private renderMethodSetting(containerEl: HTMLElement): void {
|
||||
if (this.methodSettingEl) {
|
||||
this.methodSettingEl.remove();
|
||||
this.methodSettingEl = null;
|
||||
}
|
||||
|
||||
if (this.endpoint.type !== 'rest' && this.endpoint.type !== 'rpc') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.methodSettingEl = containerEl.createDiv();
|
||||
new Setting(this.methodSettingEl)
|
||||
.setName('Method')
|
||||
.setDesc('HTTP method for REST/RPC requests')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('GET', 'GET')
|
||||
.addOption('POST', 'POST')
|
||||
.addOption('PUT', 'PUT')
|
||||
.addOption('DELETE', 'DELETE')
|
||||
.setValue(this.endpoint.method || 'GET')
|
||||
.onChange(value => {
|
||||
this.endpoint.method = value;
|
||||
}));
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
this.modalEl.addClass('data-fetcher-endpoint-editor-modal');
|
||||
contentEl.addClass('data-fetcher-endpoint-editor');
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName('Endpoint editor')
|
||||
.setHeading();
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName('Alias')
|
||||
.setDesc('Endpoint reference name used in notes, e.g. @my-api')
|
||||
.addText(text => text
|
||||
.setPlaceholder('my-api')
|
||||
.setValue(this.endpoint.alias || '')
|
||||
.onChange(value => {
|
||||
this.endpoint.alias = value.trim();
|
||||
}));
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName('Type')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('rest', 'REST')
|
||||
.addOption('graphql', 'GraphQL')
|
||||
.addOption('grpc', 'gRPC')
|
||||
.addOption('rpc', 'RPC')
|
||||
.setValue(this.endpoint.type)
|
||||
.onChange(value => {
|
||||
const validTypes: EndpointConfig['type'][] = ['rest', 'graphql', 'grpc', 'rpc'];
|
||||
this.endpoint.type = validTypes.includes(value as EndpointConfig['type'])
|
||||
? (value as EndpointConfig['type'])
|
||||
: 'rest';
|
||||
this.renderMethodSetting(contentEl);
|
||||
}));
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName('URL')
|
||||
.setDesc('Endpoint URL')
|
||||
.addText(text => text
|
||||
.setPlaceholder('https://api.example.com')
|
||||
.setValue(this.endpoint.url || '')
|
||||
.onChange(value => {
|
||||
this.endpoint.url = value.trim();
|
||||
}));
|
||||
|
||||
this.renderMethodSetting(contentEl);
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName('Headers')
|
||||
.setDesc('Authentication and custom request headers')
|
||||
.addButton(button => button
|
||||
.setButtonText('Manage headers')
|
||||
.onClick(() => {
|
||||
new HeadersModal(this.app, this.endpoint.headers || {}, (headers) => {
|
||||
this.endpoint.headers = headers;
|
||||
this.updateHeadersSummary();
|
||||
}).open();
|
||||
}));
|
||||
|
||||
this.headersSummaryEl = contentEl.createEl('div', { cls: 'data-fetcher-endpoint-header-summary' });
|
||||
this.updateHeadersSummary();
|
||||
|
||||
const actions = contentEl.createEl('div', { cls: 'data-fetcher-endpoint-editor-actions' });
|
||||
actions.createEl('button', { text: 'Cancel' }).addEventListener('click', () => this.close());
|
||||
actions.createEl('button', { text: 'Save', cls: 'mod-cta' }).addEventListener('click', () => {
|
||||
if (!this.endpoint.alias?.trim()) {
|
||||
new Notice('Alias is required.');
|
||||
return;
|
||||
}
|
||||
if (!this.endpoint.url?.trim()) {
|
||||
new Notice('URL is required.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.endpoint.type === 'graphql' || this.endpoint.type === 'grpc') {
|
||||
this.endpoint.method = 'POST';
|
||||
}
|
||||
|
||||
this.onSubmit({
|
||||
alias: this.endpoint.alias.trim(),
|
||||
type: this.endpoint.type,
|
||||
url: this.endpoint.url.trim(),
|
||||
method: this.endpoint.method || 'GET',
|
||||
headers: { ...(this.endpoint.headers || {}) }
|
||||
});
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.modalEl.removeClass('data-fetcher-endpoint-editor-modal');
|
||||
this.contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
||||
class CacheBrowserModal extends Modal {
|
||||
private cacheManager: CacheManager;
|
||||
private entriesContainer: HTMLElement;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "data-fetcher",
|
||||
"name": "Data Fetcher",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"minAppVersion": "1.8.3",
|
||||
"description": "Fetch data from multiple sources (REST APIs, RPC, gRPC, GraphQL) and insert results into notes",
|
||||
"author": "qf3l3k",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "obsidian-api-fetcher",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "obsidian-api-fetcher",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-api-fetcher",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"description": "Fetch data from multiple sources (REST APIs, RPC, gRPC, GraphQL) and insert results into notes",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
52
scripts/release-public.ps1
Normal file
52
scripts/release-public.ps1
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Version
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Require-CleanTree {
|
||||
$status = git status --porcelain
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to read git status."
|
||||
}
|
||||
$dirty = $status | Where-Object { $_ -notmatch '^\?\?\s+DEV_NOTES\.md$' }
|
||||
if ($dirty) {
|
||||
throw "Working tree is not clean. Commit/stash changes before running release script."
|
||||
}
|
||||
}
|
||||
|
||||
function Require-Ref([string]$RefName) {
|
||||
git rev-parse --verify $RefName *> $null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Missing required ref: $RefName"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "==> Releasing version $Version"
|
||||
Require-CleanTree
|
||||
|
||||
Write-Host "==> Internal release on origin/main"
|
||||
git checkout main
|
||||
git pull origin main
|
||||
cmd /c npx tsc -noEmit -skipLibCheck
|
||||
cmd /c npm run build
|
||||
git add manifest.json versions.json package.json package-lock.json CHANGELOG.md README.md
|
||||
git commit -m "release: $Version"
|
||||
git tag $Version
|
||||
git push origin main --tags
|
||||
|
||||
Write-Host "==> Preparing PR branch from public/main"
|
||||
git fetch public --tags
|
||||
Require-Ref "public/main"
|
||||
Require-Ref $Version
|
||||
|
||||
$branch = "public-fix-$Version"
|
||||
git checkout -B $branch public/main
|
||||
git checkout $Version -- manifest.json versions.json package.json package-lock.json
|
||||
git add manifest.json versions.json package.json package-lock.json
|
||||
git commit -m "public: bump release metadata to $Version"
|
||||
git push public $branch
|
||||
|
||||
Write-Host "==> Open PR:"
|
||||
Write-Host "https://github.com/qf3l3k/obsidian-data-fetcher/pull/new/$branch"
|
||||
55
scripts/release-public.sh
Normal file
55
scripts/release-public.sh
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <version>" >&2
|
||||
echo "Example: $0 1.0.7" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
V="$1"
|
||||
|
||||
require_clean_tree() {
|
||||
local dirty
|
||||
dirty="$(git status --porcelain | grep -vE '^\?\? DEV_NOTES\.md$' || true)"
|
||||
if [[ -n "$dirty" ]]; then
|
||||
echo "Working tree is not clean. Commit/stash changes before running release script." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_ref() {
|
||||
local ref="$1"
|
||||
if ! git rev-parse --verify "$ref" >/dev/null 2>&1; then
|
||||
echo "Missing required ref: $ref" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "==> Releasing version $V"
|
||||
require_clean_tree
|
||||
|
||||
echo "==> Internal release on origin/main"
|
||||
git checkout main
|
||||
git pull origin main
|
||||
npx tsc -noEmit -skipLibCheck
|
||||
npm run build
|
||||
git add manifest.json versions.json package.json package-lock.json CHANGELOG.md README.md
|
||||
git commit -m "release: $V"
|
||||
git tag "$V"
|
||||
git push origin main --tags
|
||||
|
||||
echo "==> Preparing PR branch from public/main"
|
||||
git fetch public --tags
|
||||
require_ref "public/main"
|
||||
require_ref "$V"
|
||||
|
||||
BRANCH="public-fix-$V"
|
||||
git checkout -B "$BRANCH" public/main
|
||||
git checkout "$V" -- manifest.json versions.json package.json package-lock.json
|
||||
git add manifest.json versions.json package.json package-lock.json
|
||||
git commit -m "public: bump release metadata to $V"
|
||||
git push public "$BRANCH"
|
||||
|
||||
echo "==> Open PR:"
|
||||
echo "https://github.com/qf3l3k/obsidian-data-fetcher/pull/new/$BRANCH"
|
||||
92
styles.css
92
styles.css
|
|
@ -129,18 +129,6 @@
|
|||
}
|
||||
|
||||
/* Settings styles */
|
||||
.endpoint-item {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 5px;
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.endpoint-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header-row {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
|
|
@ -151,6 +139,86 @@
|
|||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-table {
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 14px;
|
||||
font-size: var(--font-ui-smaller);
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(84px, 1fr) 72px minmax(140px, 2fr) 64px minmax(150px, 1.2fr);
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
padding: 7px 9px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-row-header {
|
||||
background-color: var(--background-secondary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-col {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-col-alias {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-col-actions {
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-actions button {
|
||||
font-size: var(--font-ui-smaller);
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-empty {
|
||||
color: var(--text-muted);
|
||||
padding: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-editor-modal {
|
||||
width: min(760px, 92vw);
|
||||
max-width: min(760px, 92vw);
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-editor-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.data-fetcher-endpoint-header-summary {
|
||||
margin-top: -4px;
|
||||
margin-bottom: 10px;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.data-fetcher-delete-btn {
|
||||
color: var(--text-error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@
|
|||
"1.0.7": "1.8.3",
|
||||
"1.0.8": "1.8.3",
|
||||
"1.0.9": "1.8.3",
|
||||
"1.1.0": "1.8.3"
|
||||
"1.1.0": "1.8.3",
|
||||
"1.1.1": "1.8.3"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue