From 5f54e482f0de3bd0f15486599202394537b61701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carsten=20Gr=C3=A4f?= Date: Sat, 14 Dec 2024 18:39:57 +0100 Subject: [PATCH] snapshot --- .editorconfig | 4 +- .gitignore | 57 +- README.md | 41 + docs/setup.md | 2 +- e2e/AboutPage.ts | 6 +- e2e/TabsetTestPage.ts | 5 +- e2e/fixtures.ts | 2 +- package.json | 91 +- package.json.ref | 138 + ...ht.config.ts => playwright.config.ts.vite2 | 0 postcss.config.js | 16 +- quasar.config.js => quasar.config.ts | 194 +- src-bex/background.ts | 194 +- src-bex/{dom.ts => dom.ts_} | 2 +- src-bex/manifest.json | 185 +- src/App.vue | 2 +- src/app/BrowserApi.ts | 4 +- src/boot/axios.ts | 31 +- src/boot/i18n.ts | 45 +- src/components/Navigation.vue | 2 +- src/components/SidePanelFooter.vue | 2 +- src/components/TabsAsTree.vue | 6 +- src/components/dialogues/ReindexDialog.vue | 6 +- src/components/layouts/SearchHit.vue | 26 +- .../SidePanelTabListElementDetails.vue | 4 +- src/components/widgets/TabCardWidget.vue | 22 +- .../widgets/TabListElementWidget.vue | 6 +- src/components/widgets/ToolbarButton.vue | 16 +- src/env.d.ts | 2 - src/layouts/PwaPageLayout.vue | 81 +- src/notes | 2 +- src/pages/FullpageStart.vue | 2 +- src/pages/PreviewPage.vue | 20 +- src/pages/SearchPage.vue | 8 +- src/pages/SearchResultPage.vue | 8 +- src/pages/SettingsPage.vue | 2 +- src/pages/SidePanelResearchPage.vue | 36 +- src/pages/TabPage.vue | 192 +- ...ncingSettings.vue => SyncingSettings.vue_} | 1 - .../mainpanel/MainPanelReadingModePage.vue | 6 +- src/pages/mainpanel/editorjs/linkTool.ts | 642 +- src/pages/sidepanel/SidePanelApisPage.vue | 118 - src/pages/sidepanel/SidePanelEntitiesPage.vue | 145 - src/pages/sidepanel/SidePanelMessagesPage.vue | 5 +- .../sidepanel/SidePanelPageContextMenu.vue | 8 +- src/pages/sidepanel/SidePanelRssPage.vue | 24 +- src/pages/sidepanel/SidePanelTabDetails.vue | 4 +- .../SidePanelTabsetDescriptionPage.vue | 10 +- .../sidepanel/SidePanelTagsListViewer.vue | 2 +- .../sidepanel/helper/FirstToolbarHelper2.vue | 2 +- src/pages/sidepanel/helper/PngViewHelper.vue | 2 +- .../helper/SearchWithTransitionHelper.vue | 2 +- .../helper/TabDetailsSearchIndex.vue | 2 +- src/router/index.ts | 5 +- src/router/routes.ts | 141 +- src/services/IndexedDbPersistenceService.ts | 3 - src/services/NavigationService.ts | 12 +- src/services/NotificationsService.ts | 16 +- src/services/PersistenceService.ts | 2 - src/services/TabService.ts | 7 +- src/services/firebase/FirebaseCall.ts | 6 +- src/snapshots | 2 +- src/stores/index.ts | 8 +- src/tabsets | 2 +- src/utils/EditorJsConfig.ts | 0 src/utils/JsUtils.ts | 2 +- .../dialogues/NewTabsetDialog.test.ts | 2 +- .../domain/tabs/UpdateTabUrl.test.ts | 4 +- .../search/stores/searchStore.test.ts | 12 +- .../__tests__/stores/bookmarksStore.test.ts | 100 +- .../commands/AddTabToTabsetCommand.test.ts | 4 +- .../commands/CreateFolderCommand.test.ts | 14 +- .../windows/stores/windowsStore.test.ts | 4 +- tsconfig.json | 8 +- vitest.config.mts | 41 + vitest.config.ts => vitest.config.ts_ | 0 yarn.lock | 5667 +++++++---------- 77 files changed, 3696 insertions(+), 4801 deletions(-) create mode 100644 package.json.ref rename playwright.config.ts => playwright.config.ts.vite2 (100%) rename quasar.config.js => quasar.config.ts (58%) rename src-bex/{dom.ts => dom.ts_} (87%) rename src/pages/helper/{SyncingSettings.vue => SyncingSettings.vue_} (99%) delete mode 100644 src/pages/sidepanel/SidePanelApisPage.vue delete mode 100644 src/pages/sidepanel/SidePanelEntitiesPage.vue create mode 100644 src/utils/EditorJsConfig.ts create mode 100644 vitest.config.mts rename vitest.config.ts => vitest.config.ts_ (100%) diff --git a/.editorconfig b/.editorconfig index 9d08a1a8..a6ce2488 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,4 @@ -root = true - -[*] +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] charset = utf-8 indent_style = space indent_size = 2 diff --git a/.gitignore b/.gitignore index 4841719f..30957b23 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules # Quasar core related directories .quasar /dist +/quasar.config.*.temporary.compiled* # Cordova related directories and files /src-cordova/node_modules @@ -13,12 +14,8 @@ node_modules /src-cordova/www # Capacitor related directories and files -/src-capacitor2/www -/src-capacitor2/node_modules - -# BEX related directories and files -/src-bex/www -/src-bex/js/core +/src-capacitor/www +/src-capacitor/node_modules # Log files npm-debug.log* @@ -36,50 +33,15 @@ yarn-error.log* docs/.vitepress/dist docs/.vitepress/cache -/config/.env.local +# local .env files +.env.local* /.env -/releases/0.1.0/Packaged.tabsets.zip -/releases/0.1.0/Packaged.tabsets/ -/releases/0.1.1/ -/releases/0.1.2/ -/releases/0.2.0/ -/releases/0.2.1/ -/releases/0.2.2/ -/releases/0.2.3/ -/test-results/ -/playwright-report/ -/playwright/.cache/ -/releases/0.2.4 (first public)/ -/releases/0.2.5/ -/e2e/screenshots/ -/releases/0.2.6/ -/releases/0.2.7/ -/releases/0.2.8/ -/releases/0.2.9/ -/releases/0.2.10/ -/releases/0.2.11/ -/releases/0.2.12/ -/releases/0.3.0/ -/releases/0.3.1/ -/releases/0.3.2/ -/releases/0.4.0/ -/public/cat.png -/public/models/Xenova/distilbert-base-uncased-finetuned-sst-2-english/model.safetensors -/public/models/Xenova/distilbert-base-uncased-finetuned-sst-2-english/pytorch_model.bin -/public/models/Xenova/distilbert-base-uncased-finetuned-sst-2-english/rust_model.ot -/public/models/Xenova/distilbert-base-uncased-finetuned-sst-2-english/tf_model.h5 -/public/vids/ -/coverage/ -/docs/vids/ -/Tabsets - Manage Tabs and Bookmarks with Ease/ -/.dev.env + +# Sentry Config File +.env.sentry-build-plugin +/.env.prd /.prd.env /.env.tmp -/.tabsets-backend-prd.env -/.env.tmp -/.opera.env -/docs/submodules/build/ -/src-bex/manifest.tmp # Sentry Config File .env.sentry-build-plugin @@ -88,3 +50,4 @@ docs/.vitepress/cache .sentryclirc /.edge.env /blob-report/ +/test-results/ diff --git a/README.md b/README.md index 27624b58..ed77986b 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,44 @@ https://evandor.github.io/tabsets/ # User Documentation https://docs.tabsets.net + +# Quasar App (quasar-project) + +A Quasar Project + +## Install the dependencies +```bash +yarn +# or +npm install +``` + +### Start the app in development mode (hot-code reloading, error reporting, etc.) +```bash +quasar dev +``` + + +### Lint the files +```bash +yarn lint +# or +npm run lint +``` + + +### Format the files +```bash +yarn format +# or +npm run format +``` + + +### Build the app for production +```bash +quasar build +``` + +### Customize the configuration +See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-vite/quasar-config-js). diff --git a/docs/setup.md b/docs/setup.md index 7dab2004..0fdcd626 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -35,7 +35,7 @@ git submodule add -b main https://github.com/evandor/submodule-opentabs.git src/ git submodule add -b main https://github.com/evandor/submodule-requests.git src/requests git submodule add -b main https://github.com/evandor/submodule-search.git src/search git submodule add -b localstorage https://github.com/evandor/submodule-snapshots.git src/snapshots -git submodule add -b main https://github.com/evandor/submodule-spaces.git src/spaces +git submodule add -b localstorage https://github.com/evandor/submodule-spaces.git src/spaces git submodule add -b main https://github.com/evandor/submodule-suggestions.git src/suggestions git submodule add -b localstorage https://github.com/evandor/submodule-tabsets.git src/tabsets git submodule add -b localstorage https://github.com/evandor/submodule-thumbnails.git src/thumbnails diff --git a/e2e/AboutPage.ts b/e2e/AboutPage.ts index 7862c886..ec904507 100644 --- a/e2e/AboutPage.ts +++ b/e2e/AboutPage.ts @@ -1,8 +1,6 @@ import {expect, Locator, Page} from "@playwright/test"; -import {TabsetPage} from "app/e2e/TabsetPage"; -import {TabsetTestPage} from "app/e2e/TabsetTestPage"; -export class AboutPage extends TabsetPage { +export class AboutPage { //extends TabsetPage { readonly page: Page; private extensionId: string; @@ -16,7 +14,7 @@ export class AboutPage extends TabsetPage { private addUrlDialogBtn: Locator; constructor(page: Page, extensionId:string) { - super(); + //super(); this.page = page; this.extensionId = extensionId; this.createFirstTabsetBtn = page.locator('[data-testid=createFirstTabsetBtn]') diff --git a/e2e/TabsetTestPage.ts b/e2e/TabsetTestPage.ts index fb42d5cb..ebb6228a 100644 --- a/e2e/TabsetTestPage.ts +++ b/e2e/TabsetTestPage.ts @@ -1,7 +1,6 @@ import {expect, Locator, Page} from "@playwright/test"; -import {TabsetPage} from "app/e2e/TabsetPage"; -export class TabsetTestPage extends TabsetPage { +export class TabsetTestPage { //extends TabsetPage { readonly page: Page; private extensionId: string; @@ -14,7 +13,7 @@ export class TabsetTestPage extends TabsetPage { // private newTabsetAutoAdd: Locator; constructor(page: Page, extensionId: string) { - super(); + // super(); this.page = page; this.extensionId = extensionId; expect(page).toHaveURL(/.*\/tabsets\//); diff --git a/e2e/fixtures.ts b/e2e/fixtures.ts index 3ffd4f27..12e20b49 100644 --- a/e2e/fixtures.ts +++ b/e2e/fixtures.ts @@ -37,7 +37,7 @@ export const test = base.extend<{ background = await context.waitForEvent('serviceworker'); const extensionId = background.url().split('/')[2]; - await use(extensionId); + await use(extensionId!); }, }); export const expect = test.expect; diff --git a/package.json b/package.json index edf983f2..13d19ce2 100644 --- a/package.json +++ b/package.json @@ -1,28 +1,18 @@ { "name": "tabsets.net", - "version": "0.6.3", + "version": "0.7.0", "description": "Use tabsets.net to safely keep track of all your tabs and links in the Side Panel, stored locally on your browser", "productName": "Tabsets.net", "author": "evandor ", + "type": "module", "private": true, "scripts": { - "dev": "quasar dev -m bex", - "dev spa (only for testing)": "quasar dev -m spa", - "dev pwa": "quasar dev -m pwa", - "dev ssr": "quasar dev -m ssr", - "dev stage prod": "stage=production quasar dev -m bex", - "dev cordova": "quasar dev -m cordova -T ios", - "web-ext run": "cd dist/bex && web-ext run --verbose", - "web-ext build": "quasar build -m bex && zip dist/tabset.src.zip -r src/ src-bex/ package.json && cd dist/bex && web-ext build", - "build bex (dev)": "mv .env .env.tmp && cp .dev.env .env && quasar build -m bex && mv .env.tmp .env", - "build bex (prd)": "mv .env .env.tmp && cp .prd.env .env && quasar build -m bex && mv .env.tmp .env", - "build bex (publish)": "quasar build -m bex", - "build bex firefox": "scripts/build.sh firefox", - "build bex edge": "scripts/build.sh edge", - "build bex opera": "scripts/build.sh opera", - "build pwa": "quasar build -m pwa", - "icon": "icongenie generate -i src/assets/icon.png", + "lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"", + "format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore", "test": "echo \"See package.json => scripts for available tests.\" && exit 0", + "dev": "quasar dev -m bex -T chrome", + "build": "quasar build", + "postinstall": "quasar prepare", "test:unit:ui": "vitest --ui", "test:unit": "vitest", "test:unit:ci": "vitest run", @@ -34,12 +24,6 @@ "test:e2e:showReport": "npx playwright show-report", "test:specificTest": "npx playwright test addFirstTabset", "test:specificTest:debug": "npx playwright test addFirstTabset --debug", - "load:0.4.11.chrome": "rm -rf dist && mkdir -p dist/bex && cd dist/bex && unzip ../../../../releases/0.4.11/tabsets-chrome-0.4.11.zip && cd ../../../../", - "build pwa.prd & deploy to india032": "mv .env .env.tmp && cp .prd.env .env && quasar build -m pwa && scp -r -P 222 dist/pwa/* carsten@carsten.evandor.de:/home/carsten/tabsets/pwa.tabsets.net && mv .env.tmp .env", - "build pwa.dev & deploy to india032": "mv .env .env.tmp && cp .dev.env .env && quasar build -m pwa && scp -r -P 222 dist/pwa/* carsten@carsten.evandor.de:/home/carsten/tabsets/pwa.dev.tabsets.net && mv .env.tmp .env", - "docs:dev": "./copySubmoduleDocs.sh && vitepress dev docs", - "docs:build": "./copySubmoduleDocs.sh && vitepress build docs", - "docs:preview": "vitepress preview docs", "info": "yarn list > docs/yarn.list.txt && quasar info > docs/quasar.info.txt", "sentry:sourcemaps": "sentry-cli sourcemaps inject --org skysail-dk --project tabsets ./dist && sentry-cli sourcemaps upload --org skysail-dk --project tabsets ./dist" }, @@ -49,9 +33,8 @@ "@editorjs/editorjs": "^2.30.7", "@editorjs/header": "^2.8.7", "@he-tree/vue": "^2.9.2", - "@intlify/unplugin-vue-i18n": "^4.0.0", "@mozilla/readability": "^0.5.0", - "@quasar/extras": "^1.16.14", + "@quasar/extras": "^1.16.4", "@rowanmanning/feed-parser": "^1.1.0", "@sentry/browser": "^8.41.0", "@sentry/cli": "^2.39.1", @@ -60,7 +43,7 @@ "@types/mdast": "^4.0.4", "@types/pngjs": "^6.0.5", "@types/sanitize-html": "^2.13.0", - "axios": "^1.7.8", + "axios": "^1.2.1", "buffer": "^6.0.3", "chart.js": "^4.4.6", "chartjs-chart-wordcloud": "^4.4.4", @@ -79,10 +62,11 @@ "mathjs": "^14.0.0", "mdast-util-from-markdown": "^2.0.1", "mhtml2html": "^3.0.0", - "pinia": "^2.2.8", + "pinia": "^2.0.11", "pngjs": "^7.0.0", - "quasar": "^2.16.11", + "quasar": "^2.16.0", "regenerator-runtime": "^0.14.1", + "register-service-worker": "^1.7.2", "sanitize-html": "^2.13.0", "throttled-queue": "^2.1.4", "translate": "^3.0.0", @@ -90,18 +74,17 @@ "url": "^0.11.4", "uuid": "^11.0.3", "vite-plugin-package-version": "^1.1.0", - "vue": "^3.5.13", + "vue": "^3.4.18", "vue-chartjs": "^5.3.2", "vue-draggable-next": "^2.2.1", "vue-grid-layout-v3": "^3.1.1-rc.4", "vue-highlight-words": "^3.0.1", - "vue-i18n": "^10.0.5", + "vue-i18n": "^9.2.2", "vue-json-pretty": "^2.4.0", - "vue-router": "^4.5.0", + "vue-router": "^4.0.12", "vue-timeago3": "^2.3.2" }, "devDependencies": { - "@babel/preset-env": "^7.25.4", "@editorjs/checklist": "^1.6.0", "@editorjs/image": "^2.10.1", "@editorjs/link": "^2.6.2", @@ -109,30 +92,40 @@ "@editorjs/raw": "^2.5.0", "@editorjs/table": "^2.4.1", "@playwright/test": "^1.49.0", - "@quasar/app-vite": "^1.11.0", - "@quasar/babel-preset-app": "^2.0.3", - "@quasar/quasar-app-extension-testing-unit-vitest": "^1.0.0", - "@types/node": "^22.10.1", - "@types/uuid": "^10.0.0", - "@vitest/coverage-c8": "^0.33.0", - "@vitest/coverage-v8": "^1.6.0", - "@vitest/ui": "^1.6.0", - "@vue/test-utils": "^2.4.6", - "@wdio/cli": "^9.4.1", - "autoprefixer": "^10.4.20", + "@eslint/js": "^9.14.0", + "@intlify/unplugin-vue-i18n": "^2.0.0", + "@quasar/app-vite": "^2.0.0", + "@quasar/quasar-app-extension-testing-unit-vitest": "^1.1.0", + "@types/node": "^20.5.9", + "@vue/eslint-config-prettier": "^10.1.0", + "@vue/eslint-config-typescript": "^14.1.3", + "@vitest/ui": "^2.0.5", + "autoprefixer": "^10.4.2", "editorjs-alert": "^1.1.4", "editorjs-text-color-plugin": "^2.0.4", + "eslint": "^9.14.0", + "eslint-plugin-vue": "^9.30.0", "fake-indexeddb": "^6.0.0", - "mermaid": "^11.4.1", - "typescript": "^5.7.2", - "vite": "^2.9.18", + "globals": "^15.12.0", + "prettier": "^3.3.3", + "typescript": "~5.5.3", + "vite-plugin-checker": "^0.8.0", "vitepress": "^1.5.0", "vitepress-plugin-mermaid": "^2.0.16", - "vitest": "^1.6.0" + "vue-tsc": "^2.0.29", + "workbox-build": "^7.0.0", + "workbox-cacheable-response": "^7.0.0", + "workbox-core": "^7.0.0", + "workbox-expiration": "^7.0.0", + "workbox-precaching": "^7.0.0", + "workbox-routing": "^7.0.0", + "workbox-strategies": "^7.0.0", + "@vue/test-utils": "^2.4.4", + "vitest": "^2.0.5" }, "engines": { - "node": "^22 || ^20 || ^18 || ^16", + "node": "^28 || ^26 || ^24 || ^22 || ^20 || ^18", "npm": ">= 6.13.4", "yarn": ">= 1.21.1" } -} +} \ No newline at end of file diff --git a/package.json.ref b/package.json.ref new file mode 100644 index 00000000..edf983f2 --- /dev/null +++ b/package.json.ref @@ -0,0 +1,138 @@ +{ + "name": "tabsets.net", + "version": "0.6.3", + "description": "Use tabsets.net to safely keep track of all your tabs and links in the Side Panel, stored locally on your browser", + "productName": "Tabsets.net", + "author": "evandor ", + "private": true, + "scripts": { + "dev": "quasar dev -m bex", + "dev spa (only for testing)": "quasar dev -m spa", + "dev pwa": "quasar dev -m pwa", + "dev ssr": "quasar dev -m ssr", + "dev stage prod": "stage=production quasar dev -m bex", + "dev cordova": "quasar dev -m cordova -T ios", + "web-ext run": "cd dist/bex && web-ext run --verbose", + "web-ext build": "quasar build -m bex && zip dist/tabset.src.zip -r src/ src-bex/ package.json && cd dist/bex && web-ext build", + "build bex (dev)": "mv .env .env.tmp && cp .dev.env .env && quasar build -m bex && mv .env.tmp .env", + "build bex (prd)": "mv .env .env.tmp && cp .prd.env .env && quasar build -m bex && mv .env.tmp .env", + "build bex (publish)": "quasar build -m bex", + "build bex firefox": "scripts/build.sh firefox", + "build bex edge": "scripts/build.sh edge", + "build bex opera": "scripts/build.sh opera", + "build pwa": "quasar build -m pwa", + "icon": "icongenie generate -i src/assets/icon.png", + "test": "echo \"See package.json => scripts for available tests.\" && exit 0", + "test:unit:ui": "vitest --ui", + "test:unit": "vitest", + "test:unit:ci": "vitest run", + "test:unit:coverage": "vitest --coverage", + "test:unit:watch": "vitest --watch", + "test:unit:watchAll": "vitest --watchAll", + "test:e2e": "npx playwright test", + "test:e2e ui": "npx playwright test --ui", + "test:e2e:showReport": "npx playwright show-report", + "test:specificTest": "npx playwright test addFirstTabset", + "test:specificTest:debug": "npx playwright test addFirstTabset --debug", + "load:0.4.11.chrome": "rm -rf dist && mkdir -p dist/bex && cd dist/bex && unzip ../../../../releases/0.4.11/tabsets-chrome-0.4.11.zip && cd ../../../../", + "build pwa.prd & deploy to india032": "mv .env .env.tmp && cp .prd.env .env && quasar build -m pwa && scp -r -P 222 dist/pwa/* carsten@carsten.evandor.de:/home/carsten/tabsets/pwa.tabsets.net && mv .env.tmp .env", + "build pwa.dev & deploy to india032": "mv .env .env.tmp && cp .dev.env .env && quasar build -m pwa && scp -r -P 222 dist/pwa/* carsten@carsten.evandor.de:/home/carsten/tabsets/pwa.dev.tabsets.net && mv .env.tmp .env", + "docs:dev": "./copySubmoduleDocs.sh && vitepress dev docs", + "docs:build": "./copySubmoduleDocs.sh && vitepress build docs", + "docs:preview": "vitepress preview docs", + "info": "yarn list > docs/yarn.list.txt && quasar info > docs/quasar.info.txt", + "sentry:sourcemaps": "sentry-cli sourcemaps inject --org skysail-dk --project tabsets ./dist && sentry-cli sourcemaps upload --org skysail-dk --project tabsets ./dist" + }, + "dependencies": { + "@calumk/editorjs-columns": "^0.3.2", + "@codexteam/icons": "^0.3.3", + "@editorjs/editorjs": "^2.30.7", + "@editorjs/header": "^2.8.7", + "@he-tree/vue": "^2.9.2", + "@intlify/unplugin-vue-i18n": "^4.0.0", + "@mozilla/readability": "^0.5.0", + "@quasar/extras": "^1.16.14", + "@rowanmanning/feed-parser": "^1.1.0", + "@sentry/browser": "^8.41.0", + "@sentry/cli": "^2.39.1", + "@sentry/vite-plugin": "^2.22.4", + "@types/lodash": "^4.17.7", + "@types/mdast": "^4.0.4", + "@types/pngjs": "^6.0.5", + "@types/sanitize-html": "^2.13.0", + "axios": "^1.7.8", + "buffer": "^6.0.3", + "chart.js": "^4.4.6", + "chartjs-chart-wordcloud": "^4.4.4", + "cheerio": "^1.0.0", + "date-fns": "^4.1.0", + "diff": "^7.0.0", + "dotenv": "^16.4.5", + "events": "^3.3.0", + "fuse.js": "^7.0.0", + "html-to-text": "^9.0.5", + "idb": "^8.0.0", + "js-sha256": "^0.11.0", + "jsonpath-plus": "^10.2.0", + "keytar": "^7.9.0", + "lodash": "^4.17.21", + "mathjs": "^14.0.0", + "mdast-util-from-markdown": "^2.0.1", + "mhtml2html": "^3.0.0", + "pinia": "^2.2.8", + "pngjs": "^7.0.0", + "quasar": "^2.16.11", + "regenerator-runtime": "^0.14.1", + "sanitize-html": "^2.13.0", + "throttled-queue": "^2.1.4", + "translate": "^3.0.0", + "ts-md5": "^1.3.1", + "url": "^0.11.4", + "uuid": "^11.0.3", + "vite-plugin-package-version": "^1.1.0", + "vue": "^3.5.13", + "vue-chartjs": "^5.3.2", + "vue-draggable-next": "^2.2.1", + "vue-grid-layout-v3": "^3.1.1-rc.4", + "vue-highlight-words": "^3.0.1", + "vue-i18n": "^10.0.5", + "vue-json-pretty": "^2.4.0", + "vue-router": "^4.5.0", + "vue-timeago3": "^2.3.2" + }, + "devDependencies": { + "@babel/preset-env": "^7.25.4", + "@editorjs/checklist": "^1.6.0", + "@editorjs/image": "^2.10.1", + "@editorjs/link": "^2.6.2", + "@editorjs/quote": "^2.7.4", + "@editorjs/raw": "^2.5.0", + "@editorjs/table": "^2.4.1", + "@playwright/test": "^1.49.0", + "@quasar/app-vite": "^1.11.0", + "@quasar/babel-preset-app": "^2.0.3", + "@quasar/quasar-app-extension-testing-unit-vitest": "^1.0.0", + "@types/node": "^22.10.1", + "@types/uuid": "^10.0.0", + "@vitest/coverage-c8": "^0.33.0", + "@vitest/coverage-v8": "^1.6.0", + "@vitest/ui": "^1.6.0", + "@vue/test-utils": "^2.4.6", + "@wdio/cli": "^9.4.1", + "autoprefixer": "^10.4.20", + "editorjs-alert": "^1.1.4", + "editorjs-text-color-plugin": "^2.0.4", + "fake-indexeddb": "^6.0.0", + "mermaid": "^11.4.1", + "typescript": "^5.7.2", + "vite": "^2.9.18", + "vitepress": "^1.5.0", + "vitepress-plugin-mermaid": "^2.0.16", + "vitest": "^1.6.0" + }, + "engines": { + "node": "^22 || ^20 || ^18 || ^16", + "npm": ">= 6.13.4", + "yarn": ">= 1.21.1" + } +} diff --git a/playwright.config.ts b/playwright.config.ts.vite2 similarity index 100% rename from playwright.config.ts rename to playwright.config.ts.vite2 diff --git a/postcss.config.js b/postcss.config.js index 94b7b1c8..25db2f4c 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,10 +1,12 @@ -/* eslint-disable */ // https://github.com/michael-ciniawsky/postcss-load-config -module.exports = { +import autoprefixer from 'autoprefixer' +// import rtlcss from 'postcss-rtlcss' + +export default { plugins: [ // https://github.com/postcss/autoprefixer - require('autoprefixer')({ + autoprefixer({ overrideBrowserslist: [ 'last 4 Chrome versions', 'last 4 Firefox versions', @@ -15,13 +17,13 @@ module.exports = { 'last 4 FirefoxAndroid versions', 'last 4 iOS versions' ] - }) + }), // https://github.com/elchininet/postcss-rtlcss // If you want to support RTL css, then - // 1. yarn/npm install postcss-rtlcss + // 1. yarn/pnpm/bun/npm install postcss-rtlcss // 2. optionally set quasar.config.js > framework > lang to an RTL language - // 3. uncomment the following line: - // require('postcss-rtlcss') + // 3. uncomment the following line (and its import statement above): + // rtlcss() ] } diff --git a/quasar.config.js b/quasar.config.ts similarity index 58% rename from quasar.config.js rename to quasar.config.ts index 9b91fff0..d0cbdffe 100644 --- a/quasar.config.js +++ b/quasar.config.ts @@ -1,30 +1,16 @@ -/* eslint-env node */ - -/* - * This file runs in a Node context (it's NOT transpiled by Babel), so use only - * the ES6 features that are supported by your Node version. https://node.green/ - */ - // Configuration for your app // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js +import { defineConfig } from '#q-app/wrappers'; +import { fileURLToPath } from 'node:url'; +import "dotenv/config.js"; +import path from "path"; -const {configure} = require('quasar/wrappers'); -const path = require('path'); -// const fs = require("fs"); -// const {sentryVitePlugin} = require("@sentry/vite-plugin"); - -module.exports = configure(function (ctx) { - - require('dotenv').config() - - //console.log("======>", path.resolve(__dirname, './src/i18n/**')) +export default defineConfig((ctx) => { return { - - // https://v2.quasar.dev/quasar-cli-vite/prefetch-feature - //preFetch: true, + // preFetch: true, // app boot file (/src/boot) // --> boot files are part of "main.js" @@ -44,7 +30,7 @@ module.exports = configure(function (ctx) { // https://github.com/quasarframework/quasar/tree/dev/extras extras: [ // 'ionicons-v4', - // 'mdi-v5', + // 'mdi-v7', // 'fontawesome-v6', 'eva-icons', // 'themify', @@ -59,21 +45,15 @@ module.exports = configure(function (ctx) { // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build build: { - - // https://github.com/quasarframework/quasar/issues/14589 - sourcemap: 'true', - target: { - browser: ['es2020', 'edge88', 'firefox78', 'chrome87'], - node: 'node16' + browser: [ 'es2022', 'firefox115', 'chrome115', 'safari14' ], + node: 'node20' }, - viteVuePluginOptions: { - template: { - compilerOptions: { - isCustomElement: (tag) => tag.startsWith('webview') - } - } + typescript: { + strict: true, + vueShim: true + // extendTsConfig (tsConfig) {} }, vueRouterMode: 'hash', // available values: 'hash', 'history' @@ -83,14 +63,14 @@ module.exports = configure(function (ctx) { // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup - //publicPath: '/www/', + // publicPath: '/', // analyze: true, env: { BUILD_TIMESTAMP: new Date().toISOString().split('T')[0], - BACKEND_URL: process.env.BACKEND_URL, + //BACKEND_URL: process.env.BACKEND_URL, HOST: process.env.HOST, - TABSETS_PWA_URL: process.env.TABSETS_PWA_URL, + //TABSETS_PWA_URL: process.env.TABSETS_PWA_URL, TABSETS_STAGE: process.env.STAGE, LOCALE: process.env.LOCALE, SENTRY_DSN: process.env.SENTRY_DSN @@ -101,44 +81,44 @@ module.exports = configure(function (ctx) { // polyfillModulePreload: true, // distDir - // !== MIT - extendViteConf(viteConf) { - - if ((ctx.mode.spa || ctx.mode.pwa || ctx.mode.electron) && viteConf && viteConf.mode === "development") { - // https://dev.to/richardbray/how-to-fix-the-referenceerror-global-is-not-defined-error-in-sveltekitvite-2i49 - viteConf.define.global = {} - } - viteConf.define.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = 'false' - - // this caused an issue with the electron build - // //if ((ctx.mode.spa || ctx.mode.pwa || ctx.mode.electron) && viteConf && viteConf.mode === "development") { - // if (!ctx.mode.bex && !ctx.mode.pwa) { - // // https://dev.to/richardbray/how-to-fix-the-referenceerror-global-is-not-defined-error-in-sveltekitvite-2i49 - // viteConf.define.global = {} - // //https://stackoverflow.com/questions/77061323/error-pouchdb-on-vite-referenceerror-global-is-not-defined - // //viteConf.define.window.global = window.global - // } - // viteConf.define.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = 'false' - }, + // extendViteConf (viteConf) {}, // viteVuePluginOptions: {}, vitePlugins: [ ['@intlify/unplugin-vue-i18n/vite', { + // if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false` + // compositionOnly: false, + + // if you want to use named tokens in your Vue I18n messages, such as 'Hello {name}', + // you need to set `runtimeOnly: false` + // runtimeOnly: false, + + ssr: ctx.modeName === 'ssr', + + // you need to set i18n resource including paths ! + // include: [ fileURLToPath(new URL('./src/i18n', import.meta.url)) ] include: [path.resolve(__dirname, './src/i18n/**')], }], - ['vite-plugin-package-version', {}], - [require('@sentry/vite-plugin').sentryVitePlugin,{ - authToken: process.env.SENTRY_AUTH_TOKEN, - org: "skysail-dk", - disable: ctx.dev, - project: "tabsets" - }] + + ['vite-plugin-checker', { + vueTsc: true, + eslint: { + lintCommand: 'eslint -c ./eslint.config.js "./src*/**/*.{ts,js,mjs,cjs,vue}"', + useFlatConfig: true + } + }, { server: false }], + // [require('@sentry/vite-plugin').sentryVitePlugin,{ + // authToken: process.env.SENTRY_AUTH_TOKEN, + // org: "skysail-dk", + // disable: ctx.dev, + // project: "tabsets" + // }] ] }, // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer devServer: { - // https: true + // https: true, open: true // opens browser window automatically }, @@ -176,45 +156,49 @@ module.exports = configure(function (ctx) { // rootComponent: 'src/App.vue', // router: 'src/router/index', // store: 'src/store/index', - // registerServiceWorker: 'src-pwa/register-service-worker', - // serviceWorker: 'src-pwa/custom-service-worker', + // pwaRegisterServiceWorker: 'src-pwa/register-service-worker', + // pwaServiceWorker: 'src-pwa/custom-service-worker', // pwaManifestFile: 'src-pwa/manifest.json', // electronMain: 'src-electron/electron-main', // electronPreload: 'src-electron/electron-preload' + // bexManifestFile: 'src-bex/manifest.json // }, // https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr ssr: { - // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name! - // will mess up SSR + prodPort: 3000, // The default port that the production server should use + // (gets superseded if process.env.PORT is specified at runtime) - // extendSSRWebserverConf (esbuildConf) {}, - // extendPackageJson (json) {}, + middlewares: [ + 'render' // keep this as last one + ], - pwa: true, + // extendPackageJson (json) {}, + // extendSSRWebserverConf (esbuildConf) {}, + // manualStoreSerialization: true, + // manualStoreSsrContextInjection: true, // manualStoreHydration: true, // manualPostHydrationTrigger: true, - prodPort: 3000, // The default port that the production server should use - // (gets superseded if process.env.PORT is specified at runtime) + pwa: false + // pwaOfflineHtmlFilename: 'offline.html', // do NOT use index.html as name! - middlewares: [ - 'render' // keep this as last one - ] + // pwaExtendGenerateSWOptions (cfg) {}, + // pwaExtendInjectManifestOptions (cfg) {} }, // https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa pwa: { - workboxMode: 'generateSW', // or 'injectManifest' - injectPwaMetaTags: true, - swFilename: 'sw.js', - manifestFilename: 'manifest.json', - useCredentialsForManifestTag: false, - // extendGenerateSWOptions (cfg) {} - // extendInjectManifestOptions (cfg) {}, - // extendManifestJson (json) {} - // extendPWACustomSWConf (esbuildConf) {} + workboxMode: 'GenerateSW' // 'GenerateSW' or 'InjectManifest' + // swFilename: 'sw.js', + // manifestFilename: 'manifest.json' + // extendManifestJson (json) {}, + // useCredentialsForManifestTag: true, + // injectPwaMetaTags: false, + // extendPWACustomSWConf (esbuildConf) {}, + // extendGenerateSWOptions (cfg) {}, + // extendInjectManifestOptions (cfg) {} }, // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova @@ -229,26 +213,27 @@ module.exports = configure(function (ctx) { // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron electron: { - // extendElectronMainConf (esbuildConf) - // extendElectronPreloadConf (esbuildConf) + // extendElectronMainConf (esbuildConf) {}, + // extendElectronPreloadConf (esbuildConf) {}, + + // extendPackageJson (json) {}, + // Electron preload scripts (if any) from /src-electron, WITHOUT file extension + preloadScripts: [ 'electron-preload' ], + + // specify the debugging port to use for the Electron app when running in development mode inspectPort: 5858, - bundler: 'builder', // 'packager' or 'builder' + bundler: 'packager', // 'packager' or 'builder' packager: { // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options + // OS X / Mac App Store // appBundleId: '', // appCategoryType: '', // osxSign: '', // protocol: 'myapp://path', - protocols: [ - { - name: 'Electron Tabsets', - schemes: ['electron-tabsets'] - } - ] // Windows only // win32metadata: { ... } @@ -257,21 +242,24 @@ module.exports = configure(function (ctx) { builder: { // https://www.electron.build/configuration/configuration - appId: 'tabsets.net', - publish: { - 'provider': 'github', - 'private': false, - 'timeout': 480000 - } + appId: 'quasar-project' } }, // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex bex: { - contentScripts: [ - 'tabsets-content-script', - 'tabsets-excalidraw-script' - ] + // extendBexScriptsConf (esbuildConf) {}, + // extendBexManifestJson (json) {}, + + /** + * The list of extra scripts (js/ts) not in your bex manifest that you want to + * compile and use in your browser extension. Maybe dynamic use them? + * + * Each entry in the list should be a relative filename to /src-bex/ + * + * @example [ 'my-script.ts', 'sub-folder/my-other-script.js' ] + */ + extraScripts: [] } } }); diff --git a/src-bex/background.ts b/src-bex/background.ts index ac4398fc..b767cbe5 100644 --- a/src-bex/background.ts +++ b/src-bex/background.ts @@ -1,4 +1,13 @@ -import {bexBackground} from 'quasar/wrappers'; +/** + * Importing the file below initializes the extension background. + * + * Warnings: + * 1. Do NOT remove the import statement below. It is required for the extension to work. + * If you don't need createBridge(), leave it as "import '#q-app/bex/background'". + * 2. Do NOT import this file in multiple background scripts. Only in one! + * 3. Import it in your background service worker (if available for your target browser). + */ +import { createBridge } from '#q-app/bex/background'; import OnInstalledReason = chrome.runtime.OnInstalledReason; // https://stackoverflow.com/questions/49739438/when-and-how-does-a-pwa-update-itself @@ -12,7 +21,19 @@ addEventListener('unhandledrejection', async (event) => { // getting error: Service worker registration failed. Status code: 15 //Analytics.fireErrorEvent(event.reason); }); +// +// function openExtension () { +// chrome.tabs.create( +// { +// url: chrome.runtime.getURL('www/index.html') +// }, +// (/* newTab */) => { +// // Tab opened. +// } +// ); +// } +//chrome.runtime.onInstalled.addListener(openExtension); chrome.runtime.onInstalled.addListener((callback) => { console.log("[service-worker] ga: fire event install", callback.reason, callback.previousVersion) // getting error: "Service worker registration failed. Status code: 15" @@ -41,6 +62,8 @@ chrome.omnibox.onInputEntered.addListener((text) => { .catch((err) => console.log("[service-worker] background.js error", err)) }); +//chrome.action.onClicked.addListener(openExtension); + let modelPromise: any = null // @ts-ignore @@ -105,7 +128,174 @@ chrome.runtime.onConnect.addListener(function (port) { } }); +declare module '@quasar/app-vite' { + interface BexEventMap { + /* eslint-disable @typescript-eslint/no-explicit-any */ + log: [{ message: string; data?: any[] }, void]; + getTime: [never, number]; + + 'storage.get': [string | undefined, any]; + 'storage.set': [{ key: string; value: any }, void]; + 'storage.remove': [string, void]; + /* eslint-enable @typescript-eslint/no-explicit-any */ + } +} + +/** + * Call useBridge() to enable communication with the app & content scripts + * (and between the app & content scripts), otherwise skip calling + * useBridge() and use no bridge. + */ +const bridge = createBridge({ debug: false }); + +bridge.on('log', ({ from, payload }) => { + console.log(`[BEX] @log from "${ from }"`, payload); +}); + +bridge.on('getTime', () => { + return Date.now(); +}); + +bridge.on('storage.get', ({ payload: key }) => { + return new Promise(resolve => { + if (key === void 0) { + chrome.storage.local.get(null, items => { + // Group the values up into an array to take advantage of the bridge's chunk splitting. + resolve(Object.values(items)); + }); + } else { + chrome.storage.local.get([key], items => { + resolve(items[key]); + }); + } + }); +}); +// Usage: +// bridge.send({ +// event: 'storage.get', +// to: 'background', +// payload: 'key' // or omit `payload` to get data for all keys +// }).then((result) => { ... }).catch((error) => { ... }); + +bridge.on('storage.set', async ({ payload: { key, value } }) => { + await chrome.storage.local.set({ [key]: value }); +}); +// Usage: +// bridge.send({ +// event: 'storage.set', +// to: 'background', +// payload: { key: 'someKey', value: 'someValue' } +// }).then(() => { ... }).catch((error) => { ... }); + +bridge.on('storage.remove', async ({ payload: key }) => { + await chrome.storage.local.remove(key); +}); +// Usage: +// bridge.send({ +// event: 'storage.remove', +// to: 'background', +// payload: 'someKey' +// }).then(() => { ... }).catch((error) => { ... }); + +/* +// More examples: + +// Listen to a message from the client +bridge.on('test', message => { + console.log(message); + console.log(message.payload); +}); + +// Send a message and split payload into chunks +// to avoid max size limit of BEX messages. +// Warning! This happens automatically when the payload is an array. +// If you actually want to send an Array, wrap it in an Object. +bridge.send({ + event: 'test', + to: 'app', + payload: [ 'chunk1', 'chunk2', 'chunk3', ... ] +}).then(responsePayload => { ... }).catch(err => { ... }); -export default bexBackground((bridge, cons/* , allActiveConnections */) => { +// Send a message and wait for a response +bridge.send({ + event: 'test', + to: 'app', + payload: { banner: 'Hello from background!' } +}).then(responsePayload => { ... }).catch(err => { ... }); +// Listen to a message from the client and respond synchronously +bridge.on('test', message => { + console.log(message); + return { banner: 'Hello from background!' }; }); + +// Listen to a message from the client and respond asynchronously +bridge.on('test', async message => { + console.log(message); + const result = await someAsyncFunction(); + return result; +}); +bridge.on('test', message => { + console.log(message) + return new Promise(resolve => { + setTimeout(() => { + resolve({ banner: 'Hello from background!' }); + }, 1000); + }); +}); + +// Broadcast a message to app & content scripts +bridge.portList.forEach(portName => { + bridge.send({ event: 'test', to: portName, payload: 'Hello from background!' }); +}); + +// Find any connected content script and send a message to it +const contentPort = bridge.portList.find(portName => portName.startsWith('content@')); +if (contentPort) { + bridge.send({ event: 'test', to: contentPort, payload: 'Hello from background!' }); +} + +// Send a message to a certain content script +bridge + .send({ event: 'test', to: 'content@my-content-script-2345', payload: 'Hello from background!' }) + .then(responsePayload => { ... }) + .catch(err => { ... }); + +// Listen for connection events +// (the "@quasar:ports" is an internal event name registered automatically by the bridge) +// --> ({ portList: string[], added?: string } | { portList: string[], removed?: string }) +bridge.on('@quasar:ports', ({ portList, added, removed }) => { + console.log('Ports:', portList) + if (added) { + console.log('New connection:', added); + } else if (removed) { + console.log('Connection removed:', removed); + } +}); + +// Send a message to the client based on something happening. +chrome.tabs.onCreated.addListener(tab => { + bridge.send(...).then(responsePayload => { ... }).catch(err => { ... }); +}); + +// Send a message to the client based on something happening. +chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + if (changeInfo.url) { + bridge.send(...).then(responsePayload => { ... }).catch(err => { ... }); + } +}); + +// Dynamically set debug mode +bridge.setDebug(true); // boolean + +// Log a message on the console (if debug is enabled) +bridge.log('Hello world!'); +bridge.log('Hello', 'world!'); +bridge.log('Hello world!', { some: 'data' }); +bridge.log('Hello', 'world', '!', { some: 'object' }); +// Log a warning on the console (regardless of the debug setting) +bridge.warn('Hello world!'); +bridge.warn('Hello', 'world!'); +bridge.warn('Hello world!', { some: 'data' }); +bridge.warn('Hello', 'world', '!', { some: 'object' }); +*/ diff --git a/src-bex/dom.ts b/src-bex/dom.ts_ similarity index 87% rename from src-bex/dom.ts rename to src-bex/dom.ts_ index a36dbc82..484c37b3 100644 --- a/src-bex/dom.ts +++ b/src-bex/dom.ts_ @@ -2,7 +2,7 @@ // More info: https://quasar.dev/quasar-cli/developing-browser-extensions/dom-hooks import {bexDom} from 'quasar/wrappers' -export default bexDom((bridge) => { +export default bexDom((bridge:any) => { //console.log("====>", bridge) diff --git a/src-bex/manifest.json b/src-bex/manifest.json index 23f44fd2..ae137aac 100644 --- a/src-bex/manifest.json +++ b/src-bex/manifest.json @@ -1,94 +1,111 @@ { - "manifest_version": 3, - "icons": { - "16": "icons/icon-16x16.png", - "48": "icons/icon-48x48.png", - "128": "icons/icon-128x128.png" - }, - "permissions": [ - "storage", - "tabs", - "activeTab", - "alarms", - "scripting", - "sidePanel", - "contextMenus", - "bookmarks" - ], - "optional_permissions": [ - "pageCapture", - "notifications", - "webRequest", - "tabGroups" - ], - "host_permissions": [ - "", - "*://*/*" - ], - "side_panel": { - "default_path": "www/index.html" - }, - "background": { - "service_worker": "background.js" - }, - "content_scripts": [ - { - "matches": ["https://excalidraw.com/*"], - "js": [ - "tabsets-excalidraw-script.js" - ] + "all": { + "manifest_version": 3, + "icons": { + "16": "icons/icon-16x16.png", + "48": "icons/icon-48x48.png", + "128": "icons/icon-128x128.png" }, - { - "matches": [ - "*://*/*" - ], - "js": [ - "tabsets-content-script.js" - ] - } - ], - "content_security_policy": { - "extension_pages": "script-src 'self'; object-src 'self';" - }, - "web_accessible_resources": [ - { - "resources": [ - "*" - ], - "matches": [ - "*://*/*" - ] - } - ], - "omnibox": { "keyword": "ts" }, - "commands": { - "_execute_action": { - "suggested_key": { - "default": "Ctrl+B", - "mac": "Command+B" + "permissions": [ + "storage", + "tabs", + "activeTab", + "alarms", + "scripting", + "sidePanel", + "contextMenus", + "bookmarks" + ], + "optional_permissions": [ + "pageCapture", + "notifications", + "webRequest", + "tabGroups" + ], + "host_permissions": [ + "", + "*://*/*" + ], + "content_scripts": [ + { + "matches": [ + "https://excalidraw.com/*" + ], + "js": [ + "tabsets-excalidraw-script.ts" + ] + }, + { + "matches": [ + "*://*/*" + ], + "js": [ + "tabsets-content-script.ts" + ] } + ], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self';" }, - "search": { - "suggested_key": { - "default": "Ctrl+K", - "mac": "Command+K" - }, - "description": "Open Search Box" + "web_accessible_resources": [ + { + "resources": [ + "*" + ], + "matches": [ + "*://*/*" + ] + } + ], + "omnibox": { + "keyword": "ts" }, - "tabHistoryBack": { - "suggested_key": { - "default": "Alt+Left", - "mac": "Alt+Left" + "commands": { + "_execute_action": { + "suggested_key": { + "default": "Ctrl+B", + "mac": "Command+B" + } }, - "description": "Open last open tab" - }, - "tabHistoryForward": { - "suggested_key": { - "default": "Alt+Right", - "mac": "Alt+Right" + "search": { + "suggested_key": { + "default": "Ctrl+K", + "mac": "Command+K" + }, + "description": "Open Search Box" }, - "description": "Forward to next tab (if available)" + "tabHistoryBack": { + "suggested_key": { + "default": "Alt+Left", + "mac": "Alt+Left" + }, + "description": "Open last open tab" + }, + "tabHistoryForward": { + "suggested_key": { + "default": "Alt+Right", + "mac": "Alt+Right" + }, + "description": "Forward to next tab (if available)" + } + }, + "options_page": "www/index.html#/mainpanel/settings" + }, + + "chrome": { + "side_panel": { + "default_path": "www/index.html" + }, + "background": { + "service_worker": "background.ts" } }, - "options_page": "www/index.html#/mainpanel/settings" + + "firefox": { + "background": { + "scripts": [ + "background.ts" + ] + } + } } diff --git a/src/App.vue b/src/App.vue index 40f6ea7e..8317c0cf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,5 @@ diff --git a/src/components/widgets/TabListElementWidget.vue b/src/components/widgets/TabListElementWidget.vue index 3beda78e..bc25b488 100644 --- a/src/components/widgets/TabListElementWidget.vue +++ b/src/components/widgets/TabListElementWidget.vue @@ -4,7 +4,7 @@ - + + :data-testid="useUtils().createDataTestIdentifier('tabListElementWidget', props.tab.title || '')"> @@ -269,7 +269,7 @@ watchEffect(() => { if (props.tab) { // @ts-ignore thumbnailFor(props.tab) - .then((tn: object) => { + .then((tn: any) => { //console.log("tn", tn) if (tn && tn['thumbnail' as keyof object]) { thumbnail.value = tn['thumbnail' as keyof object] diff --git a/src/components/widgets/ToolbarButton.vue b/src/components/widgets/ToolbarButton.vue index 01c45dd6..193b0cf4 100644 --- a/src/components/widgets/ToolbarButton.vue +++ b/src/components/widgets/ToolbarButton.vue @@ -5,8 +5,8 @@ + name="sidebar" :icon="props.icon" :size="btnSize"> + {{ props.tooltip }} @@ -17,8 +17,8 @@ :flat="!outlinedIfActive()" :outline="outlinedIfActive()" name="sidebar" :icon="props.icon" - :size="btnSize" - @click="tabsClicked(props.drawer)"> + :size="btnSize"> + {{ props.tooltip }} @@ -42,10 +42,10 @@ const props = defineProps({ const btnSize = "12px" const outlinedIfActive = (): boolean => { - const stack = useUiStore().rightDrawerViewStack - if (stack && stack.length > 0) { - return stack[stack.length - 1] === props.drawer - } + // const stack = useUiStore().rightDrawerViewStack + // if (stack && stack.length > 0) { + // return stack[stack.length - 1] === props.drawer + // } return false } diff --git a/src/env.d.ts b/src/env.d.ts index dd757b1c..12dcd189 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -1,5 +1,3 @@ -/* eslint-disable */ - declare namespace NodeJS { interface ProcessEnv { NODE_ENV: string; diff --git a/src/layouts/PwaPageLayout.vue b/src/layouts/PwaPageLayout.vue index 89aa1da8..edf894ce 100644 --- a/src/layouts/PwaPageLayout.vue +++ b/src/layouts/PwaPageLayout.vue @@ -15,18 +15,18 @@
- - {{useUiStore().sharingMqttUrl}}: {{ useUiStore().mqttOffline }} - + + +
-
- -
+ + + + + + @@ -53,37 +53,20 @@ import {ref, watchEffect} from 'vue'; import {useMeta, useQuasar} from "quasar"; import {useRouter} from "vue-router"; -import {useNotificationsStore} from "src/stores/notificationsStore"; import Navigation from "src/components/Navigation.vue" -import {useSearchStore} from "src/search/stores/searchStore"; import _ from "lodash"; import {useSpacesStore} from "src/spaces/stores/spacesStore" -import OpenTabsThresholdWidget from 'src/components/widgets/OpenTabsThresholdWidget.vue' -import SpacesSelectorWidget from 'src/spaces/widgets/SpacesSelectorWidget.vue' -import SearchWidget from 'src/components/widgets/SearchWidget.vue' import {DrawerTabs, UserLevel, useUiStore} from "src/ui/stores/uiStore"; -import NotificationDialog from "components/dialogues/NotificationDialog.vue" -import {usePermissionsStore} from "src/stores/permissionsStore"; -import {Notification, NotificationStatus} from "src/models/Notification"; import {useUtils} from "src/core/services/Utils"; -import DrawerRight from "components/DrawerRight.vue"; -import ExportDialog from "components/dialogues/ExportDialog.vue"; -import ImportDialog from "components/dialogues/ImportDialog.vue"; import {Suggestion, SuggestionState} from "src/suggestions/models/Suggestion"; -import SuggestionDialog from "src/suggestions/dialogues/SuggestionDialog.vue"; import {useSuggestionsStore} from "src/suggestions/stores/suggestionsStore"; -import {FeatureIdent} from "src/app/models/FeatureIdent"; -import {useSettingsStore} from "src/stores/settingsStore" -import ToolbarButton from "components/widgets/ToolbarButton.vue"; const $q = useQuasar() const router = useRouter() const leftDrawerOpen = ref($q.screen.gt.lg) -const notificationsStore = useNotificationsStore() -const permissionsStore = usePermissionsStore() -const settingsStore = useSettingsStore() +// const notificationsStore = useNotificationsStore() const spacesStore = useSpacesStore() const spacesOptions = ref([]) @@ -98,8 +81,6 @@ $q.loadingBar.setDefaults({ position: 'top' }) -const settingsClicked = ref(false) - watchEffect(() => { suggestions.value = useSuggestionsStore().getSuggestions([SuggestionState.NEW, SuggestionState.DECISION_DELAYED]) }) @@ -113,9 +94,6 @@ watchEffect(() => { .concat({id: '', label: 'create new space'}) }) -//@ts-ignore -const appVersion = import.meta.env.PACKAGE_VERSION - useMeta(() => { return { // @ts-ignore @@ -123,21 +101,8 @@ useMeta(() => { } }) - -const title = () => { - return inBexMode() ? 'Tabsets' : process.env.MODE === 'spa' ? - 'Tabsets Web' : 'Tabsets' -} - -const goHome = () => router.push("/") - -const toggleLeftDrawer = () => { - leftDrawerOpen.value = !leftDrawerOpen.value - useUiStore().toggleLeftDrawer() -} - const installNewVersion = (version: string) => { - notificationsStore.updateAvailable(false) + // notificationsStore.updateAvailable(false) chrome.tabs.create({ active: true, url: "https://tabsets.web.app/#/updatedTo/" + version @@ -145,29 +110,5 @@ const installNewVersion = (version: string) => { chrome.runtime.reload() } -const unreadNotifications = () => _.filter(notificationsStore.notifications, (n: Notification) => n.status === NotificationStatus.UNREAD) - -const showNotificationDialog = (nId: string) => $q.dialog({ - component: NotificationDialog, componentProps: { - notificationId: nId - } -}) - -const tabsClicked = (tab: DrawerTabs, data: object = {}) => useUiStore().rightDrawerSetActiveTab(tab, data) - -const showExportDialog = () => $q.dialog({component: ExportDialog}) -const showImportDialog = () => $q.dialog({component: ImportDialog}) - -const suggestionDialog = (s: Suggestion) => $q.dialog({ - component: SuggestionDialog, componentProps: { - suggestion: s - } -}) - -const dependingOnStates = () => - _.find(useSuggestionsStore().getSuggestions([SuggestionState.NEW, SuggestionState.DECISION_DELAYED]), s => s.state === SuggestionState.NEW) ? 'warning' : 'white' - -const toggleSettings = () => settingsClicked.value = !settingsClicked.value - diff --git a/src/notes b/src/notes index a883ca9e..a1e0bf00 160000 --- a/src/notes +++ b/src/notes @@ -1 +1 @@ -Subproject commit a883ca9eaa48dd1a6adb7ac61d12d7ffe6e07072 +Subproject commit a1e0bf00350df586b918778422fbfe7ebd900ecf diff --git a/src/pages/FullpageStart.vue b/src/pages/FullpageStart.vue index bee100b8..93ffb9a3 100644 --- a/src/pages/FullpageStart.vue +++ b/src/pages/FullpageStart.vue @@ -36,7 +36,7 @@ timer = setTimeout(() => { chrome.tabs.getCurrent((t?: chrome.tabs.Tab ) => { //console.log("got tab", t) const options = { - tabId: t.id, + tabId: t?.id || "", enabled: false } console.log("setting options", options) diff --git a/src/pages/PreviewPage.vue b/src/pages/PreviewPage.vue index 1281c88d..7f078077 100644 --- a/src/pages/PreviewPage.vue +++ b/src/pages/PreviewPage.vue @@ -84,16 +84,16 @@ watchEffect(async () => { console.log("found", found) if (found && found.url) { title.value = found.title || 'unknown' - const request = await TabsetService.getRequestForUrl(found.url) - if (request && request.requestInfo && _.find(Object.values(request.requestInfo.headers), (v: any) => v.name === 'x-frame-options')) { - src.value = 'data:text/html,

