fix: localize Browser materials workflow
This commit is contained in:
parent
a1b3c31d0d
commit
99172944a1
|
|
@ -1,5 +1,5 @@
|
||||||
/* ===========================================================
|
/* ===========================================================
|
||||||
Browser Inbox Plugin — Verstak v2 Frontend Bundle
|
Browser Plugin — Verstak v2 Frontend Bundle
|
||||||
Contract: window.VerstakPluginRegister(id, { components })
|
Contract: window.VerstakPluginRegister(id, { components })
|
||||||
=========================================================== */
|
=========================================================== */
|
||||||
|
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
function scopeFromProps(props) {
|
function scopeFromProps(props) {
|
||||||
var workspaceRoot = workspaceFromProps(props);
|
var workspaceRoot = workspaceFromProps(props);
|
||||||
if (!workspaceRoot) {
|
if (!workspaceRoot) {
|
||||||
return { mode: 'global', key: GLOBAL_KEY, label: 'All workspaces', workspaceRoot: '' };
|
return { mode: 'global', key: GLOBAL_KEY, label: '', workspaceRoot: '' };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
mode: 'workspace',
|
mode: 'workspace',
|
||||||
|
|
@ -161,13 +161,13 @@
|
||||||
return value === 'selection' || value === 'link' || value === 'file' || value === 'page' ? value : 'page';
|
return value === 'selection' || value === 'link' || value === 'file' || value === 'page' ? value : 'page';
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayTitle(capture) {
|
function displayTitle(capture, fallbackTitle) {
|
||||||
if (capture && capture.kind === 'file' && capture.fileName) return capture.fileName;
|
if (capture && capture.kind === 'file' && capture.fileName) return capture.fileName;
|
||||||
return capture.title || capture.url || capture.captureId || 'Untitled capture';
|
return capture.title || capture.url || capture.captureId || fallbackTitle || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function noteTitle(capture) {
|
function noteTitle(capture, fallbackTitle) {
|
||||||
return text((capture && (capture.title || capture.domain || capture.captureId)) || 'Browser Capture').trim() || 'Browser Capture';
|
return text((capture && (capture.title || capture.domain || capture.captureId)) || fallbackTitle).trim() || text(fallbackTitle).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function safeNoteFilename(title) {
|
function safeNoteFilename(title) {
|
||||||
|
|
@ -199,8 +199,8 @@
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
function captureToMarkdown(capture) {
|
function captureToMarkdown(capture, fallbackTitle) {
|
||||||
var title = noteTitle(capture);
|
var title = noteTitle(capture, fallbackTitle);
|
||||||
var lines = ['# ' + title, ''];
|
var lines = ['# ' + title, ''];
|
||||||
if (capture && capture.url) lines.push('Source: ' + capture.url);
|
if (capture && capture.url) lines.push('Source: ' + capture.url);
|
||||||
if (capture && capture.capturedAt) lines.push('Captured: ' + capture.capturedAt);
|
if (capture && capture.capturedAt) lines.push('Captured: ' + capture.capturedAt);
|
||||||
|
|
@ -363,7 +363,7 @@
|
||||||
var scope = scopeFromProps(props || {});
|
var scope = scopeFromProps(props || {});
|
||||||
var captures = [];
|
var captures = [];
|
||||||
var selectedId = '';
|
var selectedId = '';
|
||||||
var statusText = 'Connecting to receiver events...';
|
var statusText = '';
|
||||||
var statusClass = '';
|
var statusClass = '';
|
||||||
var disposed = false;
|
var disposed = false;
|
||||||
var unsubscribers = [];
|
var unsubscribers = [];
|
||||||
|
|
@ -377,6 +377,18 @@
|
||||||
return fallback || key;
|
return fallback || key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function localizedItemCount(count) {
|
||||||
|
var locale = api && api.i18n && typeof api.i18n.getLocale === 'function' ? api.i18n.getLocale() : 'en';
|
||||||
|
if (locale === 'ru') {
|
||||||
|
var mod10 = count % 10;
|
||||||
|
var mod100 = count % 100;
|
||||||
|
if (mod10 === 1 && mod100 !== 11) return tr('ui.items.one', { count: count }, count + ' материал');
|
||||||
|
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return tr('ui.items.few', { count: count }, count + ' материала');
|
||||||
|
return tr('ui.items.many', { count: count }, count + ' материалов');
|
||||||
|
}
|
||||||
|
return tr(count === 1 ? 'ui.items.one' : 'ui.items.other', { count: count }, count + (count === 1 ? ' item' : ' items'));
|
||||||
|
}
|
||||||
|
|
||||||
function reportError(key, fallback, err) {
|
function reportError(key, fallback, err) {
|
||||||
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
||||||
console.warn('[verstak.browser-inbox] ' + key, err);
|
console.warn('[verstak.browser-inbox] ' + key, err);
|
||||||
|
|
@ -389,14 +401,14 @@
|
||||||
statusText = tr('ui.connecting', null, 'Connecting to receiver events...');
|
statusText = tr('ui.connecting', null, 'Connecting to receiver events...');
|
||||||
|
|
||||||
var toolbar = el('div', { className: 'browser-inbox-toolbar' });
|
var toolbar = el('div', { className: 'browser-inbox-toolbar' });
|
||||||
var titleEl = el('span', { className: 'browser-inbox-title', textContent: scope.mode === 'global' ? tr('ui.title', null, 'Browser Inbox') : tr('ui.workspaceTitle', { workspace: scope.label }, 'Browser Inbox · ' + scope.label) });
|
var titleEl = el('span', { className: 'browser-inbox-title', textContent: scope.mode === 'global' ? tr('ui.title', null, 'Browser') : tr('ui.workspaceTitle', { workspace: scope.label }, 'Browser · ' + scope.label) });
|
||||||
var countEl = el('span', { className: 'browser-inbox-count' });
|
var countEl = el('span', { className: 'browser-inbox-count' });
|
||||||
var statusEl = el('span', { className: 'browser-inbox-status' });
|
var statusEl = el('span', { className: 'browser-inbox-status' });
|
||||||
var filtersEl = el('div', { className: 'browser-inbox-filters' });
|
var filtersEl = el('div', { className: 'browser-inbox-filters' });
|
||||||
var statusFilterEl = el('select', {
|
var statusFilterEl = el('select', {
|
||||||
className: 'browser-inbox-select',
|
className: 'browser-inbox-select',
|
||||||
'data-browser-inbox-filter': 'status',
|
'data-browser-inbox-filter': 'status',
|
||||||
'aria-label': 'Capture status filter',
|
'aria-label': tr('ui.statusFilter', null, 'Material status filter'),
|
||||||
onChange: function (event) {
|
onChange: function (event) {
|
||||||
statusFilter = text(event && event.target && event.target.value) || 'all';
|
statusFilter = text(event && event.target && event.target.value) || 'all';
|
||||||
selectedId = '';
|
selectedId = '';
|
||||||
|
|
@ -412,7 +424,7 @@
|
||||||
var workspaceFilterEl = el('select', {
|
var workspaceFilterEl = el('select', {
|
||||||
className: 'browser-inbox-select',
|
className: 'browser-inbox-select',
|
||||||
'data-browser-inbox-filter': 'workspace',
|
'data-browser-inbox-filter': 'workspace',
|
||||||
'aria-label': 'Workspace filter',
|
'aria-label': tr('ui.workspaceFilter', null, 'Deal filter'),
|
||||||
onChange: function (event) {
|
onChange: function (event) {
|
||||||
workspaceFilter = cleanWorkspace(event && event.target && event.target.value);
|
workspaceFilter = cleanWorkspace(event && event.target && event.target.value);
|
||||||
selectedId = '';
|
selectedId = '';
|
||||||
|
|
@ -424,7 +436,7 @@
|
||||||
type: 'search',
|
type: 'search',
|
||||||
placeholder: tr('ui.search', null, 'Search captures'),
|
placeholder: tr('ui.search', null, 'Search captures'),
|
||||||
'data-browser-inbox-filter': 'search',
|
'data-browser-inbox-filter': 'search',
|
||||||
'aria-label': 'Search captures',
|
'aria-label': tr('ui.search', null, 'Search captures'),
|
||||||
onInput: function (event) {
|
onInput: function (event) {
|
||||||
searchQuery = text(event && event.target && event.target.value).trim().toLowerCase();
|
searchQuery = text(event && event.target && event.target.value).trim().toLowerCase();
|
||||||
selectedId = '';
|
selectedId = '';
|
||||||
|
|
@ -482,7 +494,7 @@
|
||||||
function renderWorkspaceFilterOptions() {
|
function renderWorkspaceFilterOptions() {
|
||||||
if (scope.mode !== 'global') return;
|
if (scope.mode !== 'global') return;
|
||||||
workspaceFilterEl.innerHTML = '';
|
workspaceFilterEl.innerHTML = '';
|
||||||
workspaceFilterEl.appendChild(option('', 'All workspaces'));
|
workspaceFilterEl.appendChild(option('', tr('ui.allDeals', null, 'All Deals')));
|
||||||
workspaceRoots().forEach(function (root) {
|
workspaceRoots().forEach(function (root) {
|
||||||
workspaceFilterEl.appendChild(option(root, root));
|
workspaceFilterEl.appendChild(option(root, root));
|
||||||
});
|
});
|
||||||
|
|
@ -506,7 +518,7 @@
|
||||||
|
|
||||||
function publishMutation(action, payload, verify, verifySettings) {
|
function publishMutation(action, payload, verify, verifySettings) {
|
||||||
if (!api || !api.events || typeof api.events.publish !== 'function') {
|
if (!api || !api.events || typeof api.events.publish !== 'function') {
|
||||||
reportError('ui.saveError', 'Could not update the browser inbox. Please try again.');
|
reportError('ui.saveError', 'Could not update browser materials. Please try again.');
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
return api.events.publish(MUTATION_EVENT, Object.assign({ action: action }, payload || {})).then(function () {
|
return api.events.publish(MUTATION_EVENT, Object.assign({ action: action }, payload || {})).then(function () {
|
||||||
|
|
@ -524,7 +536,7 @@
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
reportError('ui.saveError', 'Could not update the browser inbox. Please try again.', err);
|
reportError('ui.saveError', 'Could not update browser materials. Please try again.', err);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -551,7 +563,9 @@
|
||||||
var ids = scope.mode === 'global'
|
var ids = scope.mode === 'global'
|
||||||
? captures.map(function (capture) { return capture.captureId; })
|
? captures.map(function (capture) { return capture.captureId; })
|
||||||
: captures.filter(function (capture) { return capture.workspaceRootPath === scope.workspaceRoot; }).map(function (capture) { return capture.captureId; });
|
: captures.filter(function (capture) { return capture.workspaceRootPath === scope.workspaceRoot; }).map(function (capture) { return capture.captureId; });
|
||||||
return archiveCaptures(ids, scope.mode === 'global' ? 'Inbox archived' : 'Workspace captures archived');
|
return archiveCaptures(ids, scope.mode === 'global'
|
||||||
|
? tr('ui.inboxArchived', null, 'Inbox archived')
|
||||||
|
: tr('ui.workspaceCapturesArchived', null, 'Deal materials archived'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectedCapture() {
|
function selectedCapture() {
|
||||||
|
|
@ -569,10 +583,8 @@
|
||||||
});
|
});
|
||||||
if (existing) return Promise.resolve();
|
if (existing) return Promise.resolve();
|
||||||
selectedId = capture.captureId;
|
selectedId = capture.captureId;
|
||||||
statusText = 'Capture received';
|
statusText = tr('ui.captureReceived', null, 'Material received');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
statusText = 'Could not load received capture from storage';
|
|
||||||
statusClass = 'error';
|
|
||||||
render();
|
render();
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
@ -598,14 +610,16 @@
|
||||||
}).then(function (saved) {
|
}).then(function (saved) {
|
||||||
if (!saved) return;
|
if (!saved) return;
|
||||||
if (workspaceRoot && workspaceOptions.indexOf(workspaceRoot) === -1) workspaceOptions.push(workspaceRoot);
|
if (workspaceRoot && workspaceOptions.indexOf(workspaceRoot) === -1) workspaceOptions.push(workspaceRoot);
|
||||||
statusText = workspaceRoot ? 'Capture assigned to ' + workspaceRoot : 'Capture is unassigned';
|
statusText = workspaceRoot
|
||||||
|
? tr('ui.assignedToWorkspace', { workspace: workspaceRoot }, 'Material assigned to ' + workspaceRoot)
|
||||||
|
: tr('ui.captureUnassigned', null, 'Material is unassigned');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function archiveCapture(captureId) {
|
function archiveCapture(captureId) {
|
||||||
return archiveCaptures([captureId], 'Capture archived');
|
return archiveCaptures([captureId], tr('ui.captureArchived', null, 'Material archived'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreCapture(captureId) {
|
function restoreCapture(captureId) {
|
||||||
|
|
@ -615,7 +629,7 @@
|
||||||
});
|
});
|
||||||
}).then(function (saved) {
|
}).then(function (saved) {
|
||||||
if (!saved) return;
|
if (!saved) return;
|
||||||
statusText = 'Capture restored to Inbox';
|
statusText = tr('ui.captureRestored', null, 'Material restored to Inbox');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
@ -627,7 +641,7 @@
|
||||||
}).then(function (saved) {
|
}).then(function (saved) {
|
||||||
if (!saved) return;
|
if (!saved) return;
|
||||||
if (selectedId === captureId) selectedId = '';
|
if (selectedId === captureId) selectedId = '';
|
||||||
statusText = 'Capture permanently deleted';
|
statusText = tr('ui.captureDeleted', null, 'Material permanently deleted');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
@ -643,7 +657,9 @@
|
||||||
});
|
});
|
||||||
}).then(function (saved) {
|
}).then(function (saved) {
|
||||||
if (!saved) return;
|
if (!saved) return;
|
||||||
statusText = processed ? 'Capture marked processed' : 'Capture marked unprocessed';
|
statusText = processed
|
||||||
|
? tr('ui.captureProcessed', null, 'Material marked processed')
|
||||||
|
: tr('ui.captureUnprocessed', null, 'Material marked unprocessed');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
@ -655,12 +671,12 @@
|
||||||
reportError('ui.createNoteError', 'Could not create the note. Please try again.');
|
reportError('ui.createNoteError', 'Could not create the note. Please try again.');
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
var title = noteTitle(capture);
|
var title = noteTitle(capture, tr('ui.untitledCapture', null, 'Untitled material'));
|
||||||
var notePath = capture.workspaceRootPath + '/Notes/' + safeNoteFilename(title);
|
var notePath = capture.workspaceRootPath + '/Notes/' + safeNoteFilename(title);
|
||||||
statusText = 'Creating note...';
|
statusText = tr('ui.creatingNote', null, 'Creating note...');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
return api.files.writeText(notePath, captureToMarkdown(capture), {
|
return api.files.writeText(notePath, captureToMarkdown(capture, tr('ui.untitledCapture', null, 'Untitled material')), {
|
||||||
createIfMissing: true,
|
createIfMissing: true,
|
||||||
overwrite: false
|
overwrite: false
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
|
|
@ -677,7 +693,7 @@
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
statusText = 'Created note: ' + notePath;
|
statusText = tr('ui.noteCreated', { path: notePath }, 'Note created: ' + notePath);
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
return archiveCapture(capture.captureId);
|
return archiveCapture(capture.captureId);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
|
|
@ -691,8 +707,8 @@
|
||||||
reportError('ui.createLinkError', 'Could not create the link. Please try again.');
|
reportError('ui.createLinkError', 'Could not create the link. Please try again.');
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
var title = noteTitle(capture);
|
var title = noteTitle(capture, tr('ui.untitledCapture', null, 'Untitled material'));
|
||||||
statusText = 'Creating link...';
|
statusText = tr('ui.creatingLink', null, 'Creating link...');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
function writeLink(number) {
|
function writeLink(number) {
|
||||||
|
|
@ -725,7 +741,7 @@
|
||||||
}
|
}
|
||||||
return linkPath;
|
return linkPath;
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
statusText = 'Created link';
|
statusText = tr('ui.linkCreated', null, 'Link created');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
return archiveCapture(capture.captureId);
|
return archiveCapture(capture.captureId);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
|
|
@ -748,7 +764,7 @@
|
||||||
}
|
}
|
||||||
var fileName = safeFileFilename(capture.fileName);
|
var fileName = safeFileFilename(capture.fileName);
|
||||||
var filePath = capture.workspaceRootPath + '/Files/' + fileName;
|
var filePath = capture.workspaceRootPath + '/Files/' + fileName;
|
||||||
statusText = 'Creating file...';
|
statusText = tr('ui.creatingFile', null, 'Creating file...');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
var writeOptions = {
|
var writeOptions = {
|
||||||
|
|
@ -775,7 +791,7 @@
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
statusText = 'Created file: ' + filePath;
|
statusText = tr('ui.fileCreated', { path: filePath }, 'File created: ' + filePath);
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
return archiveCapture(capture.captureId);
|
return archiveCapture(capture.captureId);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
|
|
@ -788,8 +804,8 @@
|
||||||
var visible = visibleCaptures();
|
var visible = visibleCaptures();
|
||||||
if (visible.length === 0) {
|
if (visible.length === 0) {
|
||||||
var emptyText = captures.length === 0
|
var emptyText = captures.length === 0
|
||||||
? 'No browser captures yet. Keep this view open, then send a page, selection, or link from the extension.'
|
? tr('ui.empty', null, 'No browser materials yet. Send a page, selection, or link from the extension.')
|
||||||
: 'No captures match the current filters.';
|
: tr('ui.emptyFiltered', null, 'No materials match the current filters.');
|
||||||
listEl.appendChild(el('div', { className: 'browser-inbox-empty', textContent: emptyText }));
|
listEl.appendChild(el('div', { className: 'browser-inbox-empty', textContent: emptyText }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -805,20 +821,22 @@
|
||||||
}, [
|
}, [
|
||||||
el('div', { className: 'browser-inbox-row-head' }, [
|
el('div', { className: 'browser-inbox-row-head' }, [
|
||||||
el('span', { className: 'browser-inbox-kind', textContent: capture.kind }),
|
el('span', { className: 'browser-inbox-kind', textContent: capture.kind }),
|
||||||
el('span', { className: 'browser-inbox-row-title', textContent: displayTitle(capture) })
|
el('span', { className: 'browser-inbox-row-title', textContent: displayTitle(capture, tr('ui.untitledCapture', null, 'Untitled material')) })
|
||||||
]),
|
]),
|
||||||
el('div', { className: 'browser-inbox-row-url', textContent: capture.url || capture.domain || capture.captureId })
|
el('div', { className: 'browser-inbox-row-url', textContent: capture.url || capture.domain || capture.captureId })
|
||||||
]);
|
]);
|
||||||
row.appendChild(el('div', { className: 'browser-inbox-row-meta' }, [
|
row.appendChild(el('div', { className: 'browser-inbox-row-meta' }, [
|
||||||
el('span', {
|
el('span', {
|
||||||
className: 'browser-inbox-badge' + (workspaceRoot ? '' : ' unassigned'),
|
className: 'browser-inbox-badge' + (workspaceRoot ? '' : ' unassigned'),
|
||||||
textContent: workspaceRoot || 'Unassigned'
|
textContent: workspaceRoot || tr('ui.unassigned', null, 'Unassigned')
|
||||||
}),
|
}),
|
||||||
el('span', {
|
el('span', {
|
||||||
className: 'browser-inbox-badge' + (capture.processed ? ' processed' : ''),
|
className: 'browser-inbox-badge' + (capture.processed ? ' processed' : ''),
|
||||||
textContent: capture.processed ? 'Processed' : 'Unprocessed'
|
textContent: capture.processed
|
||||||
|
? tr('ui.processed', null, 'Processed')
|
||||||
|
: tr('ui.unprocessed', null, 'Unprocessed')
|
||||||
}),
|
}),
|
||||||
capture.globalState === 'archived' ? el('span', { className: 'browser-inbox-badge', textContent: 'Archived' }) : null
|
capture.globalState === 'archived' ? el('span', { className: 'browser-inbox-badge', textContent: tr('ui.archive', null, 'Archive') }) : null
|
||||||
]));
|
]));
|
||||||
if (capture.text) {
|
if (capture.text) {
|
||||||
row.appendChild(el('div', { className: 'browser-inbox-row-text', textContent: capture.text }));
|
row.appendChild(el('div', { className: 'browser-inbox-row-text', textContent: capture.text }));
|
||||||
|
|
@ -835,45 +853,47 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedId = capture.captureId;
|
selectedId = capture.captureId;
|
||||||
detailEl.appendChild(el('div', { className: 'browser-inbox-detail-title', textContent: displayTitle(capture) }));
|
detailEl.appendChild(el('div', { className: 'browser-inbox-detail-title', textContent: displayTitle(capture, tr('ui.untitledCapture', null, 'Untitled material')) }));
|
||||||
detailEl.appendChild(el('div', { className: 'browser-inbox-meta' }, [
|
detailEl.appendChild(el('div', { className: 'browser-inbox-meta' }, [
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.kind', null, 'Kind') }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.kind', null, 'Kind') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: capture.kind }),
|
el('div', { className: 'browser-inbox-meta-value', textContent: capture.kind }),
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: 'URL' }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.url', null, 'URL') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: capture.url || '-' }),
|
el('div', { className: 'browser-inbox-meta-value', textContent: capture.url || '-' }),
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.domain', null, 'Domain') }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.domain', null, 'Domain') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: capture.domain || '-' }),
|
el('div', { className: 'browser-inbox-meta-value', textContent: capture.domain || '-' }),
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.captured', null, 'Captured') }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.captured', null, 'Captured') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: formatDate(capture.capturedAt) || '-' }),
|
el('div', { className: 'browser-inbox-meta-value', textContent: formatDate(capture.capturedAt) || '-' }),
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: 'Browser' }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.browser', null, 'Browser') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: capture.browserName || capture.source || '-' }),
|
el('div', { className: 'browser-inbox-meta-value', textContent: capture.browserName || capture.source || '-' }),
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.workspace', null, 'Workspace') }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.workspace', null, 'Workspace') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: capture.workspaceRootPath || 'Unassigned' }),
|
el('div', { className: 'browser-inbox-meta-value', textContent: capture.workspaceRootPath || tr('ui.unassigned', null, 'Unassigned') }),
|
||||||
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.status', null, 'Status') }),
|
el('div', { className: 'browser-inbox-meta-label', textContent: tr('ui.status', null, 'Status') }),
|
||||||
el('div', { className: 'browser-inbox-meta-value', textContent: capture.processed ? 'Processed' : 'Unprocessed' })
|
el('div', { className: 'browser-inbox-meta-value', textContent: capture.processed
|
||||||
|
? tr('ui.processed', null, 'Processed')
|
||||||
|
: tr('ui.unprocessed', null, 'Unprocessed') })
|
||||||
]));
|
]));
|
||||||
var assignmentSelect = el('select', {
|
var assignmentSelect = el('select', {
|
||||||
className: 'browser-inbox-select',
|
className: 'browser-inbox-select',
|
||||||
'data-browser-inbox-assignment': capture.captureId,
|
'data-browser-inbox-assignment': capture.captureId,
|
||||||
'aria-label': 'Assign capture workspace',
|
'aria-label': tr('ui.assignment', null, 'Assign to Deal'),
|
||||||
onChange: function (event) {
|
onChange: function (event) {
|
||||||
assignWorkspace(capture.captureId, event && event.target && event.target.value);
|
assignWorkspace(capture.captureId, event && event.target && event.target.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assignmentSelect.appendChild(option('', 'Unassigned'));
|
assignmentSelect.appendChild(option('', tr('ui.unassigned', null, 'Unassigned')));
|
||||||
workspaceRoots().forEach(function (workspaceRoot) {
|
workspaceRoots().forEach(function (workspaceRoot) {
|
||||||
assignmentSelect.appendChild(option(workspaceRoot, workspaceRoot));
|
assignmentSelect.appendChild(option(workspaceRoot, workspaceRoot));
|
||||||
});
|
});
|
||||||
assignmentSelect.value = capture.workspaceRootPath || '';
|
assignmentSelect.value = capture.workspaceRootPath || '';
|
||||||
var assignmentControls = [
|
var assignmentControls = [
|
||||||
el('span', { className: 'browser-inbox-meta-label', textContent: 'Assign workspace' }),
|
el('span', { className: 'browser-inbox-meta-label', textContent: tr('ui.assignment', null, 'Assign to Deal') }),
|
||||||
assignmentSelect
|
assignmentSelect
|
||||||
];
|
];
|
||||||
if (capture.workspaceRootPath) {
|
if (capture.workspaceRootPath) {
|
||||||
assignmentControls.push(el('button', {
|
assignmentControls.push(el('button', {
|
||||||
className: 'browser-inbox-btn',
|
className: 'browser-inbox-btn',
|
||||||
'data-browser-inbox-action': 'clear-assignment',
|
'data-browser-inbox-action': 'clear-assignment',
|
||||||
textContent: 'Clear assignment',
|
textContent: tr('ui.clearAssignment', null, 'Clear assignment'),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
assignWorkspace(capture.captureId, '');
|
assignWorkspace(capture.captureId, '');
|
||||||
}
|
}
|
||||||
|
|
@ -881,7 +901,7 @@
|
||||||
}
|
}
|
||||||
detailEl.appendChild(el('div', { className: 'browser-inbox-assignment' }, assignmentControls));
|
detailEl.appendChild(el('div', { className: 'browser-inbox-assignment' }, assignmentControls));
|
||||||
if (!capture.workspaceRootPath) {
|
if (!capture.workspaceRootPath) {
|
||||||
detailEl.appendChild(el('div', { className: 'browser-inbox-detail-note', textContent: 'Assign a workspace before creating a note, link, or file.' }));
|
detailEl.appendChild(el('div', { className: 'browser-inbox-detail-note', textContent: tr('ui.assignBeforeCreation', null, 'Assign a Deal before creating a note, link, or file.') }));
|
||||||
}
|
}
|
||||||
if (capture.text) {
|
if (capture.text) {
|
||||||
detailEl.appendChild(el('div', { className: 'browser-inbox-text', textContent: capture.text }));
|
detailEl.appendChild(el('div', { className: 'browser-inbox-text', textContent: capture.text }));
|
||||||
|
|
@ -893,7 +913,9 @@
|
||||||
actionButtons.push(el('button', {
|
actionButtons.push(el('button', {
|
||||||
className: 'browser-inbox-btn',
|
className: 'browser-inbox-btn',
|
||||||
'data-browser-inbox-action': 'toggle-processed',
|
'data-browser-inbox-action': 'toggle-processed',
|
||||||
textContent: capture.processed ? 'Mark Unprocessed' : 'Mark Processed',
|
textContent: capture.processed
|
||||||
|
? tr('ui.markUnprocessed', null, 'Mark unprocessed')
|
||||||
|
: tr('ui.markProcessed', null, 'Mark processed'),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
setProcessed(capture.captureId, !capture.processed);
|
setProcessed(capture.captureId, !capture.processed);
|
||||||
}
|
}
|
||||||
|
|
@ -902,7 +924,7 @@
|
||||||
actionButtons.push(el('button', {
|
actionButtons.push(el('button', {
|
||||||
className: 'browser-inbox-btn',
|
className: 'browser-inbox-btn',
|
||||||
'data-browser-inbox-action': 'open-link',
|
'data-browser-inbox-action': 'open-link',
|
||||||
textContent: 'Open link',
|
textContent: tr('ui.openLink', null, 'Open link'),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
openCaptureURL(capture);
|
openCaptureURL(capture);
|
||||||
}
|
}
|
||||||
|
|
@ -942,7 +964,7 @@
|
||||||
actionButtons.push(el('button', {
|
actionButtons.push(el('button', {
|
||||||
className: 'browser-inbox-btn',
|
className: 'browser-inbox-btn',
|
||||||
'data-browser-inbox-action': 'restore',
|
'data-browser-inbox-action': 'restore',
|
||||||
textContent: 'Restore to Inbox',
|
textContent: tr('ui.restore', null, 'Restore to Inbox'),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
restoreCapture(capture.captureId);
|
restoreCapture(capture.captureId);
|
||||||
}
|
}
|
||||||
|
|
@ -951,7 +973,7 @@
|
||||||
actionButtons.push(el('button', {
|
actionButtons.push(el('button', {
|
||||||
className: 'browser-inbox-btn',
|
className: 'browser-inbox-btn',
|
||||||
'data-browser-inbox-action': 'archive',
|
'data-browser-inbox-action': 'archive',
|
||||||
textContent: 'Archive',
|
textContent: tr('ui.archive', null, 'Archive'),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
archiveCapture(capture.captureId);
|
archiveCapture(capture.captureId);
|
||||||
}
|
}
|
||||||
|
|
@ -960,7 +982,7 @@
|
||||||
actionButtons.push(el('button', {
|
actionButtons.push(el('button', {
|
||||||
className: 'browser-inbox-btn danger',
|
className: 'browser-inbox-btn danger',
|
||||||
'data-browser-inbox-action': 'delete-permanently',
|
'data-browser-inbox-action': 'delete-permanently',
|
||||||
textContent: 'Delete permanently',
|
textContent: tr('ui.deletePermanently', null, 'Delete permanently'),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
permanentlyDeleteCapture(capture.captureId);
|
permanentlyDeleteCapture(capture.captureId);
|
||||||
}
|
}
|
||||||
|
|
@ -972,8 +994,11 @@
|
||||||
var visibleCount = visibleCaptures().length;
|
var visibleCount = visibleCaptures().length;
|
||||||
var total = captures.length;
|
var total = captures.length;
|
||||||
countEl.textContent = visibleCount === total
|
countEl.textContent = visibleCount === total
|
||||||
? total + ' item' + (total === 1 ? '' : 's')
|
? localizedItemCount(total)
|
||||||
: visibleCount + ' of ' + total + ' items';
|
: tr('ui.items.filtered', {
|
||||||
|
visible: localizedItemCount(visibleCount),
|
||||||
|
total: localizedItemCount(total)
|
||||||
|
}, localizedItemCount(visibleCount) + ' of ' + localizedItemCount(total));
|
||||||
var scopeCount = scope.mode === 'global'
|
var scopeCount = scope.mode === 'global'
|
||||||
? total
|
? total
|
||||||
: captures.filter(function (capture) { return capture.workspaceRootPath === scope.workspaceRoot; }).length;
|
: captures.filter(function (capture) { return capture.workspaceRootPath === scope.workspaceRoot; }).length;
|
||||||
|
|
@ -1026,7 +1051,7 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
reportError('ui.loadError', 'Could not load the browser inbox. Please try again.', err);
|
reportError('ui.loadError', 'Could not load browser materials. Please try again.', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1066,13 +1091,13 @@
|
||||||
}).then(function (saved) {
|
}).then(function (saved) {
|
||||||
if (!saved) return;
|
if (!saved) return;
|
||||||
selectedId = received.captureId;
|
selectedId = received.captureId;
|
||||||
statusText = 'Capture received';
|
statusText = tr('ui.captureReceived', null, 'Material received');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
selectedId = received.captureId;
|
selectedId = received.captureId;
|
||||||
statusText = 'Capture received';
|
statusText = tr('ui.captureReceived', null, 'Material received');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
render();
|
render();
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
@ -1081,7 +1106,9 @@
|
||||||
if (typeof unsubscribe === 'function') unsubscribers.push(unsubscribe);
|
if (typeof unsubscribe === 'function') unsubscribers.push(unsubscribe);
|
||||||
});
|
});
|
||||||
})).then(function () {
|
})).then(function () {
|
||||||
statusText = scope.mode === 'global' ? 'Receiver ready for all workspaces' : 'Receiver ready for workspace';
|
statusText = scope.mode === 'global'
|
||||||
|
? tr('ui.receiverReadyAll', null, 'Receiver ready for all Deals')
|
||||||
|
: tr('ui.receiverReadyWorkspace', null, 'Receiver ready for this Deal');
|
||||||
statusClass = '';
|
statusClass = '';
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
reportError('ui.receiverError', 'The browser receiver is unavailable. Please try again.', err);
|
reportError('ui.receiverError', 'The browser receiver is unavailable. Please try again.', err);
|
||||||
|
|
@ -1098,8 +1125,11 @@
|
||||||
});
|
});
|
||||||
if (api && api.i18n && typeof api.i18n.onDidChangeLocale === 'function') {
|
if (api && api.i18n && typeof api.i18n.onDidChangeLocale === 'function') {
|
||||||
api.i18n.onDidChangeLocale(function () {
|
api.i18n.onDidChangeLocale(function () {
|
||||||
titleEl.textContent = scope.mode === 'global' ? tr('ui.title', null, 'Browser Inbox') : tr('ui.workspaceTitle', { workspace: scope.label }, 'Browser Inbox · ' + scope.label);
|
titleEl.textContent = scope.mode === 'global' ? tr('ui.title', null, 'Browser') : tr('ui.workspaceTitle', { workspace: scope.label }, 'Browser · ' + scope.label);
|
||||||
searchInput.setAttribute('placeholder', tr('ui.search', null, 'Search captures'));
|
searchInput.setAttribute('placeholder', tr('ui.search', null, 'Search captures'));
|
||||||
|
statusFilterEl.setAttribute('aria-label', tr('ui.statusFilter', null, 'Material status filter'));
|
||||||
|
workspaceFilterEl.setAttribute('aria-label', tr('ui.workspaceFilter', null, 'Deal filter'));
|
||||||
|
searchInput.setAttribute('aria-label', tr('ui.search', null, 'Search captures'));
|
||||||
clearBtn.textContent = tr('ui.clear', null, 'Clear');
|
clearBtn.textContent = tr('ui.clear', null, 'Clear');
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,26 @@
|
||||||
{
|
{
|
||||||
"manifest.name": "Browser Inbox",
|
"manifest.name": "Browser",
|
||||||
"manifest.description": "Global browser capture queue with explicit workspace assignment delivered through the local receiver event protocol.",
|
"manifest.description": "Global browser materials with explicit Deal assignment delivered through the local receiver event protocol.",
|
||||||
"contributions.views.verstak.browser-inbox.view.title": "Browser Inbox",
|
"contributions.views.verstak.browser-inbox.view.title": "Browser",
|
||||||
"contributions.sidebarItems.verstak.browser-inbox.sidebar.title": "Browser Inbox",
|
"contributions.sidebarItems.verstak.browser-inbox.sidebar.title": "Browser",
|
||||||
"contributions.workspaceItems.verstak.browser-inbox.workspace.title": "Browser Inbox",
|
"contributions.workspaceItems.verstak.browser-inbox.workspace.title": "Browser",
|
||||||
"contributions.settingsPanels.verstak.browser-inbox.settings.title": "Browser Inbox",
|
"contributions.settingsPanels.verstak.browser-inbox.settings.title": "Browser",
|
||||||
"ui.connecting": "Connecting to receiver events...",
|
"ui.connecting": "Connecting to receiver events...",
|
||||||
"ui.title": "Browser Inbox",
|
"ui.title": "Browser",
|
||||||
"ui.workspaceTitle": "Browser Inbox · {workspace}",
|
"ui.workspaceTitle": "Browser · {workspace}",
|
||||||
"ui.allCaptures": "All captures",
|
"ui.allCaptures": "All captures",
|
||||||
|
"ui.allDeals": "All Deals",
|
||||||
"ui.unassigned": "Unassigned",
|
"ui.unassigned": "Unassigned",
|
||||||
"ui.unprocessed": "Unprocessed",
|
"ui.unprocessed": "Unprocessed",
|
||||||
"ui.processed": "Processed",
|
"ui.processed": "Processed",
|
||||||
"ui.search": "Search captures",
|
"ui.search": "Search captures",
|
||||||
"ui.clear": "Clear",
|
"ui.clear": "Clear",
|
||||||
"ui.assignedHere": "Assigned to this workspace",
|
"ui.assignedHere": "Assigned to this Deal",
|
||||||
"ui.selectCapture": "Select a capture to inspect it.",
|
"ui.selectCapture": "Select a capture to inspect it.",
|
||||||
"ui.kind": "Kind",
|
"ui.kind": "Kind",
|
||||||
"ui.domain": "Domain",
|
"ui.domain": "Domain",
|
||||||
"ui.captured": "Captured",
|
"ui.captured": "Captured",
|
||||||
"ui.workspace": "Workspace",
|
"ui.workspace": "Deal",
|
||||||
"ui.status": "Status",
|
"ui.status": "Status",
|
||||||
"ui.createNote": "Create Note",
|
"ui.createNote": "Create Note",
|
||||||
"ui.createLink": "Create Link",
|
"ui.createLink": "Create Link",
|
||||||
|
|
@ -36,14 +37,54 @@
|
||||||
"ui.rotateConfirm": "Rotate pairing token?",
|
"ui.rotateConfirm": "Rotate pairing token?",
|
||||||
"ui.rotating": "Rotating...",
|
"ui.rotating": "Rotating...",
|
||||||
"ui.tokenRotated": "Token rotated",
|
"ui.tokenRotated": "Token rotated",
|
||||||
"ui.saveError": "Could not update the browser inbox. Please try again.",
|
"ui.saveError": "Could not update browser materials. Please try again.",
|
||||||
"ui.createNoteError": "Could not create the note. Please try again.",
|
"ui.createNoteError": "Could not create the note. Please try again.",
|
||||||
"ui.createLinkError": "Could not create the link. Please try again.",
|
"ui.createLinkError": "Could not create the link. Please try again.",
|
||||||
"ui.openLinkError": "Could not open the link. Please try again.",
|
"ui.openLinkError": "Could not open the link. Please try again.",
|
||||||
"ui.createFileError": "Could not create the file. Please try again.",
|
"ui.createFileError": "Could not create the file. Please try again.",
|
||||||
"ui.loadError": "Could not load the browser inbox. Please try again.",
|
"ui.loadError": "Could not load browser materials. Please try again.",
|
||||||
"ui.receiverError": "The browser receiver is unavailable. Please try again.",
|
"ui.receiverError": "The browser receiver is unavailable. Please try again.",
|
||||||
"ui.pairingLoadError": "Could not load browser connection settings. Please try again.",
|
"ui.pairingLoadError": "Could not load browser connection settings. Please try again.",
|
||||||
"ui.clipboardError": "Could not copy to the clipboard. Please try again.",
|
"ui.clipboardError": "Could not copy to the clipboard. Please try again.",
|
||||||
"ui.tokenRotateError": "Could not rotate the pairing token. Please try again."
|
"ui.tokenRotateError": "Could not rotate the pairing token. Please try again.",
|
||||||
|
"ui.statusFilter": "Material status filter",
|
||||||
|
"ui.workspaceFilter": "Deal filter",
|
||||||
|
"ui.assignment": "Assign to Deal",
|
||||||
|
"ui.clearAssignment": "Clear assignment",
|
||||||
|
"ui.empty": "No browser materials yet. Send a page, selection, or link from the extension.",
|
||||||
|
"ui.emptyFiltered": "No materials match the current filters.",
|
||||||
|
"ui.untitledCapture": "Untitled material",
|
||||||
|
"ui.url": "URL",
|
||||||
|
"ui.browser": "Browser",
|
||||||
|
"ui.assignBeforeCreation": "Assign a Deal before creating a note, link, or file.",
|
||||||
|
"ui.markProcessed": "Mark processed",
|
||||||
|
"ui.markUnprocessed": "Mark unprocessed",
|
||||||
|
"ui.openLink": "Open link",
|
||||||
|
"ui.restore": "Restore to Inbox",
|
||||||
|
"ui.archive": "Archive",
|
||||||
|
"ui.deletePermanently": "Delete permanently",
|
||||||
|
"ui.captureReceived": "Material received",
|
||||||
|
"ui.captureLoadError": "Could not load the received material.",
|
||||||
|
"ui.inboxArchived": "Inbox archived",
|
||||||
|
"ui.workspaceCapturesArchived": "Deal materials archived",
|
||||||
|
"ui.assignedToWorkspace": "Material assigned to {workspace}",
|
||||||
|
"ui.captureUnassigned": "Material is unassigned",
|
||||||
|
"ui.captureArchived": "Material archived",
|
||||||
|
"ui.captureRestored": "Material restored to Inbox",
|
||||||
|
"ui.captureDeleted": "Material permanently deleted",
|
||||||
|
"ui.captureProcessed": "Material marked processed",
|
||||||
|
"ui.captureUnprocessed": "Material marked unprocessed",
|
||||||
|
"ui.creatingNote": "Creating note...",
|
||||||
|
"ui.noteCreated": "Note created: {path}",
|
||||||
|
"ui.creatingLink": "Creating link...",
|
||||||
|
"ui.linkCreated": "Link created",
|
||||||
|
"ui.creatingFile": "Creating file...",
|
||||||
|
"ui.fileCreated": "File created: {path}",
|
||||||
|
"ui.receiverReadyAll": "Receiver ready for all Deals",
|
||||||
|
"ui.receiverReadyWorkspace": "Receiver ready for this Deal",
|
||||||
|
"ui.items.one": "{count} item",
|
||||||
|
"ui.items.few": "{count} items",
|
||||||
|
"ui.items.many": "{count} items",
|
||||||
|
"ui.items.other": "{count} items",
|
||||||
|
"ui.items.filtered": "{visible} of {total}"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,26 @@
|
||||||
{
|
{
|
||||||
"manifest.name": "Входящие из браузера",
|
"manifest.name": "Браузер",
|
||||||
"manifest.description": "Общая очередь материалов из браузера с явным назначением рабочего пространства через локальный протокол приёма.",
|
"manifest.description": "Общие материалы из браузера с явным назначением Дела через локальный протокол приёма.",
|
||||||
"contributions.views.verstak.browser-inbox.view.title": "Входящие из браузера",
|
"contributions.views.verstak.browser-inbox.view.title": "Браузер",
|
||||||
"contributions.sidebarItems.verstak.browser-inbox.sidebar.title": "Входящие из браузера",
|
"contributions.sidebarItems.verstak.browser-inbox.sidebar.title": "Браузер",
|
||||||
"contributions.workspaceItems.verstak.browser-inbox.workspace.title": "Входящие из браузера",
|
"contributions.workspaceItems.verstak.browser-inbox.workspace.title": "Браузер",
|
||||||
"contributions.settingsPanels.verstak.browser-inbox.settings.title": "Входящие из браузера",
|
"contributions.settingsPanels.verstak.browser-inbox.settings.title": "Браузер",
|
||||||
"ui.connecting": "Подключение к событиям приёмника...",
|
"ui.connecting": "Подключение к событиям приёмника...",
|
||||||
"ui.title": "Входящие из браузера",
|
"ui.title": "Браузер",
|
||||||
"ui.workspaceTitle": "Входящие из браузера · {workspace}",
|
"ui.workspaceTitle": "Браузер · {workspace}",
|
||||||
"ui.allCaptures": "Все материалы",
|
"ui.allCaptures": "Все материалы",
|
||||||
|
"ui.allDeals": "Все Дела",
|
||||||
"ui.unassigned": "Не назначено",
|
"ui.unassigned": "Не назначено",
|
||||||
"ui.unprocessed": "Не обработано",
|
"ui.unprocessed": "Не обработано",
|
||||||
"ui.processed": "Обработано",
|
"ui.processed": "Обработано",
|
||||||
"ui.search": "Поиск материалов",
|
"ui.search": "Поиск материалов",
|
||||||
"ui.clear": "Очистить",
|
"ui.clear": "Очистить",
|
||||||
"ui.assignedHere": "Назначено этому рабочему пространству",
|
"ui.assignedHere": "Назначено этому Делу",
|
||||||
"ui.selectCapture": "Выберите материал для просмотра.",
|
"ui.selectCapture": "Выберите материал для просмотра.",
|
||||||
"ui.kind": "Тип",
|
"ui.kind": "Тип",
|
||||||
"ui.domain": "Домен",
|
"ui.domain": "Домен",
|
||||||
"ui.captured": "Получено",
|
"ui.captured": "Получено",
|
||||||
"ui.workspace": "Рабочее пространство",
|
"ui.workspace": "Дело",
|
||||||
"ui.status": "Состояние",
|
"ui.status": "Состояние",
|
||||||
"ui.createNote": "Создать заметку",
|
"ui.createNote": "Создать заметку",
|
||||||
"ui.createLink": "Создать ссылку",
|
"ui.createLink": "Создать ссылку",
|
||||||
|
|
@ -36,14 +37,54 @@
|
||||||
"ui.rotateConfirm": "Сменить токен сопряжения?",
|
"ui.rotateConfirm": "Сменить токен сопряжения?",
|
||||||
"ui.rotating": "Смена токена...",
|
"ui.rotating": "Смена токена...",
|
||||||
"ui.tokenRotated": "Токен изменён",
|
"ui.tokenRotated": "Токен изменён",
|
||||||
"ui.saveError": "Не удалось обновить входящие из браузера. Повторите попытку.",
|
"ui.saveError": "Не удалось обновить материалы браузера. Повторите попытку.",
|
||||||
"ui.createNoteError": "Не удалось создать заметку. Повторите попытку.",
|
"ui.createNoteError": "Не удалось создать заметку. Повторите попытку.",
|
||||||
"ui.createLinkError": "Не удалось создать ссылку. Повторите попытку.",
|
"ui.createLinkError": "Не удалось создать ссылку. Повторите попытку.",
|
||||||
"ui.openLinkError": "Не удалось открыть ссылку. Повторите попытку.",
|
"ui.openLinkError": "Не удалось открыть ссылку. Повторите попытку.",
|
||||||
"ui.createFileError": "Не удалось создать файл. Повторите попытку.",
|
"ui.createFileError": "Не удалось создать файл. Повторите попытку.",
|
||||||
"ui.loadError": "Не удалось загрузить входящие из браузера. Повторите попытку.",
|
"ui.loadError": "Не удалось загрузить материалы браузера. Повторите попытку.",
|
||||||
"ui.receiverError": "Приёмник браузера недоступен. Повторите попытку.",
|
"ui.receiverError": "Приёмник браузера недоступен. Повторите попытку.",
|
||||||
"ui.pairingLoadError": "Не удалось загрузить параметры подключения браузера. Повторите попытку.",
|
"ui.pairingLoadError": "Не удалось загрузить параметры подключения браузера. Повторите попытку.",
|
||||||
"ui.clipboardError": "Не удалось скопировать в буфер обмена. Повторите попытку.",
|
"ui.clipboardError": "Не удалось скопировать в буфер обмена. Повторите попытку.",
|
||||||
"ui.tokenRotateError": "Не удалось сменить токен сопряжения. Повторите попытку."
|
"ui.tokenRotateError": "Не удалось сменить токен сопряжения. Повторите попытку.",
|
||||||
|
"ui.statusFilter": "Фильтр состояния материала",
|
||||||
|
"ui.workspaceFilter": "Фильтр Дела",
|
||||||
|
"ui.assignment": "Назначить Делу",
|
||||||
|
"ui.clearAssignment": "Снять назначение",
|
||||||
|
"ui.empty": "Пока нет материалов из браузера. Отправьте страницу, выделенный текст или ссылку с помощью расширения.",
|
||||||
|
"ui.emptyFiltered": "Нет материалов по текущим фильтрам.",
|
||||||
|
"ui.untitledCapture": "Материал без названия",
|
||||||
|
"ui.url": "URL",
|
||||||
|
"ui.browser": "Браузер",
|
||||||
|
"ui.assignBeforeCreation": "Назначьте Дело перед созданием заметки, ссылки или файла.",
|
||||||
|
"ui.markProcessed": "Отметить обработанным",
|
||||||
|
"ui.markUnprocessed": "Отметить необработанным",
|
||||||
|
"ui.openLink": "Открыть ссылку",
|
||||||
|
"ui.restore": "Вернуть во входящие",
|
||||||
|
"ui.archive": "Архивировать",
|
||||||
|
"ui.deletePermanently": "Удалить навсегда",
|
||||||
|
"ui.captureReceived": "Материал получен",
|
||||||
|
"ui.captureLoadError": "Не удалось загрузить полученный материал.",
|
||||||
|
"ui.inboxArchived": "Входящие архивированы",
|
||||||
|
"ui.workspaceCapturesArchived": "Материалы Дела архивированы",
|
||||||
|
"ui.assignedToWorkspace": "Материал назначен Делу «{workspace}»",
|
||||||
|
"ui.captureUnassigned": "Материал не назначен",
|
||||||
|
"ui.captureArchived": "Материал архивирован",
|
||||||
|
"ui.captureRestored": "Материал возвращён во входящие",
|
||||||
|
"ui.captureDeleted": "Материал удалён навсегда",
|
||||||
|
"ui.captureProcessed": "Материал отмечен обработанным",
|
||||||
|
"ui.captureUnprocessed": "Материал отмечен необработанным",
|
||||||
|
"ui.creatingNote": "Создание заметки...",
|
||||||
|
"ui.noteCreated": "Заметка создана: {path}",
|
||||||
|
"ui.creatingLink": "Создание ссылки...",
|
||||||
|
"ui.linkCreated": "Ссылка создана",
|
||||||
|
"ui.creatingFile": "Создание файла...",
|
||||||
|
"ui.fileCreated": "Файл создан: {path}",
|
||||||
|
"ui.receiverReadyAll": "Приёмник готов для всех Дел",
|
||||||
|
"ui.receiverReadyWorkspace": "Приёмник готов для этого Дела",
|
||||||
|
"ui.items.one": "{count} материал",
|
||||||
|
"ui.items.few": "{count} материала",
|
||||||
|
"ui.items.many": "{count} материалов",
|
||||||
|
"ui.items.other": "{count} материала",
|
||||||
|
"ui.items.filtered": "{visible} из {total}"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "verstak.browser-inbox",
|
"id": "verstak.browser-inbox",
|
||||||
"name": "Browser Inbox",
|
"name": "Browser",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"apiVersion": "0.1.0",
|
"apiVersion": "0.1.0",
|
||||||
"description": "Global browser capture queue with explicit workspace assignment delivered through the local receiver event protocol.",
|
"description": "Global browser materials with explicit Deal assignment delivered through the local receiver event protocol.",
|
||||||
"localization": { "defaultLocale": "en", "locales": { "en": "locales/en.json", "ru": "locales/ru.json" } },
|
"localization": { "defaultLocale": "en", "locales": { "en": "locales/en.json", "ru": "locales/ru.json" } },
|
||||||
"source": "official",
|
"source": "official",
|
||||||
"icon": "inbox",
|
"icon": "inbox",
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"views": [
|
"views": [
|
||||||
{
|
{
|
||||||
"id": "verstak.browser-inbox.view",
|
"id": "verstak.browser-inbox.view",
|
||||||
"title": "Browser Inbox",
|
"title": "Browser",
|
||||||
"icon": "inbox",
|
"icon": "inbox",
|
||||||
"component": "BrowserInboxView"
|
"component": "BrowserInboxView"
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"sidebarItems": [
|
"sidebarItems": [
|
||||||
{
|
{
|
||||||
"id": "verstak.browser-inbox.sidebar",
|
"id": "verstak.browser-inbox.sidebar",
|
||||||
"title": "Browser Inbox",
|
"title": "Browser",
|
||||||
"icon": "inbox",
|
"icon": "inbox",
|
||||||
"view": "verstak.browser-inbox.view",
|
"view": "verstak.browser-inbox.view",
|
||||||
"position": 30
|
"position": 30
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
"workspaceItems": [
|
"workspaceItems": [
|
||||||
{
|
{
|
||||||
"id": "verstak.browser-inbox.workspace",
|
"id": "verstak.browser-inbox.workspace",
|
||||||
"title": "Browser Inbox",
|
"title": "Browser",
|
||||||
"icon": "inbox",
|
"icon": "inbox",
|
||||||
"component": "BrowserInboxView"
|
"component": "BrowserInboxView"
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
"settingsPanels": [
|
"settingsPanels": [
|
||||||
{
|
{
|
||||||
"id": "verstak.browser-inbox.settings",
|
"id": "verstak.browser-inbox.settings",
|
||||||
"title": "Browser Inbox",
|
"title": "Browser",
|
||||||
"component": "BrowserInboxSettings"
|
"component": "BrowserInboxSettings"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ const vm = require('vm');
|
||||||
const root = path.resolve(__dirname, '..');
|
const root = path.resolve(__dirname, '..');
|
||||||
const sourcePath = path.join(root, 'plugins', 'browser-inbox', 'frontend', 'src', 'index.js');
|
const sourcePath = path.join(root, 'plugins', 'browser-inbox', 'frontend', 'src', 'index.js');
|
||||||
const source = fs.readFileSync(sourcePath, 'utf8');
|
const source = fs.readFileSync(sourcePath, 'utf8');
|
||||||
|
const catalogs = {
|
||||||
|
en: JSON.parse(fs.readFileSync(path.join(root, 'plugins', 'browser-inbox', 'locales', 'en.json'), 'utf8')),
|
||||||
|
ru: JSON.parse(fs.readFileSync(path.join(root, 'plugins', 'browser-inbox', 'locales', 'ru.json'), 'utf8')),
|
||||||
|
};
|
||||||
const technicalErrors = [];
|
const technicalErrors = [];
|
||||||
|
|
||||||
class FakeNode {
|
class FakeNode {
|
||||||
|
|
@ -145,7 +149,7 @@ function loadComponent(document) {
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeApi(initialSettings = {}) {
|
function makeApi(initialSettings = {}, locale = 'en') {
|
||||||
const settings = { ...initialSettings };
|
const settings = { ...initialSettings };
|
||||||
const handlers = {};
|
const handlers = {};
|
||||||
const unsubscribed = [];
|
const unsubscribed = [];
|
||||||
|
|
@ -162,6 +166,13 @@ function makeApi(initialSettings = {}) {
|
||||||
receiverToken: 'initial-browser-token',
|
receiverToken: 'initial-browser-token',
|
||||||
};
|
};
|
||||||
let nextWriteError = null;
|
let nextWriteError = null;
|
||||||
|
function translate(key, params, fallback) {
|
||||||
|
let value = catalogs[locale]?.[key] || catalogs.en[key] || fallback || key;
|
||||||
|
Object.entries(params || {}).forEach(([name, replacement]) => {
|
||||||
|
value = value.replace(new RegExp(`\\{${name}\\}`, 'g'), String(replacement));
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
}
|
||||||
function backendCaptures() {
|
function backendCaptures() {
|
||||||
const keys = ['captures:global', 'captures', ...Object.keys(settings).filter((key) => key.startsWith('captures:workspace:'))];
|
const keys = ['captures:global', 'captures', ...Object.keys(settings).filter((key) => key.startsWith('captures:workspace:'))];
|
||||||
const seen = new Set();
|
const seen = new Set();
|
||||||
|
|
@ -214,6 +225,11 @@ function makeApi(initialSettings = {}) {
|
||||||
fileByteWrites,
|
fileByteWrites,
|
||||||
openedURLs,
|
openedURLs,
|
||||||
publishedEvents,
|
publishedEvents,
|
||||||
|
i18n: {
|
||||||
|
getLocale: () => locale,
|
||||||
|
t: translate,
|
||||||
|
onDidChangeLocale: () => () => {},
|
||||||
|
},
|
||||||
failNextWrite(message) {
|
failNextWrite(message) {
|
||||||
nextWriteError = new Error(message || 'write failed');
|
nextWriteError = new Error(message || 'write failed');
|
||||||
},
|
},
|
||||||
|
|
@ -307,6 +323,18 @@ async function mountSettingsWithApi(api, document = makeDocument()) {
|
||||||
}
|
}
|
||||||
styledView.component.unmount && styledView.component.unmount(styledView.container);
|
styledView.component.unmount && styledView.component.unmount(styledView.container);
|
||||||
|
|
||||||
|
const russianView = await mountWithApi(makeApi({}, 'ru'), {});
|
||||||
|
if (!russianView.container.textContent.includes('Браузер')) {
|
||||||
|
throw new Error('Browser Inbox does not use the localized Browser title');
|
||||||
|
}
|
||||||
|
if (!russianView.container.textContent.includes('Все Дела')) {
|
||||||
|
throw new Error('Browser Inbox does not use the localized Deal filter');
|
||||||
|
}
|
||||||
|
if (!russianView.container.textContent.includes('Пока нет материалов из браузера')) {
|
||||||
|
throw new Error('Browser Inbox empty state is not localized');
|
||||||
|
}
|
||||||
|
russianView.component.unmount && russianView.component.unmount(russianView.container);
|
||||||
|
|
||||||
const api = makeApi();
|
const api = makeApi();
|
||||||
const settingsView = await mountSettingsWithApi(makeApi());
|
const settingsView = await mountSettingsWithApi(makeApi());
|
||||||
const receiverURLInput = walk(settingsView.container, (node) => node.getAttribute && node.getAttribute('data-browser-inbox-pairing-url') === '');
|
const receiverURLInput = walk(settingsView.container, (node) => node.getAttribute && node.getAttribute('data-browser-inbox-pairing-url') === '');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue