web/satellite: migrate webpack to vite
Migrated webpack to vite. Replaced jest with vitest (because I couldn't resolve 'import.meta' issue) Replaced legacy vue-svg-loader with vite-svg-loader Replaced bip39 dep with bip39-english (it includes only english wordlist) Replaced aws-sdk v2 with aws-sdk V3 (because v2 was throwing some weird error in console. Ref: https://stackoverflow.com/questions/75107933/aws-sdk-contributes-to-build-error-uncaught-typeerror-e-is-not-a-constructor) Renamed VUE_APP_ENDPOINT_URL env variable to VITE_ENDPOINT_URL Removed a ton of dependencies (like babel and jest-related stuff). Tested in Chrome, Safari, Brave, Firefox and Opera browsers. Additionally fixed logout errors from buckets and object browser routes. TODO: try to remove util and stream-browserify dependencies and see if it works Change-Id: I4562649a59eb0ba80c1a672d55c59fceb8c80b23
This commit is contained in:
parent
4791a6422d
commit
e6959004c9
@ -1 +1 @@
|
||||
VUE_APP_ENDPOINT_URL=/api/v0/graphql
|
||||
VITE_ENDPOINT_URL=/api/v0/graphql
|
||||
|
@ -18,11 +18,8 @@ module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
vueFeatures: {
|
||||
filter: true,
|
||||
},
|
||||
},
|
||||
plugins: ['storj', 'eslint-plugin-import'],
|
||||
plugins: ['eslint-plugin-import'],
|
||||
rules: {
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
|
||||
@ -89,8 +86,6 @@ module.exports = {
|
||||
|
||||
'vue/no-undef-components': ['warn', { ignorePatterns: ['router-link', 'router-view'] }],
|
||||
|
||||
'storj/vue/require-annotation': 'warn',
|
||||
|
||||
'vue/no-v-html': ['error'],
|
||||
},
|
||||
settings: {
|
||||
|
@ -8,5 +8,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,20 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
process.env.TZ = 'UTC';
|
||||
|
||||
module.exports = {
|
||||
preset: '@vue/cli-plugin-unit-jest/presets/typescript',
|
||||
setupFiles: ['./jest.setup.ts'],
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.svg$': '<rootDir>/tests/unit/mock/svgTransform.js',
|
||||
},
|
||||
modulePathIgnorePatterns: ['<rootDir>/tests/unit/ignore'],
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'ts',
|
||||
'json',
|
||||
'vue',
|
||||
],
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { GlobalWithFetchMock } from 'jest-fetch-mock';
|
||||
|
||||
const customGlobal = (global as unknown) as
|
||||
(GlobalWithFetchMock & { console: Record<any,unknown> });
|
||||
|
||||
customGlobal.fetch = require('jest-fetch-mock');
|
||||
customGlobal.fetchMock = customGlobal.fetch;
|
||||
|
||||
// Disallow warnings and errors from console.
|
||||
customGlobal.console.warn = (message) => { throw new Error(message); };
|
||||
customGlobal.console.error = (message) => { throw new Error(message); };
|
File diff suppressed because it is too large
Load Diff
@ -3,22 +3,25 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"lint": "vue-cli-service lint --max-warnings 0 --fix && stylelint . --max-warnings 0 --fix",
|
||||
"lint-ci": "vue-cli-service lint --max-warnings 0 --no-fix && stylelint . --max-warnings 0 --no-fix",
|
||||
"build": "vue-cli-service build",
|
||||
"preview": "vite preview",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build-watch": "vite build --watch",
|
||||
"lint": "eslint --ext .js,.ts,.vue src --fix && stylelint . --max-warnings 0 --fix",
|
||||
"lint-ci": "eslint --ext .js,.ts,.vue src --no-fix && stylelint . --max-warnings 0 --no-fix",
|
||||
"wasm": "chmod +x ./scripts/build-wasm.sh && ./scripts/build-wasm.sh",
|
||||
"wasm-dev": "chmod +x ./scripts/build-wasm-dev.sh && ./scripts/build-wasm-dev.sh",
|
||||
"dev": "vue-cli-service build --watch --no-module",
|
||||
"test": "vue-cli-service test:unit"
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "3.7.14",
|
||||
"@aws-sdk/client-s3": "3.338.0",
|
||||
"@aws-sdk/lib-storage": "3.338.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.338.0",
|
||||
"@aws-sdk/signature-v4": "3.338.0",
|
||||
"@hcaptcha/vue3-hcaptcha": "1.2.1",
|
||||
"aws-sdk": "2.1377.0",
|
||||
"bip39": "3.1.0",
|
||||
"bip39-english": "2.5.0",
|
||||
"chart.js": "4.2.1",
|
||||
"core-js": "3.30.2",
|
||||
"graphql": "15.3.0",
|
||||
"pinia": "2.0.23",
|
||||
"pretty-bytes": "5.6.0",
|
||||
@ -32,48 +35,34 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/filesystem": "0.0.32",
|
||||
"@types/jest": "27.5.2",
|
||||
"@types/node": "16.18.14",
|
||||
"@types/qrcode": "1.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.5",
|
||||
"@typescript-eslint/parser": "5.59.5",
|
||||
"@vue/cli-plugin-babel": "5.0.8",
|
||||
"@vue/cli-plugin-eslint": "5.0.8",
|
||||
"@vue/cli-plugin-typescript": "5.0.8",
|
||||
"@vue/cli-plugin-unit-jest": "5.0.8",
|
||||
"@vue/cli-service": "5.0.8",
|
||||
"@vitejs/plugin-vue": "4.2.3",
|
||||
"@vue/eslint-config-typescript": "11.0.3",
|
||||
"@vue/test-utils": "2.3.2",
|
||||
"@vue/vue3-jest": "27.0.0",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-jest": "27.5.1",
|
||||
"compression-webpack-plugin": "9.2.0",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-import-resolver-custom-alias": "1.3.0",
|
||||
"eslint-import-resolver-typescript": "3.5.5",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-storj": "0.0.2",
|
||||
"eslint-plugin-vue": "9.12.0",
|
||||
"jest": "27.5.1",
|
||||
"jest-fetch-mock": "3.0.3",
|
||||
"jsdom": "22.0.0",
|
||||
"postcss-html": "1.5.0",
|
||||
"rollup-plugin-visualizer": "5.9.0",
|
||||
"sass": "1.62.1",
|
||||
"sass-loader": "13.2.2",
|
||||
"stylelint": "15.6.1",
|
||||
"stylelint-config-standard": "33.0.0",
|
||||
"stylelint-config-standard-scss": "9.0.0",
|
||||
"stylelint-config-standard-vue": "1.0.0",
|
||||
"stylelint-scss": "5.0.0",
|
||||
"ts-jest": "27.1.5",
|
||||
"typescript": "4.9.5",
|
||||
"vue-eslint-parser": "9.2.1",
|
||||
"vue-svg-loader": "0.17.0-beta.2",
|
||||
"webpack-bundle-analyzer": "4.8.0"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
"vite": "4.3.9",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
"vite-plugin-require": "1.1.10",
|
||||
"vite-svg-loader": "4.0.0",
|
||||
"vitest": "0.31.1",
|
||||
"vitest-fetch-mock": "0.2.2",
|
||||
"vue-eslint-parser": "9.3.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
|
@ -107,7 +107,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { generateMnemonic } from 'bip39';
|
||||
import { generateMnemonic } from 'bip39-english';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
|
@ -37,7 +37,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, Component } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import VTableCheckbox from '@/components/common/VTableCheckbox.vue';
|
||||
import BucketGuide from '@/components/objects/BucketGuide.vue';
|
||||
@ -84,7 +84,7 @@ const props = withDefaults(defineProps<{
|
||||
|
||||
const emit = defineEmits(['selectClicked']);
|
||||
|
||||
const icons = new Map<string, Component>([
|
||||
const icons = new Map<string, string>([
|
||||
['locked', TableLockedIcon],
|
||||
['bucket', ColorBucketIcon],
|
||||
['folder', ColorFolderIcon],
|
||||
|
@ -50,7 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, Component } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import WhitePlusIcon from '@/../static/images/common/plusWhite.svg';
|
||||
import AddCircleIcon from '@/../static/images/common/addCircle.svg';
|
||||
@ -106,7 +106,7 @@ const props = withDefaults(defineProps<{
|
||||
onPress: () => {},
|
||||
});
|
||||
|
||||
const icons = new Map<string, Component>([
|
||||
const icons = new Map<string, string>([
|
||||
['copy', CopyIcon],
|
||||
['check', CheckIcon],
|
||||
['download', DownloadIcon],
|
||||
@ -120,7 +120,7 @@ const icons = new Map<string, Component>([
|
||||
['add', WhitePlusIcon],
|
||||
]);
|
||||
|
||||
const iconComponent = computed((): Component | undefined => icons.get(props.icon.toLowerCase()));
|
||||
const iconComponent = computed((): string | undefined => icons.get(props.icon.toLowerCase()));
|
||||
|
||||
const containerClassName = computed((): string => {
|
||||
if (props.isDisabled) return 'disabled';
|
||||
|
@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, Component } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { ShareButtonConfig, ShareOptions } from '@/types/browser';
|
||||
|
||||
@ -29,7 +29,7 @@ import EmailIcon from '@/../static/images/objects/email.svg';
|
||||
|
||||
const props = defineProps<{ link: string; }>();
|
||||
|
||||
const images: Record<string, Component> = {
|
||||
const images: Record<string, string> = {
|
||||
[ShareOptions.Reddit]: RedditIcon,
|
||||
[ShareOptions.Facebook]: FacebookIcon,
|
||||
[ShareOptions.Twitter]: TwitterIcon,
|
||||
|
@ -8,7 +8,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Component, computed } from 'vue';
|
||||
import { computed, Component } from 'vue';
|
||||
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
<img
|
||||
v-if="previewAndMapFailed"
|
||||
class="failed-preview"
|
||||
src="/static/static/images/common/errorNotice.svg"
|
||||
:src="ErrorNoticeIcon"
|
||||
alt="failed preview"
|
||||
>
|
||||
<template v-else>
|
||||
@ -126,6 +126,7 @@ import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
import ErrorNoticeIcon from '@/../static/images/common/errorNotice.svg?url';
|
||||
import PlaceholderImage from '@/../static/images/browser/placeholder.svg';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { generateMnemonic } from 'bip39';
|
||||
import { generateMnemonic } from 'bip39-english';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
|
@ -12,10 +12,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Component } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
icon?: Component;
|
||||
icon?: string;
|
||||
title: string;
|
||||
}>();
|
||||
</script>
|
||||
|
@ -13,14 +13,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Component } from 'vue';
|
||||
|
||||
import CloseIcon from '@/../static/images/notifications/closeSmall.svg';
|
||||
|
||||
const props = defineProps<{
|
||||
wordingBold: string;
|
||||
wording: string;
|
||||
notificationIcon: Component;
|
||||
notificationIcon: string;
|
||||
warningNotification: boolean;
|
||||
onCloseClick: () => void;
|
||||
}>();
|
||||
|
@ -70,6 +70,8 @@ const edgeCredentials = computed((): EdgeCredentials => {
|
||||
* Bucket from store found by router prop.
|
||||
*/
|
||||
const bucket = computed((): Bucket => {
|
||||
if (!projectsStore.state.selectedProject.id) return new Bucket();
|
||||
|
||||
const data = bucketsStore.state.page.buckets.find(
|
||||
(bucket: Bucket) => bucket.name === route.query.bucketName,
|
||||
);
|
||||
|
@ -171,7 +171,7 @@ async function fetchBuckets(page = 1, limit: number): Promise<void> {
|
||||
try {
|
||||
await bucketsStore.getBuckets(page, projectsStore.state.selectedProject.id, limit);
|
||||
} catch (error) {
|
||||
await notify.error(`Unable to fetch buckets. ${error.message}`, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
notify.error(`Unable to fetch buckets. ${error.message}`, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,14 +180,14 @@ async function fetchBuckets(page = 1, limit: number): Promise<void> {
|
||||
*/
|
||||
async function searchBuckets(searchQuery: string): Promise<void> {
|
||||
bucketsStore.setBucketsSearch(searchQuery);
|
||||
await analytics.eventTriggered(AnalyticsEvent.SEARCH_BUCKETS);
|
||||
analytics.eventTriggered(AnalyticsEvent.SEARCH_BUCKETS);
|
||||
|
||||
searchLoading.value = true;
|
||||
|
||||
try {
|
||||
await bucketsStore.getBuckets(1, projectsStore.state.selectedProject.id);
|
||||
} catch (error) {
|
||||
await notify.error(`Unable to fetch buckets: ${error.message}`, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
notify.error(`Unable to fetch buckets: ${error.message}`, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
}
|
||||
|
||||
searchLoading.value = false;
|
||||
@ -219,7 +219,7 @@ async function openBucket(bucketName: string): Promise<void> {
|
||||
await bucketsStore.setS3Client(projectsStore.state.selectedProject.id);
|
||||
overallLoading.value = false;
|
||||
} catch (error) {
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
notify.error(error.message, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
overallLoading.value = false;
|
||||
return;
|
||||
}
|
||||
|
@ -138,6 +138,8 @@ onMounted(async (): Promise<void> => {
|
||||
});
|
||||
|
||||
watch(selectedProjectID, async () => {
|
||||
if (!selectedProjectID.value) return;
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
bucketsStore.clear();
|
||||
|
@ -238,17 +238,18 @@ onBeforeMount(() => {
|
||||
});
|
||||
|
||||
watch(passphrase, async () => {
|
||||
const projectID = projectsStore.state.selectedProject.id;
|
||||
if (!projectID) return;
|
||||
|
||||
if (!passphrase.value) {
|
||||
await router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path).catch(() => {return;});
|
||||
return;
|
||||
}
|
||||
|
||||
const projectID = projectsStore.state.selectedProject.id;
|
||||
|
||||
try {
|
||||
await bucketsStore.setS3Client(projectID);
|
||||
} catch (error) {
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -266,7 +267,7 @@ watch(passphrase, async () => {
|
||||
obStore.getObjectCount(),
|
||||
]);
|
||||
} catch (error) {
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -17,12 +17,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Component } from 'vue';
|
||||
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
icon: Component,
|
||||
icon: string,
|
||||
isDataFetching: boolean,
|
||||
title: string,
|
||||
subtitle: string,
|
||||
|
@ -36,12 +36,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, Component } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
icon: Component
|
||||
icon: string
|
||||
title: string
|
||||
color: string
|
||||
usedValue: number
|
||||
|
@ -7,7 +7,6 @@
|
||||
<h1 class="project-dashboard__heading__title" aria-roledescription="title">{{ selectedProject.name }}</h1>
|
||||
<project-ownership-tag :is-owner="selectedProject.ownerId === user.id" />
|
||||
</div>
|
||||
|
||||
<p class="project-dashboard__message">
|
||||
Expect a delay of a few hours between network activity and the latest dashboard stats.
|
||||
</p>
|
||||
|
@ -42,7 +42,10 @@ export const useAccessGrantsStore = defineStore('accessGrants', () => {
|
||||
const configStore = useConfigStore();
|
||||
|
||||
async function startWorker(): Promise<void> {
|
||||
const worker = new Worker(new URL('@/utils/accessGrant.worker.js', import.meta.url), { type: 'module' });
|
||||
// TODO(vitalii): create an issue here https://github.com/vitejs/vite
|
||||
// about worker chunk being auto removed after rebuild in watch mode if using new URL constructor.
|
||||
// const worker = new Worker(new URL('@/utils/accessGrant.worker.js', import.meta.url));
|
||||
const worker = new Worker('/static/src/utils/accessGrant.worker.js');
|
||||
worker.postMessage({ 'type': 'Setup' });
|
||||
|
||||
const event: MessageEvent = await new Promise(resolve => worker.onmessage = resolve);
|
||||
|
@ -169,6 +169,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
state.selectedPricingPlan = null;
|
||||
state.hasShownPricingPlan = false;
|
||||
state.activeDropdown = '';
|
||||
state.isUploadingModal = false;
|
||||
state.error.visible = false;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,14 @@
|
||||
|
||||
import { reactive } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import S3 from 'aws-sdk/clients/s3';
|
||||
import {
|
||||
S3Client,
|
||||
S3ClientConfig,
|
||||
CreateBucketCommand,
|
||||
DeleteBucketCommand,
|
||||
ListObjectsV2Command,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import { SignatureV4 } from '@aws-sdk/signature-v4';
|
||||
|
||||
import { Bucket, BucketCursor, BucketPage, BucketsApi } from '@/types/buckets';
|
||||
import { BucketsApiGql } from '@/api/buckets';
|
||||
@ -23,20 +30,17 @@ export class BucketsState {
|
||||
public edgeCredentials: EdgeCredentials = new EdgeCredentials();
|
||||
public edgeCredentialsForDelete: EdgeCredentials = new EdgeCredentials();
|
||||
public edgeCredentialsForCreate: EdgeCredentials = new EdgeCredentials();
|
||||
public s3Client: S3 = new S3({
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
public s3Client: S3Client = new S3Client({
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
});
|
||||
public s3ClientForDelete: S3 = new S3({
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
public s3ClientForDelete: S3Client = new S3Client({
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
});
|
||||
public s3ClientForCreate: S3 = new S3({
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
public s3ClientForCreate: S3Client = new S3Client({
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
});
|
||||
public apiKey = '';
|
||||
public passphrase = '';
|
||||
@ -81,31 +85,35 @@ export const useBucketsStore = defineStore('buckets', () => {
|
||||
function setEdgeCredentialsForDelete(credentials: EdgeCredentials): void {
|
||||
state.edgeCredentialsForDelete = credentials;
|
||||
|
||||
const s3Config = {
|
||||
accessKeyId: state.edgeCredentialsForDelete.accessKeyId,
|
||||
secretAccessKey: state.edgeCredentialsForDelete.secretKey,
|
||||
const s3Config: S3ClientConfig = {
|
||||
credentials: {
|
||||
accessKeyId: state.edgeCredentialsForDelete.accessKeyId,
|
||||
secretAccessKey: state.edgeCredentialsForDelete.secretKey,
|
||||
},
|
||||
endpoint: state.edgeCredentialsForDelete.endpoint,
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
region: 'us-east-1',
|
||||
};
|
||||
|
||||
state.s3ClientForDelete = new S3(s3Config);
|
||||
state.s3ClientForDelete = new S3Client(s3Config);
|
||||
}
|
||||
|
||||
function setEdgeCredentialsForCreate(credentials: EdgeCredentials): void {
|
||||
state.edgeCredentialsForCreate = credentials;
|
||||
|
||||
const s3Config = {
|
||||
accessKeyId: state.edgeCredentialsForCreate.accessKeyId,
|
||||
secretAccessKey: state.edgeCredentialsForCreate.secretKey,
|
||||
const s3Config: S3ClientConfig = {
|
||||
credentials: {
|
||||
accessKeyId: state.edgeCredentialsForCreate.accessKeyId,
|
||||
secretAccessKey: state.edgeCredentialsForCreate.secretKey,
|
||||
},
|
||||
endpoint: state.edgeCredentialsForCreate.endpoint,
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
region: 'us-east-1',
|
||||
};
|
||||
|
||||
state.s3ClientForCreate = new S3(s3Config);
|
||||
state.s3ClientForCreate = new S3Client(s3Config);
|
||||
}
|
||||
|
||||
async function setS3Client(projectID: string): Promise<void> {
|
||||
@ -171,16 +179,18 @@ export const useBucketsStore = defineStore('buckets', () => {
|
||||
const accessGrant = accessGrantEvent.data.value;
|
||||
state.edgeCredentials = await agStore.getEdgeCredentials(accessGrant);
|
||||
|
||||
const s3Config = {
|
||||
accessKeyId: state.edgeCredentials.accessKeyId,
|
||||
secretAccessKey: state.edgeCredentials.secretKey,
|
||||
const s3Config: S3ClientConfig = {
|
||||
credentials: {
|
||||
accessKeyId: state.edgeCredentials.accessKeyId,
|
||||
secretAccessKey: state.edgeCredentials.secretKey,
|
||||
},
|
||||
endpoint: state.edgeCredentials.endpoint,
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
region: 'us-east-1',
|
||||
};
|
||||
|
||||
state.s3Client = new S3(s3Config);
|
||||
state.s3Client = new S3Client(s3Config);
|
||||
}
|
||||
|
||||
function setPassphrase(passphrase: string): void {
|
||||
@ -192,27 +202,27 @@ export const useBucketsStore = defineStore('buckets', () => {
|
||||
}
|
||||
|
||||
async function createBucket(name: string): Promise<void> {
|
||||
await state.s3Client.createBucket({
|
||||
await state.s3Client.send(new CreateBucketCommand({
|
||||
Bucket: name,
|
||||
}).promise();
|
||||
}));
|
||||
}
|
||||
|
||||
async function createBucketWithNoPassphrase(name: string): Promise<void> {
|
||||
await state.s3ClientForCreate.createBucket({
|
||||
await state.s3ClientForCreate.send(new CreateBucketCommand({
|
||||
Bucket: name,
|
||||
}).promise();
|
||||
}));
|
||||
}
|
||||
|
||||
async function deleteBucket(name: string): Promise<void> {
|
||||
await state.s3ClientForDelete.deleteBucket({
|
||||
await state.s3ClientForDelete.send(new DeleteBucketCommand({
|
||||
Bucket: name,
|
||||
}).promise();
|
||||
}));
|
||||
}
|
||||
|
||||
async function getObjectsCount(name: string): Promise<number> {
|
||||
const response = await state.s3Client.listObjectsV2({
|
||||
const response = await state.s3Client.send(new ListObjectsV2Command({
|
||||
Bucket: name,
|
||||
}).promise();
|
||||
}));
|
||||
|
||||
return response.KeyCount === undefined ? 0 : response.KeyCount;
|
||||
}
|
||||
@ -224,20 +234,17 @@ export const useBucketsStore = defineStore('buckets', () => {
|
||||
state.edgeCredentials = new EdgeCredentials();
|
||||
state.edgeCredentialsForDelete = new EdgeCredentials();
|
||||
state.edgeCredentialsForCreate = new EdgeCredentials();
|
||||
state.s3Client = new S3({
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
state.s3Client = new S3Client({
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
});
|
||||
state.s3ClientForDelete = new S3({
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
state.s3ClientForDelete = new S3Client({
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
});
|
||||
state.s3ClientForCreate = new S3({
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
httpOptions: { timeout: 0 },
|
||||
state.s3ClientForCreate = new S3Client({
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
});
|
||||
state.fileComponentBucketName = '';
|
||||
state.leaveRoute = '';
|
||||
|
@ -3,7 +3,20 @@
|
||||
|
||||
import { computed, reactive } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import S3, { CommonPrefix } from 'aws-sdk/clients/s3';
|
||||
import {
|
||||
S3Client,
|
||||
CommonPrefix,
|
||||
S3ClientConfig,
|
||||
ListObjectsCommand,
|
||||
ListObjectsV2Command,
|
||||
DeleteObjectCommand,
|
||||
PutObjectCommand,
|
||||
_Object,
|
||||
GetObjectCommand,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import { Upload } from '@aws-sdk/lib-storage';
|
||||
import { SignatureV4 } from '@aws-sdk/signature-v4';
|
||||
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { MODALS } from '@/utils/constants/appStatePopUps';
|
||||
@ -46,7 +59,7 @@ export type UploadingBrowserObject = BrowserObject & {
|
||||
}
|
||||
|
||||
export class FilesState {
|
||||
s3: S3 | null = null;
|
||||
s3: S3Client | null = null;
|
||||
accessKey: null | string = null;
|
||||
path = '';
|
||||
bucket = '';
|
||||
@ -70,7 +83,7 @@ export class FilesState {
|
||||
}
|
||||
|
||||
type InitializedFilesState = FilesState & {
|
||||
s3: S3;
|
||||
s3: S3Client;
|
||||
};
|
||||
|
||||
function assertIsInitialized(
|
||||
@ -157,17 +170,18 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
fetchSharedLink: (arg0: string) => Promisable<string>;
|
||||
fetchPreviewAndMapUrl: (arg0: string) => Promisable<string>;
|
||||
}): void {
|
||||
const s3Config = {
|
||||
accessKeyId: accessKey,
|
||||
secretAccessKey: secretKey,
|
||||
const s3Config: S3ClientConfig = {
|
||||
credentials: {
|
||||
accessKeyId: accessKey,
|
||||
secretAccessKey: secretKey,
|
||||
},
|
||||
endpoint,
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
connectTimeout: 0,
|
||||
httpOptions: { timeout: 0 },
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
region: 'us-east-1',
|
||||
};
|
||||
|
||||
state.s3 = new S3(s3Config);
|
||||
state.s3 = new S3Client(s3Config);
|
||||
state.accessKey = accessKey;
|
||||
state.bucket = bucket;
|
||||
state.browserRoot = browserRoot;
|
||||
@ -187,18 +201,19 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
secretKey: string;
|
||||
endpoint: string;
|
||||
}): void {
|
||||
const s3Config = {
|
||||
accessKeyId: accessKey,
|
||||
secretAccessKey: secretKey,
|
||||
const s3Config: S3ClientConfig = {
|
||||
credentials: {
|
||||
accessKeyId: accessKey,
|
||||
secretAccessKey: secretKey,
|
||||
},
|
||||
endpoint,
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4',
|
||||
connectTimeout: 0,
|
||||
httpOptions: { timeout: 0 },
|
||||
forcePathStyle: true,
|
||||
signerConstructor: SignatureV4,
|
||||
region: 'us-east-1',
|
||||
};
|
||||
|
||||
state.files = [];
|
||||
state.s3 = new S3(s3Config);
|
||||
state.s3 = new S3Client(s3Config);
|
||||
state.accessKey = accessKey;
|
||||
}
|
||||
|
||||
@ -214,24 +229,20 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
|
||||
assertIsInitialized(state);
|
||||
|
||||
const response = await state.s3
|
||||
.listObjects({
|
||||
Bucket: state.bucket,
|
||||
Delimiter: '/',
|
||||
Prefix: path,
|
||||
})
|
||||
.promise();
|
||||
const response = await state.s3.send(new ListObjectsCommand({
|
||||
Bucket: state.bucket,
|
||||
Delimiter: '/',
|
||||
Prefix: path,
|
||||
}));
|
||||
|
||||
const { Contents, CommonPrefixes } = response;
|
||||
let { Contents, CommonPrefixes } = response;
|
||||
|
||||
if (Contents === undefined) {
|
||||
throw new Error('Bad S3 listObjects() response: "Contents" undefined');
|
||||
Contents = [];
|
||||
}
|
||||
|
||||
if (CommonPrefixes === undefined) {
|
||||
throw new Error(
|
||||
'Bad S3 listObjects() response: "CommonPrefixes" undefined',
|
||||
);
|
||||
CommonPrefixes = [];
|
||||
}
|
||||
|
||||
Contents.sort((a, b) => {
|
||||
@ -302,11 +313,9 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
async function getObjectCount(): Promise<void> {
|
||||
assertIsInitialized(state);
|
||||
|
||||
const responseV2 = await state.s3
|
||||
.listObjectsV2({
|
||||
Bucket: state.bucket,
|
||||
})
|
||||
.promise();
|
||||
const responseV2 = await state.s3.send(new ListObjectsV2Command({
|
||||
Bucket: state.bucket,
|
||||
}));
|
||||
|
||||
state.objectsCount = responseV2.KeyCount === undefined ? 0 : responseV2.KeyCount;
|
||||
}
|
||||
@ -375,7 +384,7 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
|
||||
const fileNames = state.files.map((file) => file.Key);
|
||||
|
||||
function getUniqueFileName(fileName) {
|
||||
function getUniqueFileName(fileName: string): string {
|
||||
for (let count = 1; fileNames.includes(fileName); count++) {
|
||||
if (count > 1) {
|
||||
fileName = fileName.replace(/\((\d+)\)(.*)/, `(${count})$2`);
|
||||
@ -415,10 +424,11 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
appStore.setLargeUploadWarningNotification(true);
|
||||
}
|
||||
|
||||
const upload = state.s3.upload(
|
||||
{ ...params },
|
||||
{ partSize: 64 * 1024 * 1024 },
|
||||
);
|
||||
const upload = new Upload({
|
||||
client: state.s3,
|
||||
partSize: 64 * 1024 * 1024,
|
||||
params,
|
||||
});
|
||||
|
||||
upload.on('httpUploadProgress', async (progress) => {
|
||||
const file = state.uploading.find(file => file.Key === params.Key);
|
||||
@ -426,7 +436,11 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
throw new Error(`No file found with key ${JSON.stringify(params.Key)}`);
|
||||
}
|
||||
|
||||
file.progress = Math.round((progress.loaded / progress.total) * 100);
|
||||
let p = 0;
|
||||
if (progress.loaded && progress.total) {
|
||||
p = Math.round((progress.loaded / progress.total) * 100);
|
||||
}
|
||||
file.progress = p;
|
||||
});
|
||||
|
||||
if (config.state.config.newUploadModalEnabled) {
|
||||
@ -473,7 +487,7 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
}
|
||||
|
||||
try {
|
||||
await upload.promise();
|
||||
await upload.done();
|
||||
state.uploading[index].status = UploadingStatus.Finished;
|
||||
} catch (error) {
|
||||
handleUploadError(error.message, index);
|
||||
@ -509,10 +523,11 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
Body: item.Body,
|
||||
};
|
||||
|
||||
const upload = state.s3.upload(
|
||||
{ ...params },
|
||||
{ partSize: 64 * 1024 * 1024 },
|
||||
);
|
||||
const upload = new Upload({
|
||||
client: state.s3,
|
||||
partSize: 64 * 1024 * 1024,
|
||||
params,
|
||||
});
|
||||
|
||||
upload.on('httpUploadProgress', async (progress) => {
|
||||
const file = state.uploading.find(file => file.Key === params.Key);
|
||||
@ -520,7 +535,11 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
throw new Error(`No file found with key ${JSON.stringify(params.Key)}`);
|
||||
}
|
||||
|
||||
file.progress = Math.round((progress.loaded / progress.total) * 100);
|
||||
let p = 0;
|
||||
if (progress.loaded && progress.total) {
|
||||
p = Math.round((progress.loaded / progress.total) * 100);
|
||||
}
|
||||
file.progress = p;
|
||||
});
|
||||
|
||||
state.uploading[index] = {
|
||||
@ -533,7 +552,7 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
};
|
||||
|
||||
try {
|
||||
await upload.promise();
|
||||
await upload.done();
|
||||
state.uploading[index].status = UploadingStatus.Finished;
|
||||
} catch (error) {
|
||||
handleUploadError(error.message, index);
|
||||
@ -563,29 +582,26 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
async function createFolder(name): Promise<void> {
|
||||
assertIsInitialized(state);
|
||||
|
||||
await state.s3
|
||||
.putObject({
|
||||
Bucket: state.bucket,
|
||||
Key: state.path + name + '/.file_placeholder',
|
||||
})
|
||||
.promise();
|
||||
await state.s3.send(new PutObjectCommand({
|
||||
Bucket: state.bucket,
|
||||
Key: state.path + name + '/.file_placeholder',
|
||||
Body: '',
|
||||
}));
|
||||
|
||||
list();
|
||||
}
|
||||
|
||||
async function deleteObject(path: string, file?: S3.Object | BrowserObject, isFolder = false): Promise<void> {
|
||||
async function deleteObject(path: string, file?: _Object | BrowserObject, isFolder = false): Promise<void> {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertIsInitialized(state);
|
||||
|
||||
await state.s3
|
||||
.deleteObject({
|
||||
Bucket: state.bucket,
|
||||
Key: path + file.Key,
|
||||
})
|
||||
.promise();
|
||||
await state.s3.send(new DeleteObjectCommand({
|
||||
Bucket: state.bucket,
|
||||
Key: path + file.Key,
|
||||
}));
|
||||
|
||||
const config = useConfigStore();
|
||||
if (config.state.config.newUploadModalEnabled) {
|
||||
@ -604,31 +620,23 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
async function recurse(filePath) {
|
||||
assertIsInitialized(state);
|
||||
|
||||
const { Contents, CommonPrefixes } = await state.s3
|
||||
.listObjects({
|
||||
Bucket: state.bucket,
|
||||
Delimiter: '/',
|
||||
Prefix: filePath,
|
||||
})
|
||||
.promise();
|
||||
let { Contents, CommonPrefixes } = await state.s3.send(new ListObjectsCommand({
|
||||
Bucket: state.bucket,
|
||||
Delimiter: '/',
|
||||
Prefix: filePath,
|
||||
}));
|
||||
|
||||
if (Contents === undefined) {
|
||||
throw new Error(
|
||||
'Bad S3 listObjects() response: "Contents" undefined',
|
||||
);
|
||||
Contents = [];
|
||||
}
|
||||
|
||||
if (CommonPrefixes === undefined) {
|
||||
throw new Error(
|
||||
'Bad S3 listObjects() response: "CommonPrefixes" undefined',
|
||||
);
|
||||
CommonPrefixes = [];
|
||||
}
|
||||
|
||||
async function thread() {
|
||||
if (Contents === undefined) {
|
||||
throw new Error(
|
||||
'Bad S3 listObjects() response: "Contents" undefined',
|
||||
);
|
||||
Contents = [];
|
||||
}
|
||||
|
||||
while (Contents.length) {
|
||||
@ -679,10 +687,10 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
function download(file): void {
|
||||
assertIsInitialized(state);
|
||||
|
||||
const url = state.s3.getSignedUrl('getObject', {
|
||||
const url = getSignedUrl(state.s3, new GetObjectCommand({
|
||||
Bucket: state.bucket,
|
||||
Key: state.path + file.Key,
|
||||
});
|
||||
}));
|
||||
const downloadURL = function(data, fileName) {
|
||||
const a = document.createElement('a');
|
||||
a.href = data;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { Component } from 'vue';
|
||||
|
||||
import { getId } from '@/utils/idGenerator';
|
||||
|
||||
import SuccessIcon from '@/../static/images/notifications/success.svg';
|
||||
@ -32,7 +30,7 @@ export class DelayedNotification {
|
||||
public readonly type: string;
|
||||
public readonly message: string;
|
||||
public readonly style: { backgroundColor: string };
|
||||
public readonly icon: Component;
|
||||
public readonly icon: string;
|
||||
|
||||
constructor(callback: () => void, type: string, message: string) {
|
||||
this.callback = callback;
|
||||
|
@ -1,20 +1,8 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { Component } from 'vue';
|
||||
|
||||
import EmailIcon from '../../static/images/objects/email.svg';
|
||||
|
||||
/**
|
||||
* Exposes all properties and methods present and available in the file/browser objects in Browser.
|
||||
*/
|
||||
export interface BrowserFile extends File {
|
||||
Key: string;
|
||||
LastModified: Date;
|
||||
Size: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export enum ShareOptions {
|
||||
Reddit = 'Reddit',
|
||||
Facebook = 'Facebook',
|
||||
@ -31,6 +19,6 @@ export class ShareButtonConfig {
|
||||
public label: ShareOptions = ShareOptions.Email,
|
||||
public color: string = 'white',
|
||||
public link: string = '',
|
||||
public image: Component = EmailIcon,
|
||||
public image: string = EmailIcon,
|
||||
) {}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { Component } from 'vue';
|
||||
|
||||
import CreateNewAccessIcon from '@/../static/images/accessGrants/newCreateFlow/createNewAccess.svg';
|
||||
import ChoosePermissionIcon from '@/../static/images/accessGrants/newCreateFlow/choosePermission.svg';
|
||||
import AccessEncryptionIcon from '@/../static/images/accessGrants/newCreateFlow/accessEncryption.svg';
|
||||
@ -20,7 +18,7 @@ import EndDateIcon from '@/../static/images/accessGrants/newCreateFlow/endDateIc
|
||||
import EncryptionPassphraseIcon from '@/../static/images/accessGrants/newCreateFlow/encryptionPassphraseIcon.svg';
|
||||
|
||||
export interface IconAndTitle {
|
||||
icon: Component;
|
||||
icon: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { Component } from 'vue';
|
||||
|
||||
export class NavigationLink {
|
||||
private readonly _path: string;
|
||||
private readonly _name: string;
|
||||
private readonly _icon: Component | undefined;
|
||||
private readonly _icon: string | undefined;
|
||||
|
||||
public constructor(path: string, name: string, icon?: Component) {
|
||||
public constructor(path: string, name: string, icon?: string) {
|
||||
this._path = path;
|
||||
this._name = name;
|
||||
this._icon = icon;
|
||||
@ -22,7 +20,7 @@ export class NavigationLink {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public get icon(): Component | undefined {
|
||||
public get icon(): string | undefined {
|
||||
return this._icon;
|
||||
}
|
||||
|
||||
@ -30,7 +28,7 @@ export class NavigationLink {
|
||||
return this._path[0] !== '/';
|
||||
}
|
||||
|
||||
public withIcon(icon: Component): NavigationLink {
|
||||
public withIcon(icon: string): NavigationLink {
|
||||
return new NavigationLink(this._path, this._name, icon);
|
||||
}
|
||||
|
||||
|
8
web/satellite/src/types/svg.d.ts
vendored
8
web/satellite/src/types/svg.d.ts
vendored
@ -1,8 +0,0 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
declare module '*.svg' {
|
||||
import { Component } from 'vue';
|
||||
const content: Component;
|
||||
export default content;
|
||||
}
|
4
web/satellite/src/types/vue.d.ts
vendored
4
web/satellite/src/types/vue.d.ts
vendored
@ -1,9 +1,11 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue';
|
||||
// eslint-disable-next-line
|
||||
const component: DefineComponent<any, any, any>;
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ self.onmessage = async function (event) {
|
||||
switch (data.type) {
|
||||
case 'Setup':
|
||||
try {
|
||||
const go = new global.Go();
|
||||
const go = new self.Go();
|
||||
const response = await fetch('/static/static/wasm/access.wasm');
|
||||
const buffer = await response.arrayBuffer();
|
||||
const module = await WebAssembly.compile(buffer);
|
||||
|
@ -13,7 +13,7 @@ import { useNotificationsStore } from '@/store/modules/notificationsStore';
|
||||
* Satellite url.
|
||||
*/
|
||||
const satelliteUrl = new HttpLink({
|
||||
uri: process.env.VUE_APP_ENDPOINT_URL,
|
||||
uri: import.meta.env.VITE_ENDPOINT_URL,
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -96,7 +96,7 @@ onMounted(() => {
|
||||
padding: 52px 24px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
background: url('~@/../static/images/errors/dotWorld.png') no-repeat center 178px;
|
||||
background: url('../../static/images/errors/dotWorld.png') no-repeat center 178px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow-y: auto;
|
||||
|
@ -281,11 +281,6 @@ import { computed, onBeforeMount, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
|
||||
|
||||
import BottomArrowIcon from '../../../static/images/common/lightBottomArrow.svg';
|
||||
import SelectedCheckIcon from '../../../static/images/common/selectedCheck.svg';
|
||||
import LogoIcon from '../../../static/images/logo.svg';
|
||||
import LogoWithPartnerIcon from '../../../static/images/partnerStorjLogo.svg';
|
||||
|
||||
import { AuthHttpApi } from '@/api/auth';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { MultiCaptchaConfig, PartneredSatellite } from '@/types/config';
|
||||
@ -299,6 +294,10 @@ import VButton from '@/components/common/VButton.vue';
|
||||
import VInput from '@/components/common/VInput.vue';
|
||||
import AddCouponCodeInput from '@/components/common/AddCouponCodeInput.vue';
|
||||
|
||||
import LogoWithPartnerIcon from '@/../static/images/partnerStorjLogo.svg';
|
||||
import LogoIcon from '@/../static/images/logo.svg';
|
||||
import SelectedCheckIcon from '@/../static/images/common/selectedCheck.svg';
|
||||
import BottomArrowIcon from '@/../static/images/common/lightBottomArrow.svg';
|
||||
import RegisterGlobe from '@/../static/images/register/RegisterGlobe.svg';
|
||||
import InfoIcon from '@/../static/images/register/info.svg';
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
{
|
||||
"default": {
|
||||
"title": "Welcome to the distributed cloud.",
|
||||
|
@ -1,8 +0,0 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
module.exports = {
|
||||
process () {
|
||||
return `module.exports = { render: function(){ return this._c("svg") } }`;
|
||||
},
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { vi } from 'vitest';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
import { ProjectMembersApiGql } from '@/api/projectMembers';
|
||||
@ -23,7 +24,7 @@ const projectMember2 = new ProjectMember('testFullName2', 'testShortName2', 'tes
|
||||
describe('actions', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia());
|
||||
jest.resetAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('fetch project members', async function () {
|
||||
@ -34,7 +35,7 @@ describe('actions', () => {
|
||||
testProjectMembersPage.totalCount = 1;
|
||||
testProjectMembersPage.pageCount = 1;
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'get')
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'get')
|
||||
.mockImplementation(() => Promise.resolve(testProjectMembersPage));
|
||||
|
||||
await store.getProjectMembers(FIRST_PAGE, selectedProject.id);
|
||||
@ -95,7 +96,7 @@ describe('actions', () => {
|
||||
expect(store.state.page.projectMembers[0].isSelected).toBe(true);
|
||||
expect(store.state.selectedProjectMembersEmails.length).toBe(1);
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'get')
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'get')
|
||||
.mockImplementation(() => Promise.resolve(testProjectMembersPage));
|
||||
|
||||
await store.getProjectMembers(FIRST_PAGE, selectedProject.id);
|
||||
@ -130,7 +131,7 @@ describe('actions', () => {
|
||||
it('add project members', async function () {
|
||||
const store = useProjectMembersStore();
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'add').mockReturnValue(Promise.resolve());
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'add').mockReturnValue(Promise.resolve());
|
||||
|
||||
try {
|
||||
await store.addProjectMembers([projectMember1.user.email], selectedProject.id);
|
||||
@ -143,7 +144,7 @@ describe('actions', () => {
|
||||
it('add project member throws error when api call fails', async function () {
|
||||
const store = useProjectMembersStore();
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'add').mockImplementation(() => {
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'add').mockImplementation(() => {
|
||||
throw TEST_ERROR;
|
||||
});
|
||||
|
||||
@ -164,7 +165,7 @@ describe('actions', () => {
|
||||
it('delete project members', async function () {
|
||||
const store = useProjectMembersStore();
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'delete').mockReturnValue(Promise.resolve());
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'delete').mockReturnValue(Promise.resolve());
|
||||
|
||||
try {
|
||||
await store.deleteProjectMembers(selectedProject.id);
|
||||
@ -177,7 +178,7 @@ describe('actions', () => {
|
||||
it('delete project member throws error when api call fails', async function () {
|
||||
const store = useProjectMembersStore();
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'delete').mockImplementation(() => {
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'delete').mockImplementation(() => {
|
||||
throw TEST_ERROR;
|
||||
});
|
||||
|
||||
@ -198,7 +199,7 @@ describe('actions', () => {
|
||||
it('fetch project members', async function () {
|
||||
const store = useProjectMembersStore();
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'get').mockReturnValue(
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'get').mockReturnValue(
|
||||
Promise.resolve(new ProjectMembersPage(
|
||||
[projectMember1],
|
||||
'',
|
||||
@ -223,7 +224,7 @@ describe('actions', () => {
|
||||
it('fetch project members throws error when api call fails', async function () {
|
||||
const store = useProjectMembersStore();
|
||||
|
||||
jest.spyOn(ProjectMembersApiGql.prototype, 'get').mockImplementation(() => {
|
||||
vi.spyOn(ProjectMembersApiGql.prototype, 'get').mockImplementation(() => {
|
||||
throw TEST_ERROR;
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { vi } from 'vitest';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
import { ProjectsApiGql } from '@/api/projects';
|
||||
@ -31,7 +32,7 @@ const projects = [
|
||||
describe('actions', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia());
|
||||
jest.resetAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('select project', () => {
|
||||
@ -47,7 +48,7 @@ describe('actions', () => {
|
||||
it('success fetch projects', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'get').mockReturnValue(
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'get').mockReturnValue(
|
||||
Promise.resolve(projects),
|
||||
);
|
||||
|
||||
@ -59,7 +60,7 @@ describe('actions', () => {
|
||||
it('fetch throws an error when api call fails', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'get').mockImplementation(() => { throw new Error(); });
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'get').mockImplementation(() => { throw new Error(); });
|
||||
|
||||
try {
|
||||
await store.getProjects();
|
||||
@ -72,7 +73,7 @@ describe('actions', () => {
|
||||
it('success create project', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'create').mockReturnValue(
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'create').mockReturnValue(
|
||||
Promise.resolve(project),
|
||||
);
|
||||
|
||||
@ -85,7 +86,7 @@ describe('actions', () => {
|
||||
it('create throws an error when create api call fails', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'create').mockImplementation(() => { throw new Error(); });
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'create').mockImplementation(() => { throw new Error(); });
|
||||
|
||||
try {
|
||||
await store.createProject(new ProjectFields());
|
||||
@ -99,7 +100,7 @@ describe('actions', () => {
|
||||
it('success update project name', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'update').mockReturnValue(
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'update').mockReturnValue(
|
||||
Promise.resolve(),
|
||||
);
|
||||
|
||||
@ -115,7 +116,7 @@ describe('actions', () => {
|
||||
it('success update project description', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'update').mockReturnValue(
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'update').mockReturnValue(
|
||||
Promise.resolve(),
|
||||
);
|
||||
|
||||
@ -131,7 +132,7 @@ describe('actions', () => {
|
||||
it('success get project limits', async () => {
|
||||
const store = useProjectsStore();
|
||||
|
||||
jest.spyOn(ProjectsApiGql.prototype, 'getLimits').mockReturnValue(
|
||||
vi.spyOn(ProjectsApiGql.prototype, 'getLimits').mockReturnValue(
|
||||
Promise.resolve(limits),
|
||||
);
|
||||
|
||||
|
77
web/satellite/vite.config.js
Normal file
77
web/satellite/vite.config.js
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { defineConfig } from 'vite';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import viteCompression from 'vite-plugin-compression';
|
||||
import vitePluginRequire from 'vite-plugin-require';
|
||||
import svgLoader from 'vite-svg-loader';
|
||||
|
||||
const productionBrotliExtensions = ['js', 'css', 'ttf', 'woff', 'woff2'];
|
||||
|
||||
const plugins = [
|
||||
vue(),
|
||||
viteCompression({
|
||||
algorithm: 'brotliCompress',
|
||||
threshold: 1024,
|
||||
ext: '.br',
|
||||
filter: new RegExp('\\.(' + productionBrotliExtensions.join('|') + ')$'),
|
||||
}),
|
||||
svgLoader({
|
||||
svgoConfig: {
|
||||
plugins: [{ name: 'removeViewBox', fn: () => {} }],
|
||||
},
|
||||
}),
|
||||
vitePluginRequire(),
|
||||
];
|
||||
|
||||
if (process.env['STORJ_DEBUG_BUNDLE_SIZE']) {
|
||||
plugins.push(visualizer({
|
||||
template: 'treemap', // or sunburst
|
||||
open: true,
|
||||
brotliSize: true,
|
||||
filename: 'analyse.html', // will be saved in project's root
|
||||
}));
|
||||
}
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
return {
|
||||
base: '/static/dist',
|
||||
plugins,
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, './src'),
|
||||
'stream': 'stream-browserify',
|
||||
'util': 'util/',
|
||||
},
|
||||
extensions: ['.js', '.ts', '.svg', '.vue'],
|
||||
},
|
||||
build: {
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
experimentalMinChunkSize: 50*1024,
|
||||
},
|
||||
},
|
||||
},
|
||||
define: {
|
||||
'process.env': {},
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: [
|
||||
'./vitest.setup.ts',
|
||||
],
|
||||
exclude: [
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
'**/tests/unit/ignore/**',
|
||||
],
|
||||
},
|
||||
};
|
||||
});
|
9
web/satellite/vitest.setup.ts
Normal file
9
web/satellite/vitest.setup.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import createFetchMock from 'vitest-fetch-mock';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
const fetchMocker = createFetchMock(vi);
|
||||
|
||||
fetchMocker.enableMocks();
|
@ -1,85 +0,0 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const webpack = require('webpack');
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
||||
const productionBrotliExtensions = ['js', 'css', 'ttf', 'woff', 'woff2'];
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
const plugins = [
|
||||
new CompressionWebpackPlugin({
|
||||
algorithm: 'brotliCompress',
|
||||
filename: '[path][name].br',
|
||||
test: new RegExp('\\.(' + productionBrotliExtensions.join('|') + ')$'),
|
||||
threshold: 1024,
|
||||
minRatio: 0.8,
|
||||
}),
|
||||
new webpack.optimize.MinChunkSizePlugin({
|
||||
minChunkSize: 50*1024,
|
||||
}),
|
||||
new webpack.IgnorePlugin({
|
||||
contextRegExp: /bip39[\\/]src$/,
|
||||
resourceRegExp: /^\.\/wordlists\/(?!english)/,
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
}),
|
||||
];
|
||||
|
||||
if (process.env['STORJ_DEBUG_BUNDLE_SIZE']) {
|
||||
plugins.push(new BundleAnalyzerPlugin());
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
publicPath: '/static/dist',
|
||||
productionSourceMap: false,
|
||||
parallel: true,
|
||||
lintOnSave: process.env.NODE_ENV !== 'production', // disables eslint for builds
|
||||
configureWebpack: {
|
||||
plugins,
|
||||
resolve: {
|
||||
fallback: {
|
||||
'util': require.resolve('util/'),
|
||||
'stream': require.resolve('stream-browserify'),
|
||||
'buffer': require.resolve('buffer'),
|
||||
},
|
||||
},
|
||||
},
|
||||
chainWebpack: config => {
|
||||
// Avoid breaking browser UI cache.
|
||||
config.output.chunkFilename(`js/vendors_[name]_[chunkhash].js`);
|
||||
config.output.filename(`js/app_[name]_[chunkhash].js`);
|
||||
|
||||
config.resolve.alias
|
||||
.set('@', path.resolve('src'));
|
||||
|
||||
// Disable node_modules/.cache directory usage due to permissions.
|
||||
// This is enabled by default in https://cli.vuejs.org/core-plugins/babel.html#caching.
|
||||
config.module.rule('js').use('babel-loader')
|
||||
.tap(options => Object.assign(options, { cacheDirectory: false }));
|
||||
|
||||
config
|
||||
.plugin('html')
|
||||
.tap(args => {
|
||||
args[0].template = './index.html';
|
||||
return args;
|
||||
});
|
||||
|
||||
const svgRule = config.module.rule('svg');
|
||||
svgRule.uses.clear();
|
||||
svgRule.type(); // Disable webpack 5 asset management.
|
||||
svgRule
|
||||
.use('vue-loader')
|
||||
.loader('vue-loader')
|
||||
.end()
|
||||
.use('vue-svg-loader')
|
||||
.loader('vue-svg-loader')
|
||||
.options({
|
||||
svgo: {
|
||||
plugins: [{ removeViewBox: false }],
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue
Block a user