cannot open this page in iFrame ;(

' - } else { - if (found.url) { - src.value = `${process.env.BACKEND_URL}/preview/${btoa(found.url)}` - } else { - src.value = 'data:text/html,

loading....

' - } - } + // const request = await TabsetService.getRequestForUrl(found.url) + // if (request && request.requestInfo && _.find(Object.values(request.requestInfo.headers), (v: any) => v.name === 'x-frame-options')) { + // src.value = 'data:text/html,

cannot open this page in iFrame ;(

' + // } else { + // if (found.url) { + // src.value = `${process.env.BACKEND_URL}/preview/${btoa(found.url)}` + // } else { + // src.value = 'data:text/html,

loading....

' + // } + // } } }) diff --git a/src/pages/SearchPage.vue b/src/pages/SearchPage.vue index f2447c4a..e738069d 100644 --- a/src/pages/SearchPage.vue +++ b/src/pages/SearchPage.vue @@ -91,7 +91,7 @@ const newSearch = (term: string) => { h.item.favIconUrl, 0, 0, Math.round(100 - (100 * (h?.score || 1))), - h.item.tabsets, + [],//h.item.tabsets, [], _.map(h['matches' as keyof object], (m: any) => { return { @@ -102,9 +102,9 @@ const newSearch = (term: string) => { h.item.description, h.item.keywords ) - if (h.item.bookmarkId) { - theHit.bookmarkId = h.item.bookmarkId - } + // if (h.item.bookmarkId) { + // theHit.bookmarkId = h.item.bookmarkId + // } tabsetHits.value.push(theHit) }) } diff --git a/src/pages/SearchResultPage.vue b/src/pages/SearchResultPage.vue index fede5981..9bf91a07 100644 --- a/src/pages/SearchResultPage.vue +++ b/src/pages/SearchResultPage.vue @@ -90,7 +90,7 @@ const newSearch = (term: string) => { h.item.favIconUrl, 0, 0, Math.round(100 - (100 * (h?.score || 1))), - h.item.tabsets, + [], //h.item!.tabsets, [], _.map(h['matches' as keyof object], (m: any) => { return { @@ -101,9 +101,9 @@ const newSearch = (term: string) => { h.item.description, h.item.keywords ) - if (h.item.bookmarkId) { - theHit.bookmarkId = h.item.bookmarkId - } + // if (h.item!.bookmarkId) { + // theHit.bookmarkId = h.item!.bookmarkId + // } tabsetHits.value.push(theHit) }) } diff --git a/src/pages/SettingsPage.vue b/src/pages/SettingsPage.vue index 30da56ab..e90f35da 100644 --- a/src/pages/SettingsPage.vue +++ b/src/pages/SettingsPage.vue @@ -180,7 +180,7 @@
- +
diff --git a/src/pages/SidePanelResearchPage.vue b/src/pages/SidePanelResearchPage.vue index c08a489f..36f8a1e8 100644 --- a/src/pages/SidePanelResearchPage.vue +++ b/src/pages/SidePanelResearchPage.vue @@ -167,16 +167,16 @@ @@ -187,15 +187,15 @@
@@ -300,7 +300,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { let titleSuggestion = undefined switch (split.length) { case 1: - titleSuggestion = getTitleSuggestion(split[0]) + titleSuggestion = getTitleSuggestion(split[0]!) break case 2: titleSuggestion = getTitleSuggestion(split[0] + " " + split[1]) diff --git a/src/pages/TabPage.vue b/src/pages/TabPage.vue index 954821ba..509f4a58 100644 --- a/src/pages/TabPage.vue +++ b/src/pages/TabPage.vue @@ -188,34 +188,34 @@ data is collected if the 'analyse tabs' feature is active. - Status Code: {{ request['statusCode'] }}

- - - - - - - + Status Code: {{ request['statusCode' as keyof object] }}

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -226,35 +226,35 @@ If this does not work as expected, you might have to refresh or reinstall the tabsets extension. - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -262,35 +262,35 @@
This is data derived from the tab's html content - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -388,7 +388,7 @@ onMounted(() => { }) watchEffect(() => { - const tabId = route.params.id.toString() || '' + const tabId = route.params.id?.toString() || '' console.log("got tabId", tabId) const tabInfo = useTabsetsStore().getTabAndTabsetId(tabId) //.then((tabInfo: TabAndTabsetId | undefined) => { @@ -561,28 +561,16 @@ const getForKey = (key: any) => { return "" } -const metaDataLabel = () => "Meta Data (" + metaRows.value.length + ")" const requestDataLabel = () => "Request Header (" + requestRows.value.length + ")" const metaLinksDataLabel = () => "Meta Links (" + metaLinkRows.value.length + ")" const linksDataLabel = () => "Links (" + Object.keys(linkRows.value || []).length + ")" const openNameLink = (key: string) => NavigationService.openOrCreateTab(["https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/" + key]) -const showNameLink = (key: string) => key.indexOf(":") < 0; - -const openValueLink = (name: any, value: string) => { - if ("fb:page_id" === name) { - NavigationService.openOrCreateTab(["https://www.facebook.com/" + value]) - } else if ("twitter:account_id" === name) { - NavigationService.openOrCreateTab(["https://twitter.com/i/user/" + value]) - } - return -} -const showValueLink = (name: string) => "fb:page_id" === name || "twitter:account_id" === name const analyseTab = () => { if (selectedTab.value) { - searchStore.reindexTab(selectedTab.value) - .then((windowId: number) => { - }) + // searchStore.reindexTab(selectedTab.value) + // .then((windowId: number) => { + // }) } } diff --git a/src/pages/helper/SyncingSettings.vue b/src/pages/helper/SyncingSettings.vue_ similarity index 99% rename from src/pages/helper/SyncingSettings.vue rename to src/pages/helper/SyncingSettings.vue_ index 01063ed9..b49d9cef 100644 --- a/src/pages/helper/SyncingSettings.vue +++ b/src/pages/helper/SyncingSettings.vue_ @@ -226,7 +226,6 @@ diff --git a/src/pages/sidepanel/SidePanelEntitiesPage.vue b/src/pages/sidepanel/SidePanelEntitiesPage.vue deleted file mode 100644 index ff79ca13..00000000 --- a/src/pages/sidepanel/SidePanelEntitiesPage.vue +++ /dev/null @@ -1,145 +0,0 @@ - - - diff --git a/src/pages/sidepanel/SidePanelMessagesPage.vue b/src/pages/sidepanel/SidePanelMessagesPage.vue index b4a8a155..f08c2ded 100644 --- a/src/pages/sidepanel/SidePanelMessagesPage.vue +++ b/src/pages/sidepanel/SidePanelMessagesPage.vue @@ -35,14 +35,13 @@ import FirstToolbarHelper2 from "pages/sidepanel/helper/FirstToolbarHelper2.vue"; import {useUiStore} from "src/ui/stores/uiStore"; -import {onMounted, ref, watchEffect} from "vue"; +import {onMounted, ref} from "vue"; import Analytics from "src/core/utils/google-analytics"; import SidePanelToolbarTabNavigationHelper from "src/opentabs/pages/SidePanelToolbarTabNavigationHelper.vue"; import SidePanelToolbarButton from "src/core/components/SidePanelToolbarButton.vue"; -import {Message} from "src/models/Message"; import {SidePanelViews} from "src/app/models/SidePanelViews"; -const messages = ref([]) +const messages = ref([]) onMounted(() => { Analytics.firePageViewEvent('SidePanelMessagesPage', document.location.href); diff --git a/src/pages/sidepanel/SidePanelPageContextMenu.vue b/src/pages/sidepanel/SidePanelPageContextMenu.vue index 17430964..bb030612 100644 --- a/src/pages/sidepanel/SidePanelPageContextMenu.vue +++ b/src/pages/sidepanel/SidePanelPageContextMenu.vue @@ -177,17 +177,17 @@ const restoreInNewWindow = (tabsetId: string, windowName: string | undefined = u const startAutoSwitchingTab = (tabsetId: string) => { const tabset = useTabsetsStore().getTabset(tabsetId) - if (tabset && tabset.tabs?.length > 1 && tabset.tabs[0].url) { + if (tabset && tabset.tabs?.length > 1 && tabset.tabs[0]!.url) { const tabs = tabset.tabs let tabIndex = 0 - NavigationService.openSingleTab(tabset.tabs[tabIndex].url || '') + NavigationService.openSingleTab(tabset.tabs[tabIndex]!.url || '') .then(tab => { console.log("tabId", tab) let interval = setInterval(() => { try { const nextTab = tabs[++tabIndex % tabs.length] - console.log("updating ", nextTab.url) - chrome.tabs.update(tab.id || 0, {url: nextTab.url}, + console.log("updating ", nextTab!.url) + chrome.tabs.update(tab.id || 0, {url: nextTab!.url}, cb => { if (chrome.runtime.lastError) { console.warn("got runtime error", chrome.runtime.lastError) diff --git a/src/pages/sidepanel/SidePanelRssPage.vue b/src/pages/sidepanel/SidePanelRssPage.vue index 591d7cff..4d310a37 100644 --- a/src/pages/sidepanel/SidePanelRssPage.vue +++ b/src/pages/sidepanel/SidePanelRssPage.vue @@ -12,7 +12,7 @@
- {{ rss.title }} + rss.title
@@ -27,28 +27,28 @@
-
{{ rss.description }}
-
Created {{ date.formatDate(rss.published, 'DD.MM.YYYY HH:mm') }}
+
rss.description
+
Created date.formatDate(rss.published, 'DD.MM.YYYY HH:mm')
- - + + + +
{{ getAsHtml(entry, "title") }}
-
{{ entry.description }}
-
{{ formatDate(entry.published) }}
- this entry was created at - {{ date.formatDate(entry.published, 'DD.MM.YYYY HH:mm') }} - + + + + +
diff --git a/src/pages/sidepanel/SidePanelTabDetails.vue b/src/pages/sidepanel/SidePanelTabDetails.vue index 925af024..9372f60c 100644 --- a/src/pages/sidepanel/SidePanelTabDetails.vue +++ b/src/pages/sidepanel/SidePanelTabDetails.vue @@ -280,7 +280,7 @@
- {{ ref.data[0]['title' as keyof object] }}: + {{ ref.data[0]!['title' as keyof object] }}:
@@ -431,7 +431,7 @@ watchEffect(() => { useThumbnailsService().getThumbnailFor(tab.value.url) .then(data => { if (data) { - thumbnail.value = data['thumbnail' as keyof object] + thumbnail.value = data['thumbnail' as keyof object]! } else { thumbnail.value = '' } diff --git a/src/pages/sidepanel/SidePanelTabsetDescriptionPage.vue b/src/pages/sidepanel/SidePanelTabsetDescriptionPage.vue index b24b8596..31fabf31 100644 --- a/src/pages/sidepanel/SidePanelTabsetDescriptionPage.vue +++ b/src/pages/sidepanel/SidePanelTabsetDescriptionPage.vue @@ -64,7 +64,7 @@ import {onMounted, PropType, ref, watchEffect} from "vue"; import EditorJS, {OutputData} from "@editorjs/editorjs"; -import EditorJsConfig from "src/utils/EditorJsConfig"; +// import EditorJsConfig from "src/utils/EditorJsConfig"; import {openURL} from "quasar"; import {useCommandExecutor} from "src/core/services/CommandExecutor"; import {DeleteTabsetDescriptionCommand} from "src/tabsets/commands/DeleteTabsetDescriptionCommand"; @@ -72,7 +72,7 @@ import {useUiStore} from "src/ui/stores/uiStore"; const props = defineProps({ tabsetId: {type: String, required: true}, - tabsetDesc: {type: Object, required: true} + tabsetDesc: {type: String, required: true} }) const showDescription = ref(false) @@ -110,7 +110,7 @@ onMounted(() => { readOnly: false, minHeight: 1, data: (props.tabsetDesc || {}) as OutputData, - tools: EditorJsConfig.toolsconfig + // tools: EditorJsConfig.toolsconfig }); // if the editor is readonly from the start, I cannot update it when tabset.page changes setTimeout(() => { @@ -137,7 +137,7 @@ watchEffect(() => { const fromStore = useUiStore().getTabsetDescriptionHeight(props.tabsetId) if (fromStore === undefined) { const blocksCount = props.tabsetDesc ? props.tabsetDesc['blocks' as keyof object]?.length : 0 - let minHeight = Math.min(20 + blocksCount * 30, 110) + let minHeight = Math.min(20 + (blocksCount || 0) * 30, 110) scrollAreaHeight.value = minHeight useUiStore().setTabsetDescriptionHeight(props.tabsetId, minHeight) } else { @@ -172,7 +172,7 @@ const changeSize = (diff: number) => { } const deleteTabsetDescription = () => - useCommandExecutor().executeFromUi(new DeleteTabsetDescriptionCommand(props.tabsetId, props.tabsetDesc)) + useCommandExecutor().executeFromUi(new DeleteTabsetDescriptionCommand(props.tabsetId, props.tabsetDesc!)) diff --git a/src/pages/sidepanel/SidePanelTagsListViewer.vue b/src/pages/sidepanel/SidePanelTagsListViewer.vue index bbf4b5f7..f73cd8fe 100644 --- a/src/pages/sidepanel/SidePanelTagsListViewer.vue +++ b/src/pages/sidepanel/SidePanelTagsListViewer.vue @@ -148,7 +148,7 @@ watchEffect(() => { responsive: false, events: ['click'], onClick: (e, b) => { - selectTag(b[0].element['text' as keyof object]) + selectTag(b[0]!.element['text' as keyof object]) }, elements: { word: { diff --git a/src/pages/sidepanel/helper/FirstToolbarHelper2.vue b/src/pages/sidepanel/helper/FirstToolbarHelper2.vue index 1f721faa..a1228bda 100644 --- a/src/pages/sidepanel/helper/FirstToolbarHelper2.vue +++ b/src/pages/sidepanel/helper/FirstToolbarHelper2.vue @@ -14,7 +14,7 @@ + :search-hits="props.searchHits!"/> diff --git a/src/pages/sidepanel/helper/PngViewHelper.vue b/src/pages/sidepanel/helper/PngViewHelper.vue index 8b3a2df2..5ca618d3 100644 --- a/src/pages/sidepanel/helper/PngViewHelper.vue +++ b/src/pages/sidepanel/helper/PngViewHelper.vue @@ -33,6 +33,6 @@ const emits = defineEmits(['newSnapshotWasClicked','newClipWasClicked']) const openMhtml = () => window.open(chrome.runtime.getURL(`www/index.html#/mainpanel/${props.extension}/${props.tabId}/${props.index}`)); // const openMhtml = () => window.open(chrome.runtime.getURL(`www/mirror.html#/mainpanel/${props.extension}/${props.tabId}/${props.index}`)); -const deleteSnapshot = () => useSnapshotsService().deleteSnapshot(props.tabId, props.index) +const deleteSnapshot = () => useSnapshotsService().deleteSnapshot(props.tabId) diff --git a/src/pages/sidepanel/helper/SearchWithTransitionHelper.vue b/src/pages/sidepanel/helper/SearchWithTransitionHelper.vue index 3021a257..cb1c4041 100644 --- a/src/pages/sidepanel/helper/SearchWithTransitionHelper.vue +++ b/src/pages/sidepanel/helper/SearchWithTransitionHelper.vue @@ -5,7 +5,7 @@ leave-active-class="animated fadeOutRight"> diff --git a/src/pages/sidepanel/helper/TabDetailsSearchIndex.vue b/src/pages/sidepanel/helper/TabDetailsSearchIndex.vue index 47b6d662..f657fb50 100644 --- a/src/pages/sidepanel/helper/TabDetailsSearchIndex.vue +++ b/src/pages/sidepanel/helper/TabDetailsSearchIndex.vue @@ -20,7 +20,7 @@