diff --git a/.circleci/config.yml b/.circleci/config.yml
index bb008867fa..57a6c20442 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -69,15 +69,18 @@ jobs:
resource_class: large
docker:
- image: cimg/node:18.19
+ environment:
+ # This is required to run the tests
+ NODE_OPTIONS: --max_old_space_size=4096
- image: docker.elastic.co/elasticsearch/elasticsearch:7.9.1
environment:
- - "ES_JAVA_OPTS=-Xms256m -Xmx256m"
- - "discovery.type=single-node"
- - "cluster.name=datashare"
+ ES_JAVA_OPTS: -Xms256m -Xmx256m
+ discovery.type: single-node
+ cluster.name: datashare
# CORS
- - "http.cors.enabled=true"
- - "http.cors.allow-origin=*"
- - "http.cors.allow-methods=OPTIONS, HEAD, GET, POST, PUT, DELETE"
+ http.cors.enabled: "true"
+ http.cors.allow-origin: "*"
+ http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
name: elasticsearch
working_directory: ~/datashare-client
steps:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000000..7dd9f4efd9
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,41 @@
+# Workflow name
+name: Build and Publish Storybook to GitHub Pages
+
+on:
+ push:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+jobs:
+
+ publish:
+ if: github.ref == 'refs/heads/feat/new-design'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Node 18
+ uses: actions/setup-node@v3
+ with:
+ node-version: '18.x'
+ cache: 'yarn'
+
+ - name: Install Node dependencies
+ run: yarn --frozen-lockfile
+
+ - name: Build storybook artifacts
+ run: yarn build:storybook
+
+ - name: Upload storybook artifacts
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: storybook-static
+
+ - name: Deploy artifact to Github Pages
+ uses: actions/deploy-pages@v4
+
+
diff --git a/.gitignore b/.gitignore
index 0ab0f33383..83010543e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@ package-lock.json
*.sln
*.sw*
*.iml
+
+*storybook.log
diff --git a/.storybook/decorators/murmur.js b/.storybook/decorators/murmur.js
new file mode 100644
index 0000000000..cac1261ad7
--- /dev/null
+++ b/.storybook/decorators/murmur.js
@@ -0,0 +1,19 @@
+import Murmur from '@icij/murmur-next'
+import { getCurrentInstance } from 'vue'
+
+export const withMurmur = (config = {},
+ useConfig = true,
+ useI18n = false,
+ useBootstrap = false,
+ registerComponents = true) => {
+ return () => ({
+ setup () {
+ const { app } = getCurrentInstance()?.appContext
+ Murmur.config.merge(config)
+ app.use(Murmur, { useConfig, useI18n, useBootstrap, registerComponents })
+ },
+ template: ''
+ })
+}
+
+export default { withMurmur }
diff --git a/.storybook/decorators/vuex.js b/.storybook/decorators/vuex.js
new file mode 100644
index 0000000000..e1fb869936
--- /dev/null
+++ b/.storybook/decorators/vuex.js
@@ -0,0 +1,30 @@
+import { createStore } from 'vuex'
+import { getCurrentInstance } from 'vue'
+import {identity} from "lodash";
+
+export const withVuex = (config = {}) => {
+ return () => ({
+ setup () {
+ const { app } = getCurrentInstance()?.appContext
+ app.use(createStore(config))
+ },
+ template: ''
+ })
+}
+
+
+export const storeDecoratorPipelineChainByCategory = withVuex({
+ modules: {
+ pipelines: {
+ namespaced: true,
+ getters: {
+ applyPipelineChainByCategory() {
+ return () => {
+ return identity
+ }
+ }
+ }
+ }
+ }
+})
+export default { withVuex, storeDecoratorPipelineChainByCategory }
diff --git a/.storybook/main.js b/.storybook/main.js
new file mode 100644
index 0000000000..839e4d42a9
--- /dev/null
+++ b/.storybook/main.js
@@ -0,0 +1,21 @@
+/** @type { import('@storybook/vue3-vite').StorybookConfig } */
+const config = {
+ core: {
+ disableTelemetry: true
+ },
+ stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+ addons: [
+ "@storybook/addon-links",
+ "@storybook/addon-essentials",
+ "@storybook/addon-interactions",
+ '@storybook/addon-themes',
+ 'storybook-addon-vue-slots',
+ "storybook-addon-pseudo-states"
+ ],
+ framework: {
+ name: "@storybook/vue3-vite",
+ options: {},
+ },
+}
+
+export default config
diff --git a/.storybook/manager.js b/.storybook/manager.js
new file mode 100644
index 0000000000..9a2cbc605b
--- /dev/null
+++ b/.storybook/manager.js
@@ -0,0 +1,4 @@
+import { addons } from '@storybook/manager-api'
+import theme from './theme'
+
+addons.setConfig({ navSize: 300, theme })
diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html
new file mode 100644
index 0000000000..21291f233d
--- /dev/null
+++ b/.storybook/preview-head.html
@@ -0,0 +1,5 @@
+
+
+
diff --git a/.storybook/preview.js b/.storybook/preview.js
new file mode 100644
index 0000000000..82377070e9
--- /dev/null
+++ b/.storybook/preview.js
@@ -0,0 +1,137 @@
+/** @type { import('@storybook/vue3').Preview } */
+import { setup } from '@storybook/vue3'
+import { useArgs } from '@storybook/preview-api'
+import { styled } from '@storybook/theming'
+import { withThemeByDataAttribute } from '@storybook/addon-themes'
+import { createBootstrap } from 'bootstrap-vue-next'
+import { createI18n } from 'vue-i18n'
+import { createVueWait } from 'vue-wait'
+import Vue3Toastify from 'vue3-toastify'
+
+import messages from '@/lang/en'
+import settings from '@/utils/settings'
+
+import './preview.scss'
+
+setup((app) => {
+ const vueWait = createVueWait({ useVuex: false })
+ const bootstrap = createBootstrap({
+ directives: true,
+ components: {
+ BPopover: {
+ offset: '16px'
+ },
+ BTooltip: {
+ offset: '6px',
+ delay: {
+ show: 500,
+ hide: 0
+ }
+ }
+ }
+ })
+ const i18n = createI18n({
+ warnHtmlInMessage: 'off',
+ warnHtmlMessage: 'off',
+ globalInjection: true,
+ allowComposition: true,
+ legacy: true,
+ locale: settings.defaultLocale,
+ fallbackLocale: settings.defaultLocale,
+ messages: {
+ [settings.defaultLocale]: messages
+ }
+ })
+ app.use(vueWait)
+ app.use(bootstrap)
+ app.use(i18n)
+ app.use(Vue3Toastify)
+})
+
+const decorators = [
+ withThemeByDataAttribute({
+ themes: {
+ light: 'light',
+ dark: 'dark'
+ },
+ defaultTheme: 'light',
+ attributeName: 'data-bs-theme'
+ }),
+ /**
+ * Support `v-model` for vue
+ * @see {@link https://craigbaldwin.com/blog/updating-args-storybook-vue/}
+ */
+ (story, context) => {
+ const [args, updateArgs] = useArgs()
+ if ('modelValue' in args) {
+ const update = args['onUpdate:model-value'] || args['onUpdate:modelValue']
+ args['onUpdate:model-value'] = undefined
+ args['onUpdate:modelValue'] = (...vals) => {
+ update?.(...vals)
+ /**
+ * Arg with `undefined` will be deleted by `deleteUndefined()`, then loss of reactive
+ * @see {@link https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/src/modules/store/ArgsStore.ts#L63}
+ */
+ const modelValue = vals[0] === undefined ? null : vals[0]
+ updateArgs({ modelValue })
+ }
+ }
+ return story({ ...context, updateArgs })
+ }
+]
+
+
+const style = {
+ fontFamily: 'var(--bs-font-sans-serif) !important',
+ fontSize: '1rem',
+}
+
+const headingsStyle = {
+ fontFamily: 'var(--bs-font-sans-serif) !important',
+ fontWeight: 'var(--bs-headings-weight-bold)'
+}
+
+const h1Style = {
+ ...headingsStyle,
+ fontSize: '2.5rem'
+}
+
+const aStyle = {
+ ...style,
+ color: 'rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));',
+ '&:hover': {
+ textDecoration: 'underline'
+ }
+}
+
+const preview = {
+ decorators,
+ parameters: {
+ docs: {
+ components: {
+ h1: styled.h1(() => h1Style),
+ h2: styled.h2(() => headingsStyle),
+ h3: styled.h3(() => headingsStyle),
+ h4: styled.h4(() => headingsStyle),
+ h5: styled.h5(() => headingsStyle),
+ h6: styled.h6(() => headingsStyle),
+ a: styled.a(() => aStyle),
+ section: styled.section(() => style),
+ p: styled.p(() => style),
+ li: styled.li(() => style),
+ div: styled.div(() => style),
+ pre: styled.div(() => ({ })),
+ span: styled.span(() => style),
+ input: styled.input(() => style)
+ },
+ },
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/i,
+ },
+ },
+ },
+}
+
+export default preview
diff --git a/.storybook/preview.scss b/.storybook/preview.scss
new file mode 100644
index 0000000000..6a787ae3c9
--- /dev/null
+++ b/.storybook/preview.scss
@@ -0,0 +1,65 @@
+@import '@/main.scss';
+
+.bg-striped {
+ background: repeating-linear-gradient(
+ 45deg,
+ #dfdddd,
+ #dfdddd 10px,
+ #cfcccc 10px,
+ #cfcccc 20px
+ );
+ width: 500px;
+}
+
+@include color-mode(dark) {
+ .bg-striped {
+ background: repeating-linear-gradient(
+ 45deg,
+ #222,
+ #333 10px,
+ #444 10px,
+ #444 20px
+ );
+ }
+}
+
+h1 {
+ font-family: var(--bs-font-sans-serif) !important;
+ font-weight: var(--bs-body-font-weight);
+ font-size: 2.5rem;
+}
+
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: var(--bs-font-sans-serif);
+ font-weight: var(--bs-body-font-weight);
+}
+
+pre.prismjs {
+ padding: 0.75rem;
+ font-size: 0.90rem;
+}
+
+.docs-story {
+ background: var(--bs-body-bg)
+}
+
+.btn.pseudo-focus {
+ box-shadow: var(--bs-btn-active-shadow), var(--bs-btn-focus-box-shadow);
+}
+
+.btn.pseudo-hover {
+ color: var(--bs-btn-hover-color);
+ background-color: var(--bs-btn-hover-bg);
+ border-color: var(--bs-btn-hover-border-color);
+}
+
+.btn.pseudo-active {
+ color: var(--bs-btn-active-color);
+ background-color: var(--bs-btn-active-bg);
+ border-color: var(--bs-btn-active-border-color);
+ box-shadow: var(--bs-btn-active-shadow);
+}
diff --git a/.storybook/theme.js b/.storybook/theme.js
new file mode 100644
index 0000000000..8cc57c6326
--- /dev/null
+++ b/.storybook/theme.js
@@ -0,0 +1,47 @@
+
+
+import { create } from '@storybook/theming/create'
+import brandImage from '../src/assets/images/logo-design-system.png'
+
+export default create({
+ base: 'light',
+ brandTitle: 'Datashare design system',
+ brandUrl: '?=/',
+ brandTarget: '_self',
+ brandImage,
+
+ colorPrimary: '#193D87',
+ colorSecondary: '#FA4070',
+
+ // UI
+ appBg: '#FFF',
+ appContentBg: '#F0F0F0',
+ appPreviewBg: '#FFF',
+ appBorderColor: 'rgba(0,0,0, .175)',
+ appBorderRadius: 4,
+
+ // Fonts
+ fontBase: '-apple-system, BlinkMacSystemFont, "Inter", "Source Sans Pro", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
+ fontCode: 'SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
+
+ // Text colors
+ textColor: '#000',
+ textInverseColor: '#FFF',
+ textMutedColor: '#717171',
+
+ // Toolbar default and active colors
+ barTextColor: '#333',
+ barHoverColor: '#000',
+ barSelectedColor: '#193D87',
+ barBg: '#e9e9e9',
+
+ // Form colors
+ buttonBg: '#193D87',
+ buttonBorder: 'rgba(0,0,0,.1)',
+ booleanBg: '#fff',
+ booleanSelectedBg: '#FA4070',
+ inputBg: '#fff',
+ inputBorder: 'rgba(0,0,0,.1)',
+ inputTextColor: '#000',
+ inputBorderRadius: 4
+})
diff --git a/.storybook/utils.js b/.storybook/utils.js
new file mode 100644
index 0000000000..ff5f696755
--- /dev/null
+++ b/.storybook/utils.js
@@ -0,0 +1,64 @@
+import { VARIANTS, VARIANTS_PLAIN } from "@/enums/variants"
+import { LAYOUTS } from "@/enums/layouts"
+import { BUTTON_SIZES, BREAKPOINT_SIZES } from "@/enums/sizes"
+import { FORMAT_FROM_NOW, FORMAT_LONG, FORMAT_SHORT } from "@/utils/humanDate"
+import { ICON_WEIGHTS } from "@/enums/iconWeights"
+import { ENTITY_CATEGORIES } from "@/enums/entityCategories"
+import { OFFCANVAS_PLACEMENTS } from "@/enums/placements"
+
+export const variantsArgType = {
+ control: 'select',
+ options: VARIANTS
+}
+export const variantsPlainArgType = {
+ control: 'select',
+ options: VARIANTS_PLAIN
+}
+export const buttonSizesArgType = {
+ control: 'inline-radio',
+ options: BUTTON_SIZES
+}
+export const breakpointSizeArgType = {
+ control: 'select',
+ options: BREAKPOINT_SIZES
+}
+export const dateFormatArgType = {
+ control: 'select',
+ options: [FORMAT_SHORT, FORMAT_LONG, FORMAT_FROM_NOW]
+}
+export const iconWeightsArgType = {
+ control: 'select',
+ options: ICON_WEIGHTS
+}
+export const entityCategoriesArgType = {
+ control: 'select',
+ options: ENTITY_CATEGORIES
+}
+export const inputTypeArgType = {
+ control: 'select',
+ options: [
+ 'text',
+ 'number',
+ 'email',
+ 'password',
+ 'search',
+ 'url',
+ 'tel',
+ 'date',
+ 'time',
+ 'range',
+ 'color',
+ 'datetime',
+ 'datetime-local',
+ 'month',
+ 'week'
+ ]
+}
+export const layoutArgType = {
+ control: 'select',
+ options: Object.values(LAYOUTS)
+}
+export const offcanvasPlacementArgType = {
+ control: 'select',
+ options: OFFCANVAS_PLACEMENTS
+}
diff --git a/Makefile b/Makefile
index 20122c6415..79b6d5b0d0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
run:
yarn serve
+storybook:
+ yarn storybook
+
clean:
rm -Rf ./dist
diff --git a/bin/presets/index.js b/bin/presets/index.js
new file mode 100644
index 0000000000..e444e647b9
--- /dev/null
+++ b/bin/presets/index.js
@@ -0,0 +1 @@
+export { PhosphorVuePreset } from './phosphor-vue'
diff --git a/bin/presets/phosphor-vue.js b/bin/presets/phosphor-vue.js
new file mode 100644
index 0000000000..7f7faef3f2
--- /dev/null
+++ b/bin/presets/phosphor-vue.js
@@ -0,0 +1,10 @@
+import keys from 'lodash/keys'
+import * as icons from '@phosphor-icons/vue'
+
+export function PhosphorVuePreset() {
+ const nameMatch = (name) => name.match(/^Ph[A-Z]/)
+
+ return {
+ '@phosphor-icons/vue': keys(icons).filter(nameMatch)
+ }
+}
diff --git a/bin/resolvers/index.js b/bin/resolvers/index.js
new file mode 100644
index 0000000000..265938c666
--- /dev/null
+++ b/bin/resolvers/index.js
@@ -0,0 +1 @@
+export { PhosphorVueResolver } from './phosphor-vue'
diff --git a/bin/resolvers/phosphor-vue.js b/bin/resolvers/phosphor-vue.js
new file mode 100644
index 0000000000..ceb8388f64
--- /dev/null
+++ b/bin/resolvers/phosphor-vue.js
@@ -0,0 +1,7 @@
+export function PhosphorVueResolver() {
+ return (name) => {
+ if (name.match(/^Ph[A-Z]/)) {
+ return { name, from: '@phosphor-icons/vue' }
+ }
+ }
+}
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 0000000000..822c186b67
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "target": "es6",
+ "paths": {
+ "@/*": ["./src/*"],
+ }
+ }
+}
diff --git a/package.json b/package.json
index 9942265888..3e7eff76d1 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
"name": "datashare-client",
"version": "11.2.1",
"private": false,
+ "type": "module",
"repository": {
"type": "git",
"url": "https://github.com/ICIJ/datashare-client/"
@@ -12,81 +13,100 @@
"test": "yarn test:unit",
"test:unit": "vitest --run",
"test:unit:watch": "vitest",
- "lint": "eslint --ext .js,.mjs,.vue .",
+ "lint": "eslint --ext .js,.mjs,.vue --ignore-pattern storybook-static .",
"lint:fix": "yarn lint --fix",
"doc": "yarn doc:api && yarn doc:hooks && yarn doc:widgets",
"doc:dir": "mkdir -p dist/docs",
"doc:api": "npx jsdoc-to-markdown --plugin bin/dmd/plugin.js --separators --no-gfm --template bin/dmd/api.hbs src/core/*.js > 'dist/docs/api.md'",
"doc:hooks": "node bin/generateHook.js",
"doc:widgets": "npx jsdoc-to-markdown --plugin bin/dmd/plugin.js --separators --no-gfm --template bin/dmd/widgets.hbs src/store/widgets/*.js > 'dist/docs/widgets.md'",
- "predoc": "yarn doc:dir"
+ "predoc": "yarn doc:dir",
+ "storybook": "storybook dev -p 6006 --ci",
+ "build:storybook": "storybook build"
},
"dependencies": {
+ "@floating-ui/vue": "^1.1.5",
"@fortawesome/fontawesome": "^1.1.4",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.6",
- "@icij/murmur-next": "4.1.5",
+ "@icij/murmur-next": "4.3.20",
+ "@phosphor-icons/vue": "^2.2.1",
"@popperjs/core": "^2.11.8",
- "axios": "^1.7.2",
+ "axios": "^1.7.7",
"bodybuilder": "^2.5.0",
- "bootstrap": "5.3.3",
- "bootstrap-vue-next": "^0.22.1",
+ "bootstrap": "^5.3.3",
+ "bootstrap-vue-next": "^0.25.8",
"d3": "^7.6.1",
"elasticsearch-browser": "16.7.1",
"fuse.js": "^7.0.0",
- "image-js": "^0.35.5",
+ "image-js": "^0.35.6",
"intersection-observer": "^0.12.2",
- "json-formatter-js": "^2.5.15",
- "lodash": "^4.17.19",
+ "json-formatter-js": "^2.5.18",
+ "lodash": "^4.17.21",
"lucene": "^2.1.0",
"mitt": "^3.0.1",
"moment": "^2.29.4",
"mutationobserver-shim": "^0.3.7",
"path-browserify": "^1.0.1",
- "path-to-regexp": "^6.2.2",
+ "path-to-regexp": "^7.1.0",
"resize-observer-polyfill": "^1.5.1",
"string-to-color": "^2.2.2",
- "tiff": "^6.1.0",
+ "tiff": "^6.1.1",
"tiny-cookie": "^2.1.2",
- "v-calendar": "^3",
+ "v-calendar": "3.0.1",
"v-runtime-template": "^1.10.0",
- "v3-infinite-loading": "^1.3.1",
- "vue": "3.4.27",
+ "v3-infinite-loading": "^1.3.2",
+ "vue": "^3.5.12",
"vue-ellipse-progress": "^2.1.2",
- "vue-i18n": "^9.13.1",
- "vue-multiselect": "3.0.0",
- "vue-router": "^4.3.3",
+ "vue-i18n": "^9.14.1",
+ "vue-multiselect": "3.1.0",
+ "vue-router": "^4.4.5",
"vue-scrollto": "^2.20.0",
"vue-sticky-directive": "^0.0.10",
"vue-virtual-scroller": "^2.0.0-beta.8",
"vue-wait": "^1.5.3",
"vue3-perfect-scrollbar": "^2.0.0",
"vue3-shortkey": "^4.0.0",
- "vue3-toastify": "^0.2.1",
- "vuex": "^4",
- "vuex-persistedstate": "^4.0.0-beta.1",
+ "vue3-toastify": "^0.2.2",
+ "vuex": "^4.1.0",
+ "vuex-persistedstate": "^4.1.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz",
- "xss": "^1.0.13"
+ "xss": "^1.0.15"
},
"devDependencies": {
+ "@babel/eslint-parser": "^7.25.1",
"@icij/eslint-config-icij": "^1.0.2",
- "@vitejs/plugin-vue": "^5.0.4",
+ "@storybook/addon-essentials": "^8.3.3",
+ "@storybook/addon-interactions": "^8.3.3",
+ "@storybook/addon-links": "^8.3.3",
+ "@storybook/addon-themes": "^8.3.3",
+ "@storybook/blocks": "^8.3.3",
+ "@storybook/test": "^8.3.3",
+ "@storybook/vue3": "^8.3.3",
+ "@storybook/vue3-vite": "^8.3.3",
+ "@vitejs/plugin-vue": "^5.1.2",
"@vitejs/plugin-vue2": "^2.3.1",
- "@vue/compiler-sfc": "^3.4.27",
+ "@vue/compiler-sfc": "^3.5.3",
"@vue/test-utils": "^2.4.6",
- "autoprefixer": "^10.4.19",
+ "autoprefixer": "^10.4.20",
+ "eslint-plugin-storybook": "^0.8.0",
"eslint-plugin-vitest": "^0.5.4",
"eslint-plugin-vitest-globals": "^1.5.0",
"front-matter": "^4.0.2",
"handlebars": "^4.7.6",
- "jsdoc-to-markdown": "^8.0.0",
- "jsdom": "^24.0.0",
- "sass": "^1.77.6",
- "unplugin-vue-components": "^0.27.0",
- "vite": "^5.3.1",
- "vitest": "^1.6.0",
+ "jsdoc-to-markdown": "^8.0.3",
+ "jsdom": "^24.1.1",
+ "sass": "^1.79.3",
+ "storybook": "^8.3.3",
+ "storybook-addon-pseudo-states": "^4.0.2",
+ "storybook-addon-vue-slots": "^0.9.30-next.2",
+ "storybook-vue3-router": "^5.0.0",
+ "unplugin-auto-import": "^0.18.5",
+ "unplugin-vue-components": "^0.27.4",
+ "vite": "^5.4.8",
+ "vitest": "^2.1.1",
"whatwg-fetch": "^3.5.0"
},
"postcss": {
@@ -114,13 +134,16 @@
"vitest-globals"
],
"extends": [
- "@icij/eslint-config-icij"
+ "@icij/eslint-config-icij",
+ "plugin:storybook/recommended"
],
"rules": {
"vue/no-v-model-argument": "off",
"vue/no-v-for-template-key": "off",
"vue/no-custom-modifiers-on-v-model": "off",
- "vue/valid-v-slot": "off"
+ "vue/no-multiple-template-root": "off",
+ "vue/valid-v-slot": "off",
+ "import/extensions": "off"
}
}
}
diff --git a/public/404.html b/public/404.html
index 1adffbeddd..060bc82728 100644
--- a/public/404.html
+++ b/public/404.html
@@ -10,39 +10,39 @@
background-color: #212529;
color: #fff;
text-align: center;
- font-family: "Lato", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ font-family: "Inter", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
margin: 0;
}
a {
color: #a3a3a5;
text-decoration: none;
- }
-
+ }
+
div.dialog {
width: 95%;
max-width: 43em;
margin: 4em auto 0;
}
-
+
div.dialog svg {
margin: 2rem 2rem;
display: block;
max-width: calc(100% - 4rem);
}
-
+
div.dialog > div {
padding: 7px 12% 0;
border-radius: .25rem .25rem 0 0;
}
-
+
h1 {
font-size: 150%;
line-height: 1.5em;
margin-top: 3em;
margin-bottom: 0;
}
-
+
div.dialog > p {
margin: 0 0 1em;
padding: 1em;
@@ -60,7 +60,7 @@
ul.links .links__item:not(:last-of-type):after {
content: "|";
- margin: 0 1rem;
+ margin: 0 1rem;
}
@@ -75,15 +75,15 @@
.cls-2 {
fill: #fff;
}
-
+
.cls-3 {
fill: #de8e68
}
-
+
.cls-6 {
fill: #d37c59
}
-
+
.cls-9 {
fill: #dc8e6c
}
diff --git a/src/api/elasticsearch.js b/src/api/elasticsearch.js
index 6ff6b826ca..fd4efcae1d 100644
--- a/src/api/elasticsearch.js
+++ b/src/api/elasticsearch.js
@@ -1,4 +1,4 @@
-import { each, find, isEqual, replace } from 'lodash'
+import { isEqual, replace } from 'lodash'
import bodybuilder from 'bodybuilder'
import es from 'elasticsearch-browser'
@@ -96,7 +96,7 @@ export function datasharePlugin(Client) {
filter,
query = '*',
filters = [],
- isGlobalSearch = false,
+ contextualize = true,
options = {},
fields = [],
from = 0,
@@ -106,8 +106,10 @@ export function datasharePlugin(Client) {
// Avoid searching for nothing
query = ['', null, undefined].indexOf(query) === -1 ? query : '*'
let body = filter.body(bodybuilder(), options, from, size)
- if (!isGlobalSearch) {
- each(filters, (filter) => filter.addFilter(body))
+ if (contextualize) {
+ for (const filter of filters) {
+ filter.addFilter(body)
+ }
this.addQueryToFilter(query, body, fields)
}
body = body.size(0).rawOption('track_total_hits', true).build()
@@ -115,9 +117,9 @@ export function datasharePlugin(Client) {
}
Client.prototype._addFiltersToBody = function (filters, body) {
- each(filters, (filter) => {
+ for (const filter of filters) {
filter.applyTo(body)
- })
+ }
}
Client.prototype._addQueryToBody = function (query, body, fields = []) {
@@ -130,23 +132,6 @@ export function datasharePlugin(Client) {
)
}
- Client.prototype._addSortToBody = function (name = 'relevance', body) {
- const { field, desc } = find(settings.searchSortFields, { name }) || settings.searchSortFields[0]
- if (name === 'creationDateNewest' || name === 'creationDateOldest') {
- body.sort([
- {
- 'metadata.tika_metadata_dcterms_created': {
- order: desc ? 'desc' : 'asc',
- unmapped_type: 'date'
- }
- }
- ])
- } else {
- body.sort(field, desc ? 'desc' : 'asc')
- }
- if (field !== 'path') body.sort('path', 'asc')
- }
-
Client.prototype.rootSearch = function (filters, query, fields = []) {
const body = bodybuilder()
this._addFiltersToBody(filters, body)
@@ -159,7 +144,7 @@ export function datasharePlugin(Client) {
const body = this.rootSearch(filters, query, fields)
body.from(from).size(size)
- this._addSortToBody(sort, body)
+ body.sort(sort)
// Select only the Documents and not the NamedEntities
// Add an option to exclude the content
body.rawOption('_source', { includes: ['*'], excludes: ['content', 'content_translated'] })
@@ -182,27 +167,49 @@ export function datasharePlugin(Client) {
})
return body
}
- Client.prototype.searchDocs = function (
+
+ Client.prototype.searchDocs = function ({
index,
query = '*',
filters = [],
from = 0,
- size = 25,
- sort = 'relevance',
+ perPage = 25,
+ sort = { _score: { order: 'desc' } },
fields = []
- ) {
+ }) {
// Avoid searching for nothing
query = ['', null, undefined].indexOf(query) === -1 ? query : '*'
- const body = this._buildBody(from, size, filters, query, sort, fields).rawOption('track_total_hits', true).build()
+ const builder = this._buildBody(from, perPage, filters, query, sort, fields)
+ const body = builder.rawOption('track_total_hits', true).build()
return this._search({ index, body })
}
+ Client.prototype.ids = function (index, values = [], _source = null) {
+ const size = values.length
+ const body = { query: { ids: { values } } }
+ return this._search({ index, size, body, _source })
+ }
+
Client.prototype.countByProject = function (index, query = undefined, size = 1000) {
const aggs = { index: { terms: { field: '_index', size } } }
const body = { size: 0, query, aggs }
const preference = 'count-by-project'
return this._search({ index, body, preference })
}
+
+ Client.prototype.maxExtractionDateByProject = function (index, query = undefined, size = 1000) {
+ const aggs = {
+ index: {
+ terms: { field: '_index', size },
+ aggs: {
+ maxExtractionDate: { max: { field: 'extractionDate' } }
+ }
+ }
+ }
+ const body = { size: 0, query, aggs }
+ const preference = 'max-extraction-date-by-project'
+ return this._search({ index, body, preference })
+ }
}
const elasticsearch = new es.Client({
diff --git a/src/api/resources/Auth.js b/src/api/resources/Auth.js
index a2613b2394..d3ae6a0ff9 100644
--- a/src/api/resources/Auth.js
+++ b/src/api/resources/Auth.js
@@ -21,9 +21,6 @@ export default class Auth {
async _checkAuthentication() {
try {
- if (this.mode.name === 'local') {
- return 'local' // default username
- }
return this._getCookieUsername() || (await this._getBasicAuthUserName())
} catch (_) {
return null
diff --git a/src/api/resources/Document.js b/src/api/resources/Document.js
index 105b026572..e06eee2a30 100644
--- a/src/api/resources/Document.js
+++ b/src/api/resources/Document.js
@@ -1,4 +1,5 @@
import { compact, endsWith, filter, find, get, keys, last, pick, startsWith, trim } from 'lodash'
+import { markRaw } from 'vue'
import Murmur from '@icij/murmur-next'
import moment from 'moment'
import { extname } from 'path'
@@ -6,18 +7,20 @@ import { extname } from 'path'
import { Api } from '@/api'
import EsDoc from '@/api/resources/EsDoc'
import humanSize from '@/utils/humanSize'
-import { findContentTypeIcon } from '@/utils/font-awesome-files'
+import { findContentTypeIcon } from '@/utils/phosphor-icon-files'
import types from '@/utils/types.json'
const _parent = '_PARENT'
const _root = '_ROOT'
+const _position = '_POSITION'
const _separator = '/'
export default class Document extends EsDoc {
- constructor(raw, parent = null, root = null) {
+ constructor(raw, parent = null, root = null, position = 0) {
super(raw)
this.parent = parent
this.root = root
+ this.position = position
}
nl2br(str) {
return trim(str)
@@ -48,6 +51,12 @@ export default class Document extends EsDoc {
shortMetaName(name) {
return name.replace('tika_metadata_', '')
}
+ set position(position) {
+ this[_position] = isNaN(position) ? null : position
+ }
+ get position() {
+ return this[_position]
+ }
set parent(parent) {
this[_parent] = parent ? new Document(parent) : null
}
@@ -66,7 +75,7 @@ export default class Document extends EsDoc {
set content(content) {
this.set('_source.content', content)
}
- get metas() {
+ get metadata() {
return keys(this.source.metadata || {})
}
get shortId() {
@@ -144,9 +153,20 @@ export default class Document extends EsDoc {
get slicedNameToString() {
return this.slicedName.join(' › ')
}
+ get language() {
+ return this.get('_source.language')
+ }
+ get author() {
+ return this.get('_source.metadata.tika_metadata_dc_creator', null)
+ }
get highlight() {
return this.raw.highlight
}
+ get excerpt() {
+ const content = this.get(['highlight', 'content', 0], '')
+ const contentTranslated = this.get(['highlight', 'content_translated.content', 0], '')
+ return trim(content || contentTranslated)
+ }
get highlights() {
const content = this.get(['highlight', 'content'], [])
const contentTranslated = this.get(['highlight', 'content_translated.content'], [])
@@ -185,7 +205,7 @@ export default class Document extends EsDoc {
return get(types, [this.contentType, 'warning'], {})
}
get contentTypeIcon() {
- return findContentTypeIcon(this.contentType)
+ return markRaw(findContentTypeIcon(this.contentType))
}
get rootContentType() {
return this.root ? this.root.source.contentType : 'unknown'
@@ -240,9 +260,6 @@ export default class Document extends EsDoc {
get humanSize() {
return humanSize(this.contentLength, true)
}
- get index() {
- return this.raw._index
- }
get routerParams() {
return pick(this, ['index', 'id', 'routing'])
}
@@ -273,11 +290,6 @@ export default class Document extends EsDoc {
get messageTo() {
return this.get('_source.metadata.tika_metadata_message_to', null)
}
- get excerpt() {
- const content = this.get(['highlight', 'content', 0], '')
- const contentTranslated = this.get(['highlight', 'content_translated.content', 0], '')
- return trim(content || contentTranslated)
- }
set translations(translations) {
this.set('_source.content_translated', translations)
}
@@ -339,8 +351,8 @@ export default class Document extends EsDoc {
return this.get('_source.nerTags', []).length > 0
}
get hasBigContentTextLength() {
- // 25,000 characters
- return this.contentTextLength === undefined || this.contentTextLength === 0 || this.contentTextLength > 25e3
+ // 50,000 characters
+ return this.contentTextLength === undefined || this.contentTextLength === 0 || this.contentTextLength > 5e4
}
static get esName() {
return 'Document'
diff --git a/src/api/resources/EsDoc.js b/src/api/resources/EsDoc.js
index 86d520dd39..ee48b85152 100644
--- a/src/api/resources/EsDoc.js
+++ b/src/api/resources/EsDoc.js
@@ -1,20 +1,10 @@
-import { cloneDeep, extend, get, set } from 'lodash'
+import { cloneDeep, get, matches, set } from 'lodash'
const _raw = '_RAW'
export default class EsDoc {
- constructor(raw) {
+ constructor(raw = {}) {
this[_raw] = cloneDeep(raw)
- this.map(raw)
- }
- map(raw) {
- // Map the given object to document attribute
- return extend(this, {
- id: raw._id,
- routing: raw._routing || raw._id,
- version: raw._version,
- type: raw._type
- })
}
get(path, defaultValue) {
return get(this.raw, path, defaultValue)
@@ -22,6 +12,24 @@ export default class EsDoc {
set(path, value) {
return set(this.raw, path, value)
}
+ get id() {
+ return this.raw._id
+ }
+ get index() {
+ return this.raw._index
+ }
+ get routing() {
+ return this.raw._routing || this.id
+ }
+ get version() {
+ return this.raw._version
+ }
+ get type() {
+ return this.raw_.type
+ }
+ get eq() {
+ return matches({ id: this.id, index: this.index })
+ }
get source() {
return this.get('_source', {})
}
@@ -31,6 +39,9 @@ export default class EsDoc {
get serializedForStorage() {
return this.raw
}
+ get project() {
+ return this.get('_index')
+ }
static match(hit) {
const raw = hit.raw || hit
return get(raw, '_source.type', 'Document') === (this.esName || this.name)
diff --git a/src/api/resources/EsDocList.js b/src/api/resources/EsDocList.js
index 70363d7bf6..4a6761f685 100644
--- a/src/api/resources/EsDocList.js
+++ b/src/api/resources/EsDocList.js
@@ -4,10 +4,16 @@ import Document from '@/api/resources/Document'
import NamedEntity from '@/api/resources/NamedEntity'
const _raw = '_RAW'
+const _parents = '_PARENTS'
+const _roots = '_ROOTS'
+const _from = '_FROM'
export default class EsDocList {
- constructor(raw) {
+ constructor(raw, parents = null, roots = null, from = 0) {
this[_raw] = isEmpty(raw) ? EsDocList.emptyRaw : raw
+ this[_parents] = isEmpty(parents) ? EsDocList.emptyRaw : parents
+ this[_roots] = isEmpty(roots) ? EsDocList.emptyRaw : roots
+ this[_from] = isNaN(from) ? null : from
}
get(path, defaultValue) {
return get(this[_raw], path, defaultValue)
@@ -38,9 +44,21 @@ export default class EsDocList {
const response = new EsDocList(raw)
response.hits.forEach((hit) => this.push('hits.hits', hit))
}
+ findParent(id) {
+ return find(this[_parents].hits.hits, ({ _id }) => _id === id)
+ }
+ findRoot(id) {
+ return find(this[_roots].hits.hits, ({ _id }) => _id === id)
+ }
+ get from() {
+ return this[_from]
+ }
get hits() {
- return map(this.get('hits.hits', []), (hit) => {
- return EsDocList.instantiate(hit)
+ return map(this.get('hits.hits', []), (hit, i) => {
+ const parent = this.findParent(hit._source.parentDocument)
+ const root = this.findRoot(hit._source.rootDocument)
+ const position = this.from + i
+ return EsDocList.instantiate(hit, parent, root, position)
})
}
get aggregations() {
@@ -49,9 +67,9 @@ export default class EsDocList {
get total() {
return this[_raw].hits.total.value
}
- static instantiate(hit) {
+ static instantiate(hit, parent = null, root = null, position = 0) {
const Type = find(EsDocList.types, (Type) => Type.match(hit))
- return new Type(hit)
+ return new Type(hit, parent, root, position)
}
static none() {
return new EsDocList(EsDocList.emptyRaw)
diff --git a/src/api/resources/NamedEntity.js b/src/api/resources/NamedEntity.js
index afb360808a..8254e776e1 100644
--- a/src/api/resources/NamedEntity.js
+++ b/src/api/resources/NamedEntity.js
@@ -24,6 +24,9 @@ export default class NamedEntity extends EsDoc {
get mention() {
return this.source.mention
}
+ get extractor() {
+ return this.source.extractor
+ }
static get esName() {
return 'NamedEntity'
}
diff --git a/src/assets/fonts/Inter/Inter-Bold.eot b/src/assets/fonts/Inter/Inter-Bold.eot
new file mode 100644
index 0000000000..a4ce8ae836
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Bold.eot differ
diff --git a/src/assets/fonts/Inter/Inter-Bold.svg b/src/assets/fonts/Inter/Inter-Bold.svg
new file mode 100644
index 0000000000..3d194bc1ab
--- /dev/null
+++ b/src/assets/fonts/Inter/Inter-Bold.svg
@@ -0,0 +1,25445 @@
+
+
+
diff --git a/src/assets/fonts/Inter/Inter-Bold.ttf b/src/assets/fonts/Inter/Inter-Bold.ttf
new file mode 100644
index 0000000000..653c4c3866
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Bold.ttf differ
diff --git a/src/assets/fonts/Inter/Inter-Bold.woff b/src/assets/fonts/Inter/Inter-Bold.woff
new file mode 100644
index 0000000000..7772ebf100
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Bold.woff differ
diff --git a/src/assets/fonts/Inter/Inter-Bold.woff2 b/src/assets/fonts/Inter/Inter-Bold.woff2
new file mode 100644
index 0000000000..676bf04a6a
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Bold.woff2 differ
diff --git a/src/assets/fonts/Inter/Inter-Light.eot b/src/assets/fonts/Inter/Inter-Light.eot
new file mode 100644
index 0000000000..502d43fd62
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Light.eot differ
diff --git a/src/assets/fonts/Inter/Inter-Light.svg b/src/assets/fonts/Inter/Inter-Light.svg
new file mode 100644
index 0000000000..4223a784fd
--- /dev/null
+++ b/src/assets/fonts/Inter/Inter-Light.svg
@@ -0,0 +1,25012 @@
+
+
+
diff --git a/src/assets/fonts/Inter/Inter-Light.ttf b/src/assets/fonts/Inter/Inter-Light.ttf
new file mode 100644
index 0000000000..5ce6df61c5
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Light.ttf differ
diff --git a/src/assets/fonts/Inter/Inter-Light.woff b/src/assets/fonts/Inter/Inter-Light.woff
new file mode 100644
index 0000000000..42989e66f5
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Light.woff differ
diff --git a/src/assets/fonts/Inter/Inter-Light.woff2 b/src/assets/fonts/Inter/Inter-Light.woff2
new file mode 100644
index 0000000000..2d2579e4c0
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Light.woff2 differ
diff --git a/src/assets/fonts/Inter/Inter-Medium.eot b/src/assets/fonts/Inter/Inter-Medium.eot
new file mode 100644
index 0000000000..dfd006e529
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Medium.eot differ
diff --git a/src/assets/fonts/Inter/Inter-Medium.svg b/src/assets/fonts/Inter/Inter-Medium.svg
new file mode 100644
index 0000000000..bb76ddda33
--- /dev/null
+++ b/src/assets/fonts/Inter/Inter-Medium.svg
@@ -0,0 +1,25402 @@
+
+
+
diff --git a/src/assets/fonts/Inter/Inter-Medium.ttf b/src/assets/fonts/Inter/Inter-Medium.ttf
new file mode 100644
index 0000000000..99e4676bdf
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Medium.ttf differ
diff --git a/src/assets/fonts/Inter/Inter-Medium.woff b/src/assets/fonts/Inter/Inter-Medium.woff
new file mode 100644
index 0000000000..e13a2c2f98
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Medium.woff differ
diff --git a/src/assets/fonts/Inter/Inter-Medium.woff2 b/src/assets/fonts/Inter/Inter-Medium.woff2
new file mode 100644
index 0000000000..bbb0a43b33
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Medium.woff2 differ
diff --git a/src/assets/fonts/Inter/Inter-Regular.eot b/src/assets/fonts/Inter/Inter-Regular.eot
new file mode 100644
index 0000000000..c72df89ec5
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Regular.eot differ
diff --git a/src/assets/fonts/Inter/Inter-Regular.svg b/src/assets/fonts/Inter/Inter-Regular.svg
new file mode 100644
index 0000000000..73af12d05c
--- /dev/null
+++ b/src/assets/fonts/Inter/Inter-Regular.svg
@@ -0,0 +1,24343 @@
+
+
+
diff --git a/src/assets/fonts/Inter/Inter-Regular.ttf b/src/assets/fonts/Inter/Inter-Regular.ttf
new file mode 100644
index 0000000000..1a1d9c13c9
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Regular.ttf differ
diff --git a/src/assets/fonts/Inter/Inter-Regular.woff b/src/assets/fonts/Inter/Inter-Regular.woff
new file mode 100644
index 0000000000..e370846697
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Regular.woff differ
diff --git a/src/assets/fonts/Inter/Inter-Regular.woff2 b/src/assets/fonts/Inter/Inter-Regular.woff2
new file mode 100644
index 0000000000..a9c51b34c2
Binary files /dev/null and b/src/assets/fonts/Inter/Inter-Regular.woff2 differ
diff --git a/src/assets/fonts/Inter/demo.html b/src/assets/fonts/Inter/demo.html
new file mode 100644
index 0000000000..c147556906
--- /dev/null
+++ b/src/assets/fonts/Inter/demo.html
@@ -0,0 +1,279 @@
+
+
+
+
+
+
+
+
+ Transfonter demo
+
+
+
+
+
+
+
Inter Medium
+
.your-style {
+ font-family: 'Inter';
+ font-weight: 500;
+ font-style: normal;
+}
+
+<link rel="preload" href="Inter-Medium.woff2" as="font" type="font/woff2" crossorigin>
+
+
+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~
+
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
+
+
+
+
Inter Bold
+
.your-style {
+ font-family: 'Inter';
+ font-weight: bold;
+ font-style: normal;
+}
+
+<link rel="preload" href="Inter-Bold.woff2" as="font" type="font/woff2" crossorigin>
+
+
+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~
+
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
+
+
+
+
Inter Regular
+
.your-style {
+ font-family: 'Inter';
+ font-weight: normal;
+ font-style: normal;
+}
+
+<link rel="preload" href="Inter-Regular.woff2" as="font" type="font/woff2" crossorigin>
+
+
+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~
+
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
+
+
+
+
Inter Light
+
.your-style {
+ font-family: 'Inter';
+ font-weight: 300;
+ font-style: normal;
+}
+
+<link rel="preload" href="Inter-Light.woff2" as="font" type="font/woff2" crossorigin>
+
+
+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~
+
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
The quick brown fox jumps over the lazy dog.
+
+
+
+
+
+
diff --git a/src/assets/fonts/Inter/stylesheet.css b/src/assets/fonts/Inter/stylesheet.css
new file mode 100644
index 0000000000..00faf1111e
--- /dev/null
+++ b/src/assets/fonts/Inter/stylesheet.css
@@ -0,0 +1,51 @@
+@font-face {
+ font-family: 'Inter';
+ src: url('Inter-Medium.eot');
+ src: url('Inter-Medium.eot?#iefix') format('embedded-opentype'),
+ url('Inter-Medium.woff2') format('woff2'),
+ url('Inter-Medium.woff') format('woff'),
+ url('Inter-Medium.ttf') format('truetype'),
+ url('Inter-Medium.svg#Inter-Medium') format('svg');
+ font-weight: 500;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'Inter';
+ src: url('Inter-Bold.eot');
+ src: url('Inter-Bold.eot?#iefix') format('embedded-opentype'),
+ url('Inter-Bold.woff2') format('woff2'),
+ url('Inter-Bold.woff') format('woff'),
+ url('Inter-Bold.ttf') format('truetype'),
+ url('Inter-Bold.svg#Inter-Bold') format('svg');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'Inter';
+ src: url('Inter-Regular.eot');
+ src: url('Inter-Regular.eot?#iefix') format('embedded-opentype'),
+ url('Inter-Regular.woff2') format('woff2'),
+ url('Inter-Regular.woff') format('woff'),
+ url('Inter-Regular.ttf') format('truetype'),
+ url('Inter-Regular.svg#Inter-Regular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'Inter';
+ src: url('Inter-Light.eot');
+ src: url('Inter-Light.eot?#iefix') format('embedded-opentype'),
+ url('Inter-Light.woff2') format('woff2'),
+ url('Inter-Light.woff') format('woff'),
+ url('Inter-Light.ttf') format('truetype'),
+ url('Inter-Light.svg#Inter-Light') format('svg');
+ font-weight: 300;
+ font-style: normal;
+ font-display: swap;
+}
diff --git a/src/assets/fonts/Lato/hinted-Lato-Bold.eot b/src/assets/fonts/Lato/hinted-Lato-Bold.eot
deleted file mode 100644
index 90007a28ac..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Bold.eot and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Bold.svg b/src/assets/fonts/Lato/hinted-Lato-Bold.svg
deleted file mode 100644
index f260ae3c30..0000000000
--- a/src/assets/fonts/Lato/hinted-Lato-Bold.svg
+++ /dev/null
@@ -1,5845 +0,0 @@
-
-
-
diff --git a/src/assets/fonts/Lato/hinted-Lato-Bold.ttf b/src/assets/fonts/Lato/hinted-Lato-Bold.ttf
deleted file mode 100644
index 6434dd8643..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Bold.ttf and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Bold.woff b/src/assets/fonts/Lato/hinted-Lato-Bold.woff
deleted file mode 100644
index 04101e05fd..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Bold.woff and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Bold.woff2 b/src/assets/fonts/Lato/hinted-Lato-Bold.woff2
deleted file mode 100644
index 950213e27b..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Bold.woff2 and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Regular.eot b/src/assets/fonts/Lato/hinted-Lato-Regular.eot
deleted file mode 100644
index ca00539dfd..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Regular.eot and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Regular.svg b/src/assets/fonts/Lato/hinted-Lato-Regular.svg
deleted file mode 100644
index c9e682fd5b..0000000000
--- a/src/assets/fonts/Lato/hinted-Lato-Regular.svg
+++ /dev/null
@@ -1,5440 +0,0 @@
-
-
-
diff --git a/src/assets/fonts/Lato/hinted-Lato-Regular.ttf b/src/assets/fonts/Lato/hinted-Lato-Regular.ttf
deleted file mode 100644
index 8c62e7f782..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Regular.ttf and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Regular.woff b/src/assets/fonts/Lato/hinted-Lato-Regular.woff
deleted file mode 100644
index 99ca37a20a..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Regular.woff and /dev/null differ
diff --git a/src/assets/fonts/Lato/hinted-Lato-Regular.woff2 b/src/assets/fonts/Lato/hinted-Lato-Regular.woff2
deleted file mode 100644
index 4c0c57de96..0000000000
Binary files a/src/assets/fonts/Lato/hinted-Lato-Regular.woff2 and /dev/null differ
diff --git a/src/assets/fonts/Lato/stylesheet.css b/src/assets/fonts/Lato/stylesheet.css
deleted file mode 100644
index 1a35d98533..0000000000
--- a/src/assets/fonts/Lato/stylesheet.css
+++ /dev/null
@@ -1,26 +0,0 @@
-@font-face {
- font-family: 'Lato';
- src: url('hinted-Lato-Regular.eot');
- src: local('Lato Regular'), local('Lato-Regular'),
- url('hinted-Lato-Regular.eot?#iefix') format('embedded-opentype'),
- url('hinted-Lato-Regular.woff2') format('woff2'),
- url('hinted-Lato-Regular.woff') format('woff'),
- url('hinted-Lato-Regular.ttf') format('truetype'),
- url('hinted-Lato-Regular.svg#Lato-Regular') format('svg');
- font-weight: normal;
- font-style: normal;
-}
-
-@font-face {
- font-family: 'Lato';
- src: url('hinted-Lato-Bold.eot');
- src: local('Lato Bold'), local('Lato-Bold'),
- url('hinted-Lato-Bold.eot?#iefix') format('embedded-opentype'),
- url('hinted-Lato-Bold.woff2') format('woff2'),
- url('hinted-Lato-Bold.woff') format('woff'),
- url('hinted-Lato-Bold.ttf') format('truetype'),
- url('hinted-Lato-Bold.svg#Lato-Bold') format('svg');
- font-weight: bold;
- font-style: normal;
-}
-
diff --git a/src/assets/images/illustrations/app-building-dark.svg b/src/assets/images/illustrations/app-building-dark.svg
new file mode 100644
index 0000000000..ce67b44690
--- /dev/null
+++ b/src/assets/images/illustrations/app-building-dark.svg
@@ -0,0 +1,351 @@
+
+
diff --git a/src/assets/images/illustrations/app-building.svg b/src/assets/images/illustrations/app-building.svg
new file mode 100644
index 0000000000..9d0dba6b15
--- /dev/null
+++ b/src/assets/images/illustrations/app-building.svg
@@ -0,0 +1,340 @@
+
+
diff --git a/src/assets/images/illustrations/app-modal-alert-naming-dark.svg b/src/assets/images/illustrations/app-modal-alert-naming-dark.svg
new file mode 100644
index 0000000000..574cb391af
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-alert-naming-dark.svg
@@ -0,0 +1,28 @@
+
diff --git a/src/assets/images/illustrations/app-modal-alert-naming-light.svg b/src/assets/images/illustrations/app-modal-alert-naming-light.svg
new file mode 100644
index 0000000000..d9186b88ee
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-alert-naming-light.svg
@@ -0,0 +1,28 @@
+
diff --git a/src/assets/images/illustrations/app-modal-default-dark.svg b/src/assets/images/illustrations/app-modal-default-dark.svg
new file mode 100644
index 0000000000..0248ec6f66
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-default-dark.svg
@@ -0,0 +1,39 @@
+
diff --git a/src/assets/images/illustrations/app-modal-default-light.svg b/src/assets/images/illustrations/app-modal-default-light.svg
new file mode 100644
index 0000000000..fe70b44c71
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-default-light.svg
@@ -0,0 +1,39 @@
+
diff --git a/src/assets/images/illustrations/app-modal-error-dark.svg b/src/assets/images/illustrations/app-modal-error-dark.svg
new file mode 100644
index 0000000000..35362b1556
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-error-dark.svg
@@ -0,0 +1,29 @@
+
diff --git a/src/assets/images/illustrations/app-modal-error-light.svg b/src/assets/images/illustrations/app-modal-error-light.svg
new file mode 100644
index 0000000000..f70a01e610
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-error-light.svg
@@ -0,0 +1,29 @@
+
diff --git a/src/assets/images/illustrations/app-modal-saved-search-naming-dark.svg b/src/assets/images/illustrations/app-modal-saved-search-naming-dark.svg
new file mode 100644
index 0000000000..88a82b5699
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-saved-search-naming-dark.svg
@@ -0,0 +1,42 @@
+
diff --git a/src/assets/images/illustrations/app-modal-saved-search-naming-light.svg b/src/assets/images/illustrations/app-modal-saved-search-naming-light.svg
new file mode 100644
index 0000000000..bba7ae418d
--- /dev/null
+++ b/src/assets/images/illustrations/app-modal-saved-search-naming-light.svg
@@ -0,0 +1,42 @@
+
diff --git a/src/assets/images/illustrations/login-image-dark.svg b/src/assets/images/illustrations/login-image-dark.svg
new file mode 100644
index 0000000000..f0a4bf2915
--- /dev/null
+++ b/src/assets/images/illustrations/login-image-dark.svg
@@ -0,0 +1,31 @@
+
diff --git a/src/assets/images/illustrations/login-image-light.svg b/src/assets/images/illustrations/login-image-light.svg
new file mode 100644
index 0000000000..6ab1f9243d
--- /dev/null
+++ b/src/assets/images/illustrations/login-image-light.svg
@@ -0,0 +1,31 @@
+
diff --git a/src/assets/images/illustrations/theme-dark.png b/src/assets/images/illustrations/theme-dark.png
new file mode 100644
index 0000000000..e5712ee1c6
Binary files /dev/null and b/src/assets/images/illustrations/theme-dark.png differ
diff --git a/src/assets/images/illustrations/theme-light.png b/src/assets/images/illustrations/theme-light.png
new file mode 100644
index 0000000000..37443b3a14
Binary files /dev/null and b/src/assets/images/illustrations/theme-light.png differ
diff --git a/src/assets/images/logo-design-system.png b/src/assets/images/logo-design-system.png
new file mode 100644
index 0000000000..6470524a09
Binary files /dev/null and b/src/assets/images/logo-design-system.png differ
diff --git a/src/assets/images/logo-design-system.svg b/src/assets/images/logo-design-system.svg
new file mode 100644
index 0000000000..9d1c88ad71
--- /dev/null
+++ b/src/assets/images/logo-design-system.svg
@@ -0,0 +1,141 @@
+
+
diff --git a/src/components/Addon/AddonCard.vue b/src/components/Addon/AddonCard.vue
new file mode 100644
index 0000000000..87029b0c64
--- /dev/null
+++ b/src/components/Addon/AddonCard.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
diff --git a/src/components/Addon/AddonCardView/AddonCardView.vue b/src/components/Addon/AddonCardView/AddonCardView.vue
new file mode 100644
index 0000000000..38b11b56ee
--- /dev/null
+++ b/src/components/Addon/AddonCardView/AddonCardView.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Addon/AddonCardView/AddonCardViewActions.vue b/src/components/Addon/AddonCardView/AddonCardViewActions.vue
new file mode 100644
index 0000000000..c1c1b647ff
--- /dev/null
+++ b/src/components/Addon/AddonCardView/AddonCardViewActions.vue
@@ -0,0 +1,78 @@
+
+
+
+
+ {{ installLabel }}
+
+ {{ updateLabel }}
+ {{
+ versionLabel
+ }}
+ {{ uninstallLabel }}
+
+
+
+
+
diff --git a/src/components/Addon/AddonCardView/AddonCardViewDetails.vue b/src/components/Addon/AddonCardView/AddonCardViewDetails.vue
new file mode 100644
index 0000000000..17fb397c96
--- /dev/null
+++ b/src/components/Addon/AddonCardView/AddonCardViewDetails.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+ {{ homepageLabel }} {{ url }}
+
+
+
diff --git a/src/components/Addon/AddonUrlInput.vue b/src/components/Addon/AddonUrlInput.vue
new file mode 100644
index 0000000000..16a66c8aed
--- /dev/null
+++ b/src/components/Addon/AddonUrlInput.vue
@@ -0,0 +1,53 @@
+
+
+
+
diff --git a/src/components/Api.vue b/src/components/Api.vue
index 75befd34bf..3c32d6094b 100644
--- a/src/components/Api.vue
+++ b/src/components/Api.vue
@@ -6,7 +6,7 @@
-
+
{{ $t('api.newApiKey') }}
@@ -56,13 +56,13 @@
:model-value="showModal"
lazy
ok-only
- footer-class="bg-light rounded-bottom border-top py-2 px-3"
+ footer-class="bg-tertiary rounded-bottom border-top py-2 px-3"
@hidden="apiKey = null"
>
{{ $t('api.key.warning') }}
-
+
diff --git a/src/components/AppModal/AppModal.vue b/src/components/AppModal/AppModal.vue
new file mode 100644
index 0000000000..db3f148b9d
--- /dev/null
+++ b/src/components/AppModal/AppModal.vue
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/AppModal/AppModalFooter.vue b/src/components/AppModal/AppModalFooter.vue
new file mode 100644
index 0000000000..4db406fe37
--- /dev/null
+++ b/src/components/AppModal/AppModalFooter.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
diff --git a/src/components/AppModal/AppModalHeader.vue b/src/components/AppModal/AppModalHeader.vue
new file mode 100644
index 0000000000..d1ce26e3f1
--- /dev/null
+++ b/src/components/AppModal/AppModalHeader.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppModal/AppModalPrompt.vue b/src/components/AppModal/AppModalPrompt.vue
new file mode 100644
index 0000000000..d704e690f3
--- /dev/null
+++ b/src/components/AppModal/AppModalPrompt.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ description }}
+
+
+
+
+
diff --git a/src/components/AppNav.vue b/src/components/AppNav.vue
deleted file mode 100644
index 97215fe28e..0000000000
--- a/src/components/AppNav.vue
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/components/AppSidebar.vue b/src/components/AppSidebar.vue
deleted file mode 100644
index 6ae003e8c3..0000000000
--- a/src/components/AppSidebar.vue
+++ /dev/null
@@ -1,620 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/components/AppSidebar/AppSidebar.vue b/src/components/AppSidebar/AppSidebar.vue
new file mode 100644
index 0000000000..6011b98fc8
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebar.vue
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarClose.vue b/src/components/AppSidebar/AppSidebarClose.vue
new file mode 100644
index 0000000000..d1419e29b1
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarClose.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarFooter.vue b/src/components/AppSidebar/AppSidebarFooter.vue
new file mode 100644
index 0000000000..92ee0effda
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarFooter.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarSection.vue b/src/components/AppSidebar/AppSidebarSection.vue
new file mode 100644
index 0000000000..555571a12f
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarSection.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarSectionEntry.vue b/src/components/AppSidebar/AppSidebarSectionEntry.vue
new file mode 100644
index 0000000000..d3e283ea82
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarSectionEntry.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarSectionTitle.vue b/src/components/AppSidebar/AppSidebarSectionTitle.vue
new file mode 100644
index 0000000000..60a1b508f8
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarSectionTitle.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarSectionToggler.vue b/src/components/AppSidebar/AppSidebarSectionToggler.vue
new file mode 100644
index 0000000000..ed46789e05
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarSectionToggler.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
diff --git a/src/components/AppSidebar/AppSidebarToggler.vue b/src/components/AppSidebar/AppSidebarToggler.vue
new file mode 100644
index 0000000000..19e10d9fa8
--- /dev/null
+++ b/src/components/AppSidebar/AppSidebarToggler.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/src/components/AppliedSearchFilters.vue b/src/components/AppliedSearchFilters.vue
index 476172fcfd..b291ec0387 100644
--- a/src/components/AppliedSearchFilters.vue
+++ b/src/components/AppliedSearchFilters.vue
@@ -34,7 +34,7 @@ export default {
const date = new Date(parseInt(label))
label = date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2)
}
- filters.push({ name: filter.name, label, value, negation: filter.reverse })
+ filters.push({ name: filter.name, label, value, negation: filter.excluded })
})
})
return filters
diff --git a/src/components/Badge/BadgeFilter.vue b/src/components/Badge/BadgeFilter.vue
new file mode 100644
index 0000000000..5e0824ff22
--- /dev/null
+++ b/src/components/Badge/BadgeFilter.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Badge/BadgeFilterHeader.vue b/src/components/Badge/BadgeFilterHeader.vue
new file mode 100644
index 0000000000..8c9428eafb
--- /dev/null
+++ b/src/components/Badge/BadgeFilterHeader.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
diff --git a/src/components/Badge/BadgeFilterValue.vue b/src/components/Badge/BadgeFilterValue.vue
new file mode 100644
index 0000000000..0fd70a41d0
--- /dev/null
+++ b/src/components/Badge/BadgeFilterValue.vue
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
diff --git a/src/components/BatchSearch/BatchSearchCard.vue b/src/components/BatchSearch/BatchSearchCard.vue
new file mode 100644
index 0000000000..55ef138ead
--- /dev/null
+++ b/src/components/BatchSearch/BatchSearchCard.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/BatchSearch/BatchSearchCardActions.vue b/src/components/BatchSearch/BatchSearchCardActions.vue
new file mode 100644
index 0000000000..54e8dfe9bd
--- /dev/null
+++ b/src/components/BatchSearch/BatchSearchCardActions.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
diff --git a/src/components/BatchSearch/BatchSearchCardDetails.vue b/src/components/BatchSearch/BatchSearchCardDetails.vue
new file mode 100644
index 0000000000..cc4fb4ed23
--- /dev/null
+++ b/src/components/BatchSearch/BatchSearchCardDetails.vue
@@ -0,0 +1,280 @@
+
+
+
+
+
+ -
+
+ {{ statusItem.value }}
+
+
+ -
+
+
+ -
+ {{ seeAllDocumentsLabel }}
+
+ -
+ {{ downloadDocumentsLabel }}
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
diff --git a/src/components/BatchSearch/BatchSearchCardDetailsEntry.vue b/src/components/BatchSearch/BatchSearchCardDetailsEntry.vue
new file mode 100644
index 0000000000..d6490010de
--- /dev/null
+++ b/src/components/BatchSearch/BatchSearchCardDetailsEntry.vue
@@ -0,0 +1,34 @@
+
+
+
+ {{ value }}
+
+
diff --git a/src/components/BatchSearch/BatchSearchErrorModal.vue b/src/components/BatchSearch/BatchSearchErrorModal.vue
new file mode 100644
index 0000000000..2e417f6c7d
--- /dev/null
+++ b/src/components/BatchSearch/BatchSearchErrorModal.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+ {{ query }}
+
+
{{ errorTitle }}
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/BatchSearchActions.vue b/src/components/BatchSearchActions.vue
index cebd403e39..fccf31d851 100644
--- a/src/components/BatchSearchActions.vue
+++ b/src/components/BatchSearchActions.vue
@@ -3,7 +3,7 @@
@@ -41,7 +41,7 @@
split
end
class="batch-search-actions__item batch-search-actions__item--download-queries ms-2"
- variant="light"
+ variant="tertiary"
:split-href="downloadQueriesUrl"
:title="$t('batchSearchResults.downloadQueriesTooltip')"
>
@@ -59,7 +59,7 @@
v-if="isEnded"
v-b-tooltip.hover
class="batch-search-actions__item batch-search-actions__item--download-results ms-2"
- variant="primary"
+ variant="action"
:title="$t('batchSearchResults.downloadQueriesTooltip')"
:href="downloadResultsUrl"
>
diff --git a/src/components/BatchSearchCopyForm.vue b/src/components/BatchSearchCopyForm.vue
index a3fc0c41ef..d805b5aa35 100644
--- a/src/components/BatchSearchCopyForm.vue
+++ b/src/components/BatchSearchCopyForm.vue
@@ -21,7 +21,7 @@