Allow selective data export and import
This commit is contained in:
parent
6a85dbb2eb
commit
c7333482ce
3 changed files with 81 additions and 0 deletions
45
options/dataTransfer.js
Normal file
45
options/dataTransfer.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
"use strict";
|
||||||
|
const storage = (globalThis.messenger ?? browser).storage;
|
||||||
|
const KEY_GROUPS = {
|
||||||
|
settings: [
|
||||||
|
'endpoint',
|
||||||
|
'templateName',
|
||||||
|
'customTemplate',
|
||||||
|
'customSystemPrompt',
|
||||||
|
'aiParams',
|
||||||
|
'debugLogging',
|
||||||
|
'htmlToMarkdown',
|
||||||
|
'stripUrlParams',
|
||||||
|
'altTextImages',
|
||||||
|
'collapseWhitespace'
|
||||||
|
],
|
||||||
|
rules: ['aiRules'],
|
||||||
|
cache: ['aiCache']
|
||||||
|
};
|
||||||
|
|
||||||
|
function collectKeys(categories = Object.keys(KEY_GROUPS)) {
|
||||||
|
return categories.flatMap(cat => KEY_GROUPS[cat] || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function exportData(categories) {
|
||||||
|
const data = await storage.local.get(collectKeys(categories));
|
||||||
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'sortana-export.json';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function importData(file, categories) {
|
||||||
|
const text = await file.text();
|
||||||
|
const parsed = JSON.parse(text);
|
||||||
|
const data = {};
|
||||||
|
for (const key of collectKeys(categories)) {
|
||||||
|
if (key in parsed) data[key] = parsed[key];
|
||||||
|
}
|
||||||
|
await storage.local.set(data);
|
||||||
|
}
|
|
@ -207,6 +207,23 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<button class="button is-danger" id="clear-cache" type="button">Clear Cache</button>
|
<button class="button is-danger" id="clear-cache" type="button">Clear Cache</button>
|
||||||
|
<div class="field mt-4">
|
||||||
|
<label class="label">Data categories</label>
|
||||||
|
<div class="control">
|
||||||
|
<label class="checkbox mr-3"><input class="transfer-category" type="checkbox" value="settings" checked> Settings</label>
|
||||||
|
<label class="checkbox mr-3"><input class="transfer-category" type="checkbox" value="rules" checked> Rules</label>
|
||||||
|
<label class="checkbox"><input class="transfer-category" type="checkbox" value="cache" checked> Cache</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field is-grouped mt-4">
|
||||||
|
<p class="control">
|
||||||
|
<button class="button" id="export-data" type="button">Export Data</button>
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<button class="button" id="import-data" type="button">Import Data</button>
|
||||||
|
<input class="is-hidden" type="file" id="import-file" accept="application/json">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -2,6 +2,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const storage = (globalThis.messenger ?? browser).storage;
|
const storage = (globalThis.messenger ?? browser).storage;
|
||||||
const logger = await import(browser.runtime.getURL('logger.js'));
|
const logger = await import(browser.runtime.getURL('logger.js'));
|
||||||
const AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js'));
|
const AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js'));
|
||||||
|
const dataTransfer = await import(browser.runtime.getURL('options/dataTransfer.js'));
|
||||||
const defaults = await storage.local.get([
|
const defaults = await storage.local.get([
|
||||||
'endpoint',
|
'endpoint',
|
||||||
'templateName',
|
'templateName',
|
||||||
|
@ -395,6 +396,24 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
await AiClassifier.clearCache();
|
await AiClassifier.clearCache();
|
||||||
cacheCountEl.textContent = '0';
|
cacheCountEl.textContent = '0';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function selectedCategories() {
|
||||||
|
return [...document.querySelectorAll('.transfer-category:checked')].map(el => el.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('export-data').addEventListener('click', () => {
|
||||||
|
dataTransfer.exportData(selectedCategories());
|
||||||
|
});
|
||||||
|
|
||||||
|
const importInput = document.getElementById('import-file');
|
||||||
|
document.getElementById('import-data').addEventListener('click', () => importInput.click());
|
||||||
|
importInput.addEventListener('change', async () => {
|
||||||
|
if (importInput.files.length) {
|
||||||
|
await dataTransfer.importData(importInput.files[0], selectedCategories());
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
document.getElementById('save').addEventListener('click', async () => {
|
document.getElementById('save').addEventListener('click', async () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue