mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-01 06:22:44 -08:00
fix(anki): harden proxy auto-enrichment and docs
This commit is contained in:
@@ -27,6 +27,7 @@ Scope: Current unmerged working-tree changes implement an optional local AnkiCon
|
|||||||
|
|
||||||
Delivered behavior:
|
Delivered behavior:
|
||||||
- Added proxy server that forwards AnkiConnect requests and enqueues addNote/addNotes note IDs for post-create enrichment, with de-duplication and loop-configuration protection.
|
- Added proxy server that forwards AnkiConnect requests and enqueues addNote/addNotes note IDs for post-create enrichment, with de-duplication and loop-configuration protection.
|
||||||
|
- Added follow-up response-shape compatibility handling so proxy enqueue works for both envelope (`{result,error}`) and bare JSON payloads, including `multi` variants.
|
||||||
- Added config schema/defaults/resolution for ankiConnect.proxy (enabled, host, port, upstreamUrl) with validation warnings and fallback behavior.
|
- Added config schema/defaults/resolution for ankiConnect.proxy (enabled, host, port, upstreamUrl) with validation warnings and fallback behavior.
|
||||||
- Runtime now supports transport switching (polling vs proxy) and restarts transport when runtime config patches change transport keys.
|
- Runtime now supports transport switching (polling vs proxy) and restarts transport when runtime config patches change transport keys.
|
||||||
- Added Yomitan default-profile server sync helper to keep bundled parser profile aligned with configured Anki endpoint.
|
- Added Yomitan default-profile server sync helper to keep bundled parser profile aligned with configured Anki endpoint.
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
"logging": {
|
"logging": {
|
||||||
"level": "info" // Minimum log level for runtime logging. Values: debug | info | warn | error
|
"level": "info" // Minimum log level for runtime logging. Values: debug | info | warn | error
|
||||||
}, // Controls logging verbosity.
|
}, // Controls logging verbosity. Keep this as an object; do not replace with a bare string.
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// Keyboard Shortcuts
|
// Keyboard Shortcuts
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ AnkiConnect listens on `http://127.0.0.1:8765` by default. If you changed the po
|
|||||||
|
|
||||||
SubMiner supports two auto-enrichment transport modes:
|
SubMiner supports two auto-enrichment transport modes:
|
||||||
|
|
||||||
1. `proxy` (default): runs a local AnkiConnect-compatible proxy and enriches cards immediately after successful `addNote` / `addNotes` responses.
|
1. `proxy` (default): runs a local AnkiConnect-compatible proxy and enriches cards immediately after successful `addNote` / `addNotes` / `multi` responses.
|
||||||
2. `polling`: polls AnkiConnect at `ankiConnect.pollingRate` (default: 3s).
|
2. `polling`: polls AnkiConnect at `ankiConnect.pollingRate` (default: 3s).
|
||||||
|
|
||||||
In both modes, the enrichment workflow is the same:
|
In both modes, the enrichment workflow is the same:
|
||||||
@@ -70,6 +70,39 @@ In Yomitan, go to Settings → Profile and:
|
|||||||
|
|
||||||
This is only for non-bundled, external/browser Yomitan or other clients. The bundled profile auto-update logic only targets `profiles[0]` when it is blank or still default.
|
This is only for non-bundled, external/browser Yomitan or other clients. The bundled profile auto-update logic only targets `profiles[0]` when it is blank or still default.
|
||||||
|
|
||||||
|
### Proxy Troubleshooting (quick checks)
|
||||||
|
|
||||||
|
If auto-enrichment appears to do nothing:
|
||||||
|
|
||||||
|
1. Confirm proxy listener is running while SubMiner is active:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ss -ltnp | rg 8766
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Confirm requests can pass through the proxy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sS http://127.0.0.1:8766 \
|
||||||
|
-H 'content-type: application/json' \
|
||||||
|
-d '{"action":"version","version":2}'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check both log sinks:
|
||||||
|
|
||||||
|
- Launcher/mpv-integrated log: `~/.cache/SubMiner/mp.log`
|
||||||
|
- App runtime log: `~/.config/SubMiner/logs/SubMiner-YYYY-MM-DD.log`
|
||||||
|
|
||||||
|
4. Ensure config JSONC is valid and logging shape is correct:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"logging": {
|
||||||
|
"level": "debug"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`"logging": "debug"` is invalid for current schema and can break reload/start behavior.
|
||||||
|
|
||||||
## Field Mapping
|
## Field Mapping
|
||||||
|
|
||||||
SubMiner maps its data to your Anki note fields. Configure these under `ankiConnect.fields`:
|
SubMiner maps its data to your Anki note fields. Configure these under `ankiConnect.fields`:
|
||||||
|
|||||||
@@ -243,6 +243,9 @@ export class AnkiIntegration {
|
|||||||
return new AnkiConnectProxyServer({
|
return new AnkiConnectProxyServer({
|
||||||
shouldAutoUpdateNewCards: () => this.config.behavior?.autoUpdateNewCards !== false,
|
shouldAutoUpdateNewCards: () => this.config.behavior?.autoUpdateNewCards !== false,
|
||||||
processNewCard: (noteId: number) => this.processNewCard(noteId),
|
processNewCard: (noteId: number) => this.processNewCard(noteId),
|
||||||
|
getDeck: () => this.config.deck,
|
||||||
|
findNotes: async (query, options) =>
|
||||||
|
(await this.client.findNotes(query, options)) as number[],
|
||||||
logInfo: (message, ...args) => log.info(message, ...args),
|
logInfo: (message, ...args) => log.info(message, ...args),
|
||||||
logWarn: (message, ...args) => log.warn(message, ...args),
|
logWarn: (message, ...args) => log.warn(message, ...args),
|
||||||
logError: (message, ...args) => log.error(message, ...args),
|
logError: (message, ...args) => log.error(message, ...args),
|
||||||
|
|||||||
@@ -38,6 +38,26 @@ test('proxy enqueues addNote result for enrichment', async () => {
|
|||||||
assert.deepEqual(processed, [42]);
|
assert.deepEqual(processed, [42]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('proxy enqueues addNote bare numeric response for enrichment', async () => {
|
||||||
|
const processed: number[] = [];
|
||||||
|
const proxy = new AnkiConnectProxyServer({
|
||||||
|
shouldAutoUpdateNewCards: () => true,
|
||||||
|
processNewCard: async (noteId) => {
|
||||||
|
processed.push(noteId);
|
||||||
|
},
|
||||||
|
logInfo: () => undefined,
|
||||||
|
logWarn: () => undefined,
|
||||||
|
logError: () => undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
(proxy as unknown as {
|
||||||
|
maybeEnqueueFromRequest: (request: Record<string, unknown>, responseBody: Buffer) => void;
|
||||||
|
}).maybeEnqueueFromRequest({ action: 'addNote' }, Buffer.from('42', 'utf8'));
|
||||||
|
|
||||||
|
await waitForCondition(() => processed.length === 1);
|
||||||
|
assert.deepEqual(processed, [42]);
|
||||||
|
});
|
||||||
|
|
||||||
test('proxy de-duplicates addNotes IDs within the same response', async () => {
|
test('proxy de-duplicates addNotes IDs within the same response', async () => {
|
||||||
const processed: number[] = [];
|
const processed: number[] = [];
|
||||||
const proxy = new AnkiConnectProxyServer({
|
const proxy = new AnkiConnectProxyServer({
|
||||||
@@ -62,6 +82,108 @@ test('proxy de-duplicates addNotes IDs within the same response', async () => {
|
|||||||
assert.deepEqual(processed, [101, 102]);
|
assert.deepEqual(processed, [101, 102]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('proxy enqueues note IDs from multi action addNote/addNotes results', async () => {
|
||||||
|
const processed: number[] = [];
|
||||||
|
const proxy = new AnkiConnectProxyServer({
|
||||||
|
shouldAutoUpdateNewCards: () => true,
|
||||||
|
processNewCard: async (noteId) => {
|
||||||
|
processed.push(noteId);
|
||||||
|
},
|
||||||
|
logInfo: () => undefined,
|
||||||
|
logWarn: () => undefined,
|
||||||
|
logError: () => undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
(proxy as unknown as {
|
||||||
|
maybeEnqueueFromRequest: (request: Record<string, unknown>, responseBody: Buffer) => void;
|
||||||
|
}).maybeEnqueueFromRequest(
|
||||||
|
{
|
||||||
|
action: 'multi',
|
||||||
|
params: {
|
||||||
|
actions: [
|
||||||
|
{ action: 'version' },
|
||||||
|
{ action: 'addNote' },
|
||||||
|
{ action: 'addNotes' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Buffer.from(JSON.stringify({ result: [6, 777, [888, 777, null]], error: null }), 'utf8'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForCondition(() => processed.length === 2);
|
||||||
|
assert.deepEqual(processed, [777, 888]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('proxy enqueues note IDs from bare multi action results', async () => {
|
||||||
|
const processed: number[] = [];
|
||||||
|
const proxy = new AnkiConnectProxyServer({
|
||||||
|
shouldAutoUpdateNewCards: () => true,
|
||||||
|
processNewCard: async (noteId) => {
|
||||||
|
processed.push(noteId);
|
||||||
|
},
|
||||||
|
logInfo: () => undefined,
|
||||||
|
logWarn: () => undefined,
|
||||||
|
logError: () => undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
(proxy as unknown as {
|
||||||
|
maybeEnqueueFromRequest: (request: Record<string, unknown>, responseBody: Buffer) => void;
|
||||||
|
}).maybeEnqueueFromRequest(
|
||||||
|
{
|
||||||
|
action: 'multi',
|
||||||
|
params: {
|
||||||
|
actions: [{ action: 'version' }, { action: 'addNote' }, { action: 'addNotes' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Buffer.from(JSON.stringify([6, 777, [888, null]]), 'utf8'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForCondition(() => processed.length === 2);
|
||||||
|
assert.deepEqual(processed, [777, 888]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('proxy enqueues note IDs from multi action envelope results', async () => {
|
||||||
|
const processed: number[] = [];
|
||||||
|
const proxy = new AnkiConnectProxyServer({
|
||||||
|
shouldAutoUpdateNewCards: () => true,
|
||||||
|
processNewCard: async (noteId) => {
|
||||||
|
processed.push(noteId);
|
||||||
|
},
|
||||||
|
logInfo: () => undefined,
|
||||||
|
logWarn: () => undefined,
|
||||||
|
logError: () => undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
(proxy as unknown as {
|
||||||
|
maybeEnqueueFromRequest: (request: Record<string, unknown>, responseBody: Buffer) => void;
|
||||||
|
}).maybeEnqueueFromRequest(
|
||||||
|
{
|
||||||
|
action: 'multi',
|
||||||
|
params: {
|
||||||
|
actions: [
|
||||||
|
{ action: 'version' },
|
||||||
|
{ action: 'addNote' },
|
||||||
|
{ action: 'addNotes' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Buffer.from(
|
||||||
|
JSON.stringify({
|
||||||
|
result: [
|
||||||
|
{ result: 6, error: null },
|
||||||
|
{ result: 777, error: null },
|
||||||
|
{ result: [888, 777, null], error: null },
|
||||||
|
],
|
||||||
|
error: null,
|
||||||
|
}),
|
||||||
|
'utf8',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForCondition(() => processed.length === 2);
|
||||||
|
assert.deepEqual(processed, [777, 888]);
|
||||||
|
});
|
||||||
|
|
||||||
test('proxy skips auto-enrichment when auto-update is disabled', async () => {
|
test('proxy skips auto-enrichment when auto-update is disabled', async () => {
|
||||||
const processed: number[] = [];
|
const processed: number[] = [];
|
||||||
const proxy = new AnkiConnectProxyServer({
|
const proxy = new AnkiConnectProxyServer({
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ interface AnkiConnectEnvelope {
|
|||||||
export interface AnkiConnectProxyServerDeps {
|
export interface AnkiConnectProxyServerDeps {
|
||||||
shouldAutoUpdateNewCards: () => boolean;
|
shouldAutoUpdateNewCards: () => boolean;
|
||||||
processNewCard: (noteId: number) => Promise<void>;
|
processNewCard: (noteId: number) => Promise<void>;
|
||||||
|
getDeck?: () => string | undefined;
|
||||||
|
findNotes?: (
|
||||||
|
query: string,
|
||||||
|
options?: {
|
||||||
|
maxRetries?: number;
|
||||||
|
},
|
||||||
|
) => Promise<number[]>;
|
||||||
logInfo: (message: string, ...args: unknown[]) => void;
|
logInfo: (message: string, ...args: unknown[]) => void;
|
||||||
logWarn: (message: string, ...args: unknown[]) => void;
|
logWarn: (message: string, ...args: unknown[]) => void;
|
||||||
logError: (message: string, ...args: unknown[]) => void;
|
logError: (message: string, ...args: unknown[]) => void;
|
||||||
@@ -169,26 +176,118 @@ export class AnkiConnectProxyServer {
|
|||||||
|
|
||||||
const action =
|
const action =
|
||||||
typeof requestJson.action === 'string' ? requestJson.action : String(requestJson.action ?? '');
|
typeof requestJson.action === 'string' ? requestJson.action : String(requestJson.action ?? '');
|
||||||
if (action !== 'addNote' && action !== 'addNotes') {
|
if (action !== 'addNote' && action !== 'addNotes' && action !== 'multi') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const responseJson = this.tryParseJson(responseBody) as AnkiConnectEnvelope | null;
|
const parsedResponse = this.tryParseJsonValue(responseBody);
|
||||||
if (!responseJson || responseJson.error !== null) {
|
if (parsedResponse === null || parsedResponse === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseResult = this.extractSuccessfulResult(parsedResponse);
|
||||||
|
if (responseResult === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteIds =
|
const noteIds =
|
||||||
action === 'addNote'
|
action === 'multi'
|
||||||
? this.collectSingleResultId(responseJson.result)
|
? this.collectMultiResultIds(requestJson, responseResult)
|
||||||
: this.collectBatchResultIds(responseJson.result);
|
: this.collectNoteIdsForAction(action, responseResult);
|
||||||
if (noteIds.length === 0) {
|
if (noteIds.length === 0) {
|
||||||
|
void this.enqueueMostRecentAddedNote();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.enqueueNotes(noteIds);
|
this.enqueueNotes(noteIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async enqueueMostRecentAddedNote(): Promise<void> {
|
||||||
|
const findNotes = this.deps.findNotes;
|
||||||
|
if (!findNotes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const deck = this.deps.getDeck ? this.deps.getDeck() : undefined;
|
||||||
|
const query = deck ? `"deck:${deck}" added:1` : 'added:1';
|
||||||
|
const noteIds = await findNotes(query, { maxRetries: 0 });
|
||||||
|
if (!noteIds || noteIds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const latestNoteId = Math.max(...noteIds);
|
||||||
|
this.deps.logInfo(
|
||||||
|
`[anki-proxy] Falling back to latest added note ${latestNoteId} (response did not include note IDs)`,
|
||||||
|
);
|
||||||
|
this.enqueueNotes([latestNoteId]);
|
||||||
|
} catch (error) {
|
||||||
|
this.deps.logWarn(
|
||||||
|
'[anki-proxy] Failed latest-note fallback lookup:',
|
||||||
|
(error as Error).message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private collectNoteIdsForAction(action: string, result: unknown): number[] {
|
||||||
|
if (action === 'addNote') {
|
||||||
|
return this.collectSingleResultId(result);
|
||||||
|
}
|
||||||
|
if (action === 'addNotes') {
|
||||||
|
return this.collectBatchResultIds(result);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private collectMultiResultIds(requestJson: Record<string, unknown>, result: unknown): number[] {
|
||||||
|
if (!Array.isArray(result)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const params =
|
||||||
|
requestJson.params && typeof requestJson.params === 'object'
|
||||||
|
? (requestJson.params as Record<string, unknown>)
|
||||||
|
: null;
|
||||||
|
const actions = Array.isArray(params?.actions) ? params.actions : [];
|
||||||
|
if (actions.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteIds: number[] = [];
|
||||||
|
const count = Math.min(actions.length, result.length);
|
||||||
|
for (let index = 0; index < count; index += 1) {
|
||||||
|
const actionEntry = actions[index];
|
||||||
|
if (!actionEntry || typeof actionEntry !== 'object') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const actionName =
|
||||||
|
typeof (actionEntry as Record<string, unknown>).action === 'string'
|
||||||
|
? ((actionEntry as Record<string, unknown>).action as string)
|
||||||
|
: '';
|
||||||
|
const actionResult = this.extractMultiActionResult(result[index]);
|
||||||
|
if (actionResult === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
noteIds.push(...this.collectNoteIdsForAction(actionName, actionResult));
|
||||||
|
}
|
||||||
|
return noteIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractMultiActionResult(value: unknown): unknown | null {
|
||||||
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const envelope = value as Record<string, unknown>;
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(envelope, 'result')) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (envelope.error !== null && envelope.error !== undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return envelope.result;
|
||||||
|
}
|
||||||
|
|
||||||
private collectSingleResultId(value: unknown): number[] {
|
private collectSingleResultId(value: unknown): number[] {
|
||||||
if (typeof value === 'number' && Number.isInteger(value) && value > 0) {
|
if (typeof value === 'number' && Number.isInteger(value) && value > 0) {
|
||||||
return [value];
|
return [value];
|
||||||
@@ -284,6 +383,32 @@ export class AnkiConnectProxyServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private tryParseJsonValue(rawBody: Buffer): unknown {
|
||||||
|
if (rawBody.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JSON.parse(rawBody.toString('utf8'));
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractSuccessfulResult(value: unknown): unknown | null {
|
||||||
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const envelope = value as Partial<AnkiConnectEnvelope>;
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(envelope, 'result')) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (envelope.error !== null && envelope.error !== undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return envelope.result;
|
||||||
|
}
|
||||||
|
|
||||||
private setCorsHeaders(res: ServerResponse<IncomingMessage>): void {
|
private setCorsHeaders(res: ServerResponse<IncomingMessage>): void {
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
|||||||
@@ -91,10 +91,14 @@ export class NoteUpdateWorkflow {
|
|||||||
this.deps.appendKnownWordsFromNoteInfo(noteInfo);
|
this.deps.appendKnownWordsFromNoteInfo(noteInfo);
|
||||||
const fields = this.deps.extractFields(noteInfo.fields);
|
const fields = this.deps.extractFields(noteInfo.fields);
|
||||||
|
|
||||||
const expressionText = fields.expression || fields.word || '';
|
const expressionText = (fields.expression || fields.word || '').trim();
|
||||||
if (!expressionText) {
|
const hasExpressionText = expressionText.length > 0;
|
||||||
this.deps.logWarn('No expression/word field found in card:', noteId);
|
if (!hasExpressionText) {
|
||||||
return;
|
// Some note types omit Expression/Word; still run enrichment updates and skip duplicate checks.
|
||||||
|
this.deps.logWarn(
|
||||||
|
'No expression/word field found in card; skipping duplicate checks but continuing update:',
|
||||||
|
noteId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sentenceCardConfig = this.deps.getEffectiveSentenceCardConfig();
|
const sentenceCardConfig = this.deps.getEffectiveSentenceCardConfig();
|
||||||
@@ -103,7 +107,7 @@ export class NoteUpdateWorkflow {
|
|||||||
sentenceCardConfig.kikuEnabled &&
|
sentenceCardConfig.kikuEnabled &&
|
||||||
sentenceCardConfig.kikuFieldGrouping !== 'disabled';
|
sentenceCardConfig.kikuFieldGrouping !== 'disabled';
|
||||||
let duplicateNoteId: number | null = null;
|
let duplicateNoteId: number | null = null;
|
||||||
if (shouldRunFieldGrouping) {
|
if (shouldRunFieldGrouping && hasExpressionText) {
|
||||||
duplicateNoteId = await this.deps.findDuplicateNote(expressionText, noteId, noteInfo);
|
duplicateNoteId = await this.deps.findDuplicateNote(expressionText, noteId, noteInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,11 +199,11 @@ export class NoteUpdateWorkflow {
|
|||||||
if (updatePerformed) {
|
if (updatePerformed) {
|
||||||
await this.deps.client.updateNoteFields(noteId, updatedFields);
|
await this.deps.client.updateNoteFields(noteId, updatedFields);
|
||||||
await this.deps.addConfiguredTagsToNote(noteId);
|
await this.deps.addConfiguredTagsToNote(noteId);
|
||||||
this.deps.logInfo('Updated card fields for:', expressionText);
|
this.deps.logInfo('Updated card fields for:', hasExpressionText ? expressionText : noteId);
|
||||||
await this.deps.showNotification(noteId, expressionText);
|
await this.deps.showNotification(noteId, hasExpressionText ? expressionText : noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldRunFieldGrouping && duplicateNoteId !== null) {
|
if (shouldRunFieldGrouping && hasExpressionText && duplicateNoteId !== null) {
|
||||||
let noteInfoForGrouping = noteInfo;
|
let noteInfoForGrouping = noteInfo;
|
||||||
if (updatePerformed) {
|
if (updatePerformed) {
|
||||||
const refreshedInfoResult = await this.deps.client.notesInfo([noteId]);
|
const refreshedInfoResult = await this.deps.client.notesInfo([noteId]);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const INTEGRATIONS_DEFAULT_CONFIG: Pick<
|
|||||||
url: 'http://127.0.0.1:8765',
|
url: 'http://127.0.0.1:8765',
|
||||||
pollingRate: 3000,
|
pollingRate: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
enabled: false,
|
enabled: true,
|
||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: 8766,
|
port: 8766,
|
||||||
upstreamUrl: 'http://127.0.0.1:8765',
|
upstreamUrl: 'http://127.0.0.1:8765',
|
||||||
|
|||||||
Reference in New Issue
Block a user