web/satellite: FileBrowser component migrated to use composition api
Change-Id: Id0bb007b790e0d2365eb78f2bc78f8c3da05bc70
This commit is contained in:
parent
e4fab975ad
commit
8ebea4cf8d
@ -32,13 +32,7 @@ module.exports = {
|
||||
'indent': ['warn', 4],
|
||||
'vue/html-indent': ['warn', 4],
|
||||
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn', {
|
||||
'vars': 'all',
|
||||
'args': 'all',
|
||||
'argsIgnorePattern': '^_',
|
||||
}],
|
||||
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
|
||||
@ -65,6 +59,8 @@ module.exports = {
|
||||
'newlines-between': 'always',
|
||||
}],
|
||||
'no-duplicate-imports': 'error',
|
||||
'import/default': 'off',
|
||||
'vue/script-setup-uses-vars': 'error',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'quotes': ['error', 'single', { 'allowTemplateLiterals': true }],
|
||||
'semi': ['error', 'always'],
|
||||
|
@ -146,7 +146,6 @@
|
||||
items-label="access grants"
|
||||
:limit="accessGrantLimit"
|
||||
:total-page-count="totalPageCount"
|
||||
:items="accessGrantsList"
|
||||
:total-items-count="accessGrantsTotalCount"
|
||||
:on-page-click-callback="onPageClick"
|
||||
>
|
||||
@ -186,7 +185,6 @@
|
||||
:selectable="true"
|
||||
:limit="accessGrantLimit"
|
||||
:total-page-count="totalPageCount"
|
||||
:items="accessGrantsList"
|
||||
:total-items-count="accessGrantsTotalCount"
|
||||
:on-page-click-callback="onPageClick"
|
||||
>
|
||||
|
@ -155,7 +155,6 @@
|
||||
<v-table
|
||||
class="payments-area__transactions-area__table"
|
||||
items-label="transactions"
|
||||
:items="displayedHistory"
|
||||
:limit="pageSize"
|
||||
:total-page-count="pageCount"
|
||||
:total-items-count="transactionCount"
|
||||
|
@ -4,7 +4,7 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<div class="d-inline">
|
||||
<a class="d-inline path-buckets" @click="() => $emit('bucketClick')">Buckets</a>
|
||||
<a class="d-inline path-buckets" @click="bucketClick">Buckets</a>
|
||||
<svg
|
||||
class="mx-3"
|
||||
width="6"
|
||||
@ -24,9 +24,9 @@
|
||||
</div>
|
||||
|
||||
<div v-for="(path, idx) in crumbs" :key="idx" class="d-inline">
|
||||
<router-link :to="link(idx)">
|
||||
<span @click="redirectToCrumb(idx)">
|
||||
<a class="path" href="javascript:null">{{ path }}</a>
|
||||
</router-link>
|
||||
</span>
|
||||
|
||||
<svg
|
||||
v-if="displayDivider(idx)"
|
||||
@ -49,48 +49,65 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
// @vue/component
|
||||
@Component
|
||||
export default class BreadCrumbs extends Vue {
|
||||
/**
|
||||
* Retrieves the current bucket name from the store.
|
||||
*/
|
||||
private get bucketName(): string {
|
||||
return this.$store.state.files.bucket;
|
||||
}
|
||||
import { useRouter, useStore } from '@/utils/hooks';
|
||||
|
||||
/**
|
||||
* Retrieves the current path from the store and creates an array of folders for the bread crumbs that the user can click on.
|
||||
*/
|
||||
public get crumbs(): string[] {
|
||||
let path: string[] = this.$store.state.files.path.split('/');
|
||||
path =
|
||||
path.length > 1
|
||||
? [this.bucketName, ...path.slice(0, path.length - 1)]
|
||||
: [this.bucketName];
|
||||
return path;
|
||||
}
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
|
||||
/**
|
||||
* Returns a link to the folder at the current breadcrumb index.
|
||||
*/
|
||||
public link(idx: number): string {
|
||||
const crumbs = this.crumbs;
|
||||
let path = '';
|
||||
if (idx > 0) path = crumbs.slice(1, idx + 1).join('/') + '/';
|
||||
return this.$store.state.files.browserRoot + path;
|
||||
}
|
||||
const emit = defineEmits(['onUpdate']);
|
||||
|
||||
/**
|
||||
* Returns a boolean denoting if a divider needs to be displayed at current breadcrumb index.
|
||||
*/
|
||||
public displayDivider(idx: number): boolean {
|
||||
const length = this.crumbs.length;
|
||||
return (idx !== 0 || length > 1) && idx !== length - 1;
|
||||
}
|
||||
/**
|
||||
* Retrieves the current bucket name from the store.
|
||||
*/
|
||||
const bucketName = computed((): string => {
|
||||
return store.state.files.bucket;
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieves the current path from the store and creates an array of folders for the bread crumbs that the user can click on.
|
||||
*/
|
||||
const crumbs = computed((): string[] => {
|
||||
let path: string[] = store.state.files.path.split('/');
|
||||
path =
|
||||
path.length > 1
|
||||
? [bucketName.value, ...path.slice(0, path.length - 1)]
|
||||
: [bucketName.value];
|
||||
return path;
|
||||
});
|
||||
|
||||
function bucketClick() {
|
||||
emit('bucketClick');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to partial upload to bucket buckets path.
|
||||
*/
|
||||
async function redirectToCrumb(idx: number): Promise<void> {
|
||||
await router.push(link(idx)).catch(err => {});
|
||||
emit('onUpdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a link to the folder at the current breadcrumb index.
|
||||
*/
|
||||
function link(idx: number): string {
|
||||
let path = '';
|
||||
|
||||
if (idx > 0) path = crumbs.value.slice(1, idx + 1).join('/') + '/';
|
||||
|
||||
return store.state.files.browserRoot + path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean denoting if a divider needs to be displayed at current breadcrumb index.
|
||||
*/
|
||||
function displayDivider(idx: number): boolean {
|
||||
const length = crumbs.value.length;
|
||||
|
||||
return (idx !== 0 || length > 1) && idx !== length - 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
@drop.prevent="upload"
|
||||
@dragover.prevent
|
||||
>
|
||||
<bread-crumbs @bucketClick="goToBuckets" />
|
||||
<bread-crumbs @onUpdate="onRouteChange" @bucketClick="goToBuckets" />
|
||||
|
||||
<div class="tile-action-bar">
|
||||
<h2 class="tile-action-bar__title">{{ bucketName }}</h2>
|
||||
@ -150,7 +150,7 @@
|
||||
<td />
|
||||
</tr>
|
||||
|
||||
<tr v-if="filesUploadingLength">
|
||||
<tr v-if="filesUploading.length">
|
||||
<div class="files-uploading-count my-3">
|
||||
<div
|
||||
class="px-2"
|
||||
@ -164,14 +164,13 @@
|
||||
|
||||
<tr v-if="path.length > 0">
|
||||
<td class="px-3">
|
||||
<router-link to="../">
|
||||
<span @click="onBack">
|
||||
<a
|
||||
id="navigate-back"
|
||||
href="javascript:null"
|
||||
class="px-2 font-weight-bold"
|
||||
@click="back"
|
||||
>..</a>
|
||||
</router-link>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -180,6 +179,7 @@
|
||||
:key="file.Key"
|
||||
:path="path"
|
||||
:file="file"
|
||||
@onUpdate="onRouteChange"
|
||||
/>
|
||||
|
||||
<file-entry
|
||||
@ -191,7 +191,7 @@
|
||||
</template>
|
||||
</v-table>
|
||||
<div
|
||||
v-if="displayUpload"
|
||||
v-if="!fetchingFilesSpinner"
|
||||
class="upload-help"
|
||||
@click="buttonFileUpload"
|
||||
>
|
||||
@ -201,7 +201,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="fetchingFilesSpinner"
|
||||
v-else
|
||||
class="d-flex justify-content-center"
|
||||
>
|
||||
<div class="spinner-border" />
|
||||
@ -212,8 +212,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, ref } from 'vue';
|
||||
|
||||
import FileBrowserHeader from './FileBrowserHeader.vue';
|
||||
import FileEntry from './FileEntry.vue';
|
||||
@ -224,6 +224,7 @@ import { BrowserFile } from '@/types/browser';
|
||||
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { useRouter, useStore } from '@/utils/hooks';
|
||||
import eventBus from '@/utils/eventBus';
|
||||
|
||||
import BucketSettingsNav from '@/components/objects/BucketSettingsNav.vue';
|
||||
@ -233,290 +234,245 @@ import BlackArrowHide from '@/../static/images/common/BlackArrowHide.svg';
|
||||
import BlackArrowExpand from '@/../static/images/common/BlackArrowExpand.svg';
|
||||
import UploadIcon from '@/../static/images/browser/upload.svg';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
BucketSettingsNav,
|
||||
FileEntry,
|
||||
BreadCrumbs,
|
||||
VTable,
|
||||
FileBrowserHeader,
|
||||
BlackArrowExpand,
|
||||
BlackArrowHide,
|
||||
UploadIcon,
|
||||
},
|
||||
})
|
||||
export default class FileBrowser extends Vue {
|
||||
public $refs!: {
|
||||
folderInput: HTMLInputElement;
|
||||
fileInput: HTMLInputElement;
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
|
||||
const folderInput = ref<HTMLInputElement>(null);
|
||||
const fileInput = ref<HTMLInputElement>(null);
|
||||
|
||||
const fetchingFilesSpinner = ref<boolean>(false);
|
||||
const isUploadDropDownShown = ref<boolean>(false);
|
||||
|
||||
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
/**
|
||||
* Check if the s3 client has been initialized in the store.
|
||||
*/
|
||||
const isInitialized = computed((): boolean => {
|
||||
return store.getters['files/isInitialized'];
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the current path from the store.
|
||||
*/
|
||||
const path = computed((): string => {
|
||||
return store.state.files.path;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return files that are currently being uploaded from the store.
|
||||
*/
|
||||
const filesUploading = computed((): string => {
|
||||
return store.state.files.uploading;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return up to five files currently being uploaded for display purposes.
|
||||
*/
|
||||
const formattedFilesUploading = computed((): BrowserFile[] => {
|
||||
if (filesUploading.value.length > 5) {
|
||||
return filesUploading.value.slice(0, 5);
|
||||
}
|
||||
|
||||
return filesUploading.value;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the text of how many files in total are being uploaded to be displayed to give users more context.
|
||||
*/
|
||||
const formattedFilesWaitingToBeUploaded = computed((): BrowserFile[] => {
|
||||
let file = 'file';
|
||||
|
||||
if (filesUploading.value.length > 1) {
|
||||
file = 'files';
|
||||
}
|
||||
|
||||
return `${filesUploading.value.length} ${file}`;
|
||||
});
|
||||
|
||||
const bucketName = computed((): string => {
|
||||
return store.state.files.bucket;
|
||||
});
|
||||
|
||||
const files = computed((): BrowserFile[] => {
|
||||
return store.getters['files/sortedFiles'];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of BrowserFile type that are files and not folders.
|
||||
*/
|
||||
const singleFiles = computed((): BrowserFile[] => {
|
||||
return files.value.filter((f) => f.type === 'file');
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of BrowserFile type that are folders and not files.
|
||||
*/
|
||||
const folders = computed((): BrowserFile[] => {
|
||||
return files.value.filter((f) => f.type === 'folder');
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the pathMatch from the current route.
|
||||
*/
|
||||
const routePath = ref(calculateRoutePath());
|
||||
|
||||
/**
|
||||
* Returns bucket name from store.
|
||||
*/
|
||||
const bucket = computed((): string => {
|
||||
return store.state.objectsModule.fileComponentBucketName;
|
||||
});
|
||||
|
||||
function calculateRoutePath(): string {
|
||||
let pathMatch = router.history.current.params.pathMatch;
|
||||
pathMatch = Array.isArray(pathMatch)
|
||||
? pathMatch.join('/') + '/'
|
||||
: pathMatch;
|
||||
return pathMatch;
|
||||
}
|
||||
|
||||
async function onBack(): Promise<void> {
|
||||
await router.push('../');
|
||||
await onRouteChange();
|
||||
}
|
||||
|
||||
async function onRouteChange(): Promise<void> {
|
||||
routePath.value = calculateRoutePath();
|
||||
await store.dispatch('files/closeDropdown');
|
||||
await list(routePath.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set spinner state. If routePath is not present navigate away. If there's some error re-render the page with a call to list. All of this is done on the created lifecycle method.
|
||||
*/
|
||||
onBeforeMount(async () => {
|
||||
if (!bucket.value) {
|
||||
const path = RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path;
|
||||
|
||||
await analytics.pageVisit(path);
|
||||
await router.push(path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// display the spinner while files are being fetched
|
||||
fetchingFilesSpinner.value = true;
|
||||
|
||||
if (!routePath.value) {
|
||||
try {
|
||||
await analytics.pageVisit(`${store.state.files.browserRoot}${path.value}`);
|
||||
await router.push({
|
||||
path: `${store.state.files.browserRoot}${path.value}`,
|
||||
});
|
||||
} catch (err) {
|
||||
await list('');
|
||||
}
|
||||
}
|
||||
|
||||
// remove the spinner after files have been fetched
|
||||
fetchingFilesSpinner.value = false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Close modal, file share modal, dropdown, and remove all selected files from the store.
|
||||
*/
|
||||
function closeModalDropdown(): void {
|
||||
if (store.state.files.openedDropdown) {
|
||||
store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
if (store.state.files.selectedFile) {
|
||||
store.dispatch('files/clearAllSelectedFiles');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the folder creation modal in the store.
|
||||
*/
|
||||
function toggleFolderCreationModal(): void {
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_NEW_FOLDER_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file name of the passed in file argument formatted.
|
||||
*/
|
||||
function filename(file: BrowserFile): string {
|
||||
return file.Key.length > 25
|
||||
? file.Key.slice(0, 25) + '...'
|
||||
: file.Key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the current selected or dragged-and-dropped file.
|
||||
*/
|
||||
async function upload(e: Event): Promise<void> {
|
||||
const callback = () => {
|
||||
eventBus.$emit('upload_progress');
|
||||
};
|
||||
public fetchingFilesSpinner = false;
|
||||
public isUploadDropDownShown = false;
|
||||
await store.dispatch('files/upload', { e, callback });
|
||||
await analytics.eventTriggered(AnalyticsEvent.OBJECT_UPLOADED);
|
||||
const target = e.target as HTMLInputElement;
|
||||
target.value = '';
|
||||
}
|
||||
|
||||
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
/**
|
||||
* Cancel the upload of the current file that's passed in as an argument.
|
||||
*/
|
||||
function cancelUpload(fileName: string): void {
|
||||
store.dispatch('files/cancelUpload', fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the s3 client has been initialized in the store.
|
||||
*/
|
||||
public get isInitialized(): boolean {
|
||||
return this.$store.getters['files/isInitialized'];
|
||||
}
|
||||
/**
|
||||
* Call the list method from the store, which will trigger a re-render and fetch all files under the current path passed in as an argument.
|
||||
*/
|
||||
async function list(path: string): Promise<void> {
|
||||
await store.dispatch('files/list', path, {
|
||||
root: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current path from the store.
|
||||
*/
|
||||
private get path(): string {
|
||||
return this.$store.state.files.path;
|
||||
}
|
||||
/**
|
||||
* Open the operating system's file system for file upload.
|
||||
*/
|
||||
async function buttonFileUpload(): Promise<void> {
|
||||
await analytics.eventTriggered(AnalyticsEvent.UPLOAD_FILE_CLICKED);
|
||||
const fileInputElement = fileInput.value as HTMLInputElement;
|
||||
fileInputElement.click();
|
||||
closeUploadDropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return files that are currently being uploaded from the store.
|
||||
*/
|
||||
private get filesUploading(): BrowserFile[] {
|
||||
return this.$store.state.files.uploading;
|
||||
}
|
||||
/**
|
||||
* Open the operating system's file system for folder upload.
|
||||
*/
|
||||
async function buttonFolderUpload(): Promise<void> {
|
||||
await analytics.eventTriggered(AnalyticsEvent.UPLOAD_FOLDER_CLICKED);
|
||||
const folderInputElement = folderInput.value as HTMLInputElement;
|
||||
folderInputElement.click();
|
||||
closeUploadDropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the array of files currently being uploaded.
|
||||
*/
|
||||
public get filesUploadingLength(): number {
|
||||
return this.filesUploading.length;
|
||||
}
|
||||
/**
|
||||
* Toggles upload options dropdown.
|
||||
*/
|
||||
function toggleUploadDropdown(): void {
|
||||
isUploadDropDownShown.value = !isUploadDropDownShown.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return up to five files currently being uploaded for display purposes.
|
||||
*/
|
||||
public get formattedFilesUploading(): BrowserFile[] {
|
||||
if (this.filesUploadingLength > 5) {
|
||||
return this.filesUploading.slice(0, 5);
|
||||
}
|
||||
|
||||
return this.filesUploading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text of how many files in total are being uploaded to be displayed to give users more context.
|
||||
*/
|
||||
public get formattedFilesWaitingToBeUploaded(): string {
|
||||
let file = 'file';
|
||||
|
||||
if (this.filesUploadingLength > 1) {
|
||||
file = 'files';
|
||||
}
|
||||
|
||||
return `${this.filesUploadingLength} ${file}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current bucket from the store.
|
||||
*/
|
||||
private get bucketName(): string {
|
||||
return this.$store.state.files.bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all of the files sorted from the store.
|
||||
*/
|
||||
private get files(): BrowserFile[] {
|
||||
return this.$store.getters['files/sortedFiles'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of BrowserFile type that are files and not folders.
|
||||
*/
|
||||
public get singleFiles(): BrowserFile[] {
|
||||
return this.files.filter((f) => f.type === 'file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of BrowserFile type that are folders and not files.
|
||||
*/
|
||||
public get folders(): BrowserFile[] {
|
||||
return this.files.filter((f) => f.type === 'folder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the pathMatch from the current route.
|
||||
*/
|
||||
private get routePath(): string {
|
||||
let pathMatch = this.$route.params.pathMatch;
|
||||
pathMatch = Array.isArray(pathMatch)
|
||||
? pathMatch.join('/') + '/'
|
||||
: pathMatch;
|
||||
return pathMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns bucket name from store.
|
||||
*/
|
||||
private get bucket(): string {
|
||||
return this.$store.state.objectsModule.fileComponentBucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the upload display is allowed to be shown.
|
||||
*/
|
||||
public get displayUpload(): boolean {
|
||||
return !this.fetchingFilesSpinner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch for changes in the path and call goToRoutePath, navigating away from the current page.
|
||||
*/
|
||||
@Watch('routePath')
|
||||
private async handleRoutePathChange() {
|
||||
await this.goToRoutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set spinner state. If routePath is not present navigate away. If there's some error re-render the page with a call to list. All of this is done on the created lifecycle method.
|
||||
*/
|
||||
public async created(): Promise<void> {
|
||||
if (!this.bucket) {
|
||||
const path = RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path;
|
||||
|
||||
this.analytics.pageVisit(path);
|
||||
await this.$router.push(path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// display the spinner while files are being fetched
|
||||
this.fetchingFilesSpinner = true;
|
||||
|
||||
if (!this.routePath) {
|
||||
try {
|
||||
this.analytics.pageVisit(`${this.$store.state.files.browserRoot}${this.path}`);
|
||||
await this.$router.push({
|
||||
path: `${this.$store.state.files.browserRoot}${this.path}`,
|
||||
});
|
||||
} catch (err) {
|
||||
await this.list('');
|
||||
}
|
||||
}
|
||||
|
||||
// remove the spinner after files have been fetched
|
||||
this.fetchingFilesSpinner = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close modal, file share modal, dropdown, and remove all selected files from the store.
|
||||
*/
|
||||
public closeModalDropdown(): void {
|
||||
if (this.$store.state.files.openedDropdown) {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
if (this.$store.state.files.selectedFile) {
|
||||
this.$store.dispatch('files/clearAllSelectedFiles');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the folder creation modal in the store.
|
||||
*/
|
||||
public toggleFolderCreationModal(): void {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_NEW_FOLDER_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file name of the passed in file argument formatted.
|
||||
*/
|
||||
public filename(file: BrowserFile): string {
|
||||
return file.Key.length > 25
|
||||
? file.Key.slice(0, 25) + '...'
|
||||
: file.Key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the current selected or dragged-and-dropped file.
|
||||
*/
|
||||
public async upload(e: Event): Promise<void> {
|
||||
const callback = () => {
|
||||
eventBus.$emit('upload_progress');
|
||||
};
|
||||
await this.$store.dispatch('files/upload', { e, callback });
|
||||
this.analytics.eventTriggered(AnalyticsEvent.OBJECT_UPLOADED);
|
||||
const target = e.target as HTMLInputElement;
|
||||
target.value = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the upload of the current file that's passed in as an argument.
|
||||
*/
|
||||
public cancelUpload(fileName: string): void {
|
||||
this.$store.dispatch('files/cancelUpload', fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the list method from the store, which will trigger a re-render and fetch all files under the current path passed in as an argument.
|
||||
*/
|
||||
private async list(path: string): Promise<void> {
|
||||
await this.$store.dispatch('files/list', path, {
|
||||
root: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the folder creation input and close any opened dropdowns when a user chooses to navigate back to the previous folder.
|
||||
*/
|
||||
public async back(): Promise<void> {
|
||||
await this.$store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the path under routePath.
|
||||
*/
|
||||
private async goToRoutePath(): Promise<void> {
|
||||
if (typeof this.routePath === 'string') {
|
||||
await this.$store.dispatch('files/closeDropdown');
|
||||
await this.list(this.routePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the operating system's file system for file upload.
|
||||
*/
|
||||
public async buttonFileUpload(): Promise<void> {
|
||||
this.analytics.eventTriggered(AnalyticsEvent.UPLOAD_FILE_CLICKED);
|
||||
const fileInputElement = this.$refs.fileInput as HTMLInputElement;
|
||||
fileInputElement.click();
|
||||
this.closeUploadDropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the operating system's file system for folder upload.
|
||||
*/
|
||||
public async buttonFolderUpload(): Promise<void> {
|
||||
this.analytics.eventTriggered(AnalyticsEvent.UPLOAD_FOLDER_CLICKED);
|
||||
const folderInputElement = this.$refs.folderInput as HTMLInputElement;
|
||||
folderInputElement.click();
|
||||
this.closeUploadDropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles upload options dropdown.
|
||||
*/
|
||||
public toggleUploadDropdown(): void {
|
||||
this.isUploadDropDownShown = !this.isUploadDropDownShown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes upload options dropdown.
|
||||
*/
|
||||
public closeUploadDropdown(): void {
|
||||
this.isUploadDropDownShown = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to buckets list view.
|
||||
*/
|
||||
public goToBuckets(): void {
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
|
||||
this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
|
||||
}
|
||||
/**
|
||||
* Closes upload options dropdown.
|
||||
*/
|
||||
function closeUploadDropdown(): void {
|
||||
isUploadDropDownShown.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to buckets list view.
|
||||
*/
|
||||
async function goToBuckets(): Promise<void> {
|
||||
await analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
|
||||
await router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path).catch(err => {});
|
||||
await onRouteChange();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -6,13 +6,13 @@
|
||||
<th
|
||||
class="w-50"
|
||||
scope="col"
|
||||
@mouseover="mouseOverName"
|
||||
@mouseover="mouseOver('name')"
|
||||
@mouseleave="mouseLeave"
|
||||
@click="sortByName"
|
||||
@click="sortBy('name')"
|
||||
>
|
||||
Name
|
||||
<span v-if="showNameArrow">
|
||||
<a v-if="nameDesc" class="arrow">
|
||||
<span v-if="showArrow('name')">
|
||||
<a v-if="isDesc('name')" class="arrow">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
@ -47,13 +47,13 @@
|
||||
<th
|
||||
class="file-browser-heading w-25"
|
||||
scope="col"
|
||||
@mouseover="mouseOverSize"
|
||||
@mouseover="mouseOver('size')"
|
||||
@mouseleave="mouseLeave"
|
||||
@click="sortBySize"
|
||||
@click="sortBy('size')"
|
||||
>
|
||||
Size
|
||||
<span v-if="showSizeArrow">
|
||||
<a v-if="sizeDesc" class="arrow">
|
||||
<span v-if="showArrow('size')">
|
||||
<a v-if="isDesc('size')" class="arrow">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
@ -88,13 +88,13 @@
|
||||
<th
|
||||
class="file-browser-heading"
|
||||
scope="col"
|
||||
@mouseover="mouseOverDate"
|
||||
@mouseover="mouseOver('date')"
|
||||
@mouseleave="mouseLeave"
|
||||
@click="sortByDate"
|
||||
@click="sortBy('date')"
|
||||
>
|
||||
Upload Date
|
||||
<span v-if="showDateArrow">
|
||||
<a v-if="dateDesc" class="arrow">
|
||||
<span v-if="showArrow('date')">
|
||||
<a v-if="isDesc('date')" class="arrow">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
@ -132,7 +132,7 @@
|
||||
v-if="filesToDelete"
|
||||
id="header-delete"
|
||||
class="d-flex justify-content-end"
|
||||
@click="deleteSelectedDropdown"
|
||||
@click.stop="deleteSelectedDropdown"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -152,7 +152,7 @@
|
||||
</svg>
|
||||
</a>
|
||||
<div
|
||||
v-if="displayDropdown"
|
||||
v-if="isDropdownDisplayed"
|
||||
class="dropdown-menu shadow show"
|
||||
>
|
||||
<div>
|
||||
@ -211,202 +211,93 @@
|
||||
</fragment>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
<script setup lang="ts">
|
||||
import { Fragment } from 'vue-fragment';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
Fragment,
|
||||
},
|
||||
})
|
||||
export default class FileBrowserHeader extends Vue {
|
||||
private hover = '';
|
||||
import { useStore } from '@/utils/hooks';
|
||||
|
||||
/**
|
||||
* Check if a heading is sorted in descending order.
|
||||
*/
|
||||
private isDesc(heading: string): boolean {
|
||||
return this.headingSorted === heading && this.orderBy === 'desc';
|
||||
}
|
||||
const store = useStore();
|
||||
|
||||
/**
|
||||
* Check if sorting arrow should be displayed.
|
||||
*/
|
||||
private showArrow(heading: string): boolean {
|
||||
return this.headingSorted === heading || this.hover === heading;
|
||||
}
|
||||
const hover = ref('');
|
||||
|
||||
/**
|
||||
* Retreive a string property from the store.
|
||||
*/
|
||||
private fromFilesStore(prop: string): string {
|
||||
return this.$store.state.files[prop];
|
||||
}
|
||||
function fromFilesStore (prop: string): string {
|
||||
return store.state.files[prop];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the heading of the current heading being hovered over.
|
||||
*/
|
||||
private mouseOver(heading: string): void {
|
||||
this.hover = heading;
|
||||
}
|
||||
/**
|
||||
* Check if the trashcan to delete selected files/folder should be displayed.
|
||||
*/
|
||||
const filesToDelete = computed( (): string => {
|
||||
return (!!store.state.files.selectedAnchorFile || (
|
||||
store.state.files.unselectedAnchorFile &&
|
||||
(store.state.files.selectedFiles.length > 0 ||
|
||||
store.state.files.shiftSelectedFiles.length > 0)
|
||||
));
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the heading for files/folders to be sorted by in the store.
|
||||
*/
|
||||
private sortBy(heading: string): void {
|
||||
this.$store.commit('files/sort', heading);
|
||||
}
|
||||
/**
|
||||
* Check if the files/folders deletion dropdown should be displayed.
|
||||
*/
|
||||
const isDropdownDisplayed = computed( (): boolean => {
|
||||
return store.state.files.openedDropdown === 'FileBrowser';
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the current heading being sorted from the store.
|
||||
*/
|
||||
private get headingSorted(): string {
|
||||
return this.fromFilesStore('headingSorted');
|
||||
}
|
||||
/**
|
||||
* Check if a heading is sorted in descending order.
|
||||
*/
|
||||
function isDesc(heading: string): boolean {
|
||||
return fromFilesStore('headingSorted') === heading && fromFilesStore('orderBy') === 'desc';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current order being sorted from the store.
|
||||
*/
|
||||
private get orderBy(): string {
|
||||
return this.fromFilesStore('orderBy');
|
||||
}
|
||||
/**
|
||||
* Check if sorting arrow should be displayed.
|
||||
*/
|
||||
function showArrow(heading: string): boolean {
|
||||
return fromFilesStore('headingSorted') === heading || hover.value === heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the name heading is being sorted in descending order.
|
||||
*/
|
||||
public get nameDesc(): boolean {
|
||||
return this.isDesc('name');
|
||||
}
|
||||
/**
|
||||
* Set the heading of the current heading being hovered over.
|
||||
*/
|
||||
function mouseOver(heading: string): void {
|
||||
hover.value = heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the size heading is being sorted in descending order.
|
||||
*/
|
||||
public get sizeDesc(): boolean {
|
||||
return this.isDesc('size');
|
||||
}
|
||||
/**
|
||||
* Set the heading for files/folders to be sorted by in the store.
|
||||
*/
|
||||
function sortBy(heading: string): void {
|
||||
store.commit('files/sort', heading);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the date heading is being sorted in descending order.
|
||||
*/
|
||||
public get dateDesc(): boolean {
|
||||
return this.isDesc('date');
|
||||
}
|
||||
/**
|
||||
* Change the hover property to nothing on mouse leave.
|
||||
*/
|
||||
function mouseLeave(): void {
|
||||
hover.value = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the name heading's arrow should be displayed.
|
||||
*/
|
||||
public get showNameArrow(): boolean {
|
||||
return this.showArrow('name');
|
||||
}
|
||||
/**
|
||||
* Open the deletion of files/folders dropdown.
|
||||
*/
|
||||
function deleteSelectedDropdown(): void {
|
||||
store.dispatch('files/openFileBrowserDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the size heading's arrow should be displayed.
|
||||
*/
|
||||
public get showSizeArrow(): boolean {
|
||||
return this.showArrow('size');
|
||||
}
|
||||
/**
|
||||
* Delete the selected files/folders.
|
||||
*/
|
||||
function confirmDeleteSelection(): void {
|
||||
store.dispatch('files/deleteSelected');
|
||||
store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the date heading's arrow should be displayed.
|
||||
*/
|
||||
public get showDateArrow(): boolean {
|
||||
return this.showArrow('date');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the trashcan to delete selected files/folder should be displayed.
|
||||
*/
|
||||
public get filesToDelete(): boolean {
|
||||
return (
|
||||
!!this.$store.state.files.selectedAnchorFile ||
|
||||
!!(
|
||||
this.$store.state.files.unselectedAnchorFile &&
|
||||
(this.$store.state.files.selectedFiles.length > 0 ||
|
||||
this.$store.state.files.shiftSelectedFiles.length > 0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the files/folders deletion dropdown should be displayed.
|
||||
*/
|
||||
public get displayDropdown(): boolean {
|
||||
return this.$store.state.files.openedDropdown === 'FileBrowser';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort files/folder based on their name.
|
||||
*/
|
||||
public sortByName(): void {
|
||||
this.sortBy('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort files/folder based on their size.
|
||||
*/
|
||||
public sortBySize(): void {
|
||||
this.sortBy('size');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort files/folder based on their date.
|
||||
*/
|
||||
public sortByDate(): void {
|
||||
this.sortBy('date');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the hover property to the name heading on hover.
|
||||
*/
|
||||
public mouseOverName(): void {
|
||||
this.mouseOver('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the hover property to the size heading on hover.
|
||||
*/
|
||||
public mouseOverSize(): void {
|
||||
this.mouseOver('size');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the hover property to the date heading on hover.
|
||||
*/
|
||||
public mouseOverDate(): void {
|
||||
this.mouseOver('date');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the hover property to nothing on mouse leave.
|
||||
*/
|
||||
public mouseLeave(): void {
|
||||
this.hover = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the deletion of files/folders dropdown.
|
||||
*/
|
||||
public deleteSelectedDropdown(event: Event): void {
|
||||
event.stopPropagation();
|
||||
this.$store.dispatch('files/openFileBrowserDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the selected files/folders.
|
||||
*/
|
||||
public confirmDeleteSelection(): void {
|
||||
this.$store.dispatch('files/deleteSelected');
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort files/folder selected for deletion.
|
||||
*/
|
||||
public cancelDeleteSelection(): void {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
}
|
||||
/**
|
||||
* Abort files/folder selected for deletion.
|
||||
*/
|
||||
function cancelDeleteSelection(): void {
|
||||
store.dispatch('files/closeDropdown');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
:class="{ 'selected-row': isFileSelected }"
|
||||
@click.stop="selectFile"
|
||||
>
|
||||
<td data-ls-disabled>
|
||||
<td data-ls-disabled class="px-3">
|
||||
<span v-if="fileTypeIsFolder" class="folder-name">
|
||||
<svg
|
||||
class="ml-2 mr-1"
|
||||
@ -23,16 +23,14 @@
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span>
|
||||
<router-link :to="link">
|
||||
<a
|
||||
href="javascript:null"
|
||||
class="file-name"
|
||||
aria-roledescription="folder"
|
||||
>
|
||||
{{ filename }}
|
||||
</a>
|
||||
</router-link>
|
||||
<span @click="openBucket">
|
||||
<a
|
||||
href="javascript:null"
|
||||
class="file-name"
|
||||
aria-roledescription="folder"
|
||||
>
|
||||
{{ file.Key }}
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@ -55,13 +53,11 @@
|
||||
/>
|
||||
<path d="M9.5 3V0L14 4.5h-3A1.5 1.5 0 0 1 9.5 3z" />
|
||||
</svg>
|
||||
<middle-truncate :text="filename" />
|
||||
<middle-truncate :text="file.Key" />
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="fileTypeIsFile" aria-roledescription="file-size">{{
|
||||
size
|
||||
}}</span>
|
||||
<span v-if="fileTypeIsFile" aria-roledescription="file-size">{{ size }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
@ -365,337 +361,325 @@
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
|
||||
import MiddleTruncate from './MiddleTruncate.vue';
|
||||
|
||||
import type { BrowserFile } from '@/types/browser';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { useNotify, useRouter, useStore } from '@/utils/hooks';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
MiddleTruncate,
|
||||
},
|
||||
})
|
||||
export default class FileEntry extends Vue {
|
||||
public deleteConfirmation = false;
|
||||
const store = useStore();
|
||||
const notify = useNotify();
|
||||
const router = useRouter();
|
||||
|
||||
@Prop({ default: '' })
|
||||
private readonly path: string;
|
||||
@Prop()
|
||||
private readonly file: BrowserFile;
|
||||
const props = defineProps({
|
||||
path: { type: String, default: '' },
|
||||
file: { type: Object as BrowserFile, default: undefined },
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the name of file/folder formatted.
|
||||
*/
|
||||
public get filename(): string {
|
||||
return this.file.Key;
|
||||
const emit = defineEmits(['onUpdate']);
|
||||
|
||||
const deleteConfirmation = ref(false);
|
||||
|
||||
/**
|
||||
* Return the size of the file formatted.
|
||||
*/
|
||||
const size: string = computed((): string => {
|
||||
return prettyBytes(props.file.Size);
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the upload date of the file formatted.
|
||||
*/
|
||||
const uploadDate: string = computed((): string => {
|
||||
return props.file.LastModified.toLocaleString().split(',')[0];
|
||||
});
|
||||
|
||||
/**
|
||||
* Check with the store to see if the dropdown is open for the current file/folder.
|
||||
*/
|
||||
const dropdownOpen: string = computed((): string => {
|
||||
return store.state.files.openedDropdown === props.file.Key;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a link to the current folder for navigation.
|
||||
*/
|
||||
const link: string = computed((): string => {
|
||||
const browserRoot = store.state.files.browserRoot;
|
||||
const pathAndKey = store.state.files.path + props.file.Key;
|
||||
return pathAndKey.length > 0
|
||||
? browserRoot + pathAndKey + '/'
|
||||
: browserRoot;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a flag signifying whether the current file/folder is selected.
|
||||
*/
|
||||
const isFileSelected: boolean = computed((): string => {
|
||||
return Boolean(
|
||||
store.state.files.selectedAnchorFile === props.file ||
|
||||
store.state.files.selectedFiles.find(
|
||||
(file) => file === props.file,
|
||||
) ||
|
||||
store.state.files.shiftSelectedFiles.find(
|
||||
(file) => file === props.file,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is a folder.
|
||||
*/
|
||||
const fileTypeIsFolder: boolean = computed((): string => {
|
||||
return props.file.type === 'folder';
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is a file.
|
||||
*/
|
||||
const fileTypeIsFile: boolean = computed((): string => {
|
||||
return props.file.type === 'file';
|
||||
});
|
||||
|
||||
/**
|
||||
* Open the modal for the current file.
|
||||
*/
|
||||
function openModal(): void {
|
||||
store.commit('files/setObjectPathForModal', props.path + props.file.Key);
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_OBJECT_DETAILS_MODAL_SHOWN);
|
||||
store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is in the process of being deleted, therefore a spinner shoud be shown.
|
||||
*/
|
||||
function loadingSpinner(): boolean {
|
||||
return Boolean(store.state.files.filesToBeDeleted.find(
|
||||
(file) => file === props.file,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the current file/folder whether it be a click, click + shiftKey, click + metaKey or ctrlKey, or unselect the rest.
|
||||
*/
|
||||
function selectFile(event: KeyboardEvent): void {
|
||||
if (store.state.files.openedDropdown) {
|
||||
store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the file formatted.
|
||||
*/
|
||||
public get size(): string {
|
||||
return prettyBytes(this.file.Size);
|
||||
if (event.shiftKey) {
|
||||
setShiftSelectedFiles();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the upload date of the file formatted.
|
||||
*/
|
||||
public get uploadDate(): string {
|
||||
return this.file.LastModified.toLocaleString().split(',')[0];
|
||||
}
|
||||
const isSelectedFile = Boolean(event.metaKey || event.ctrlKey);
|
||||
|
||||
/**
|
||||
* Check with the store to see if the dropdown is open for the current file/folder.
|
||||
*/
|
||||
public get dropdownOpen(): boolean {
|
||||
return this.$store.state.files.openedDropdown === this.file.Key;
|
||||
}
|
||||
setSelectedFile(isSelectedFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a link to the current folder for navigation.
|
||||
*/
|
||||
public get link(): string {
|
||||
const browserRoot = this.$store.state.files.browserRoot;
|
||||
const pathAndKey = this.$store.state.files.path + this.file.Key;
|
||||
const url =
|
||||
pathAndKey.length > 0
|
||||
? browserRoot + pathAndKey + '/'
|
||||
: browserRoot;
|
||||
return url;
|
||||
}
|
||||
async function openBucket(): Promise<void> {
|
||||
await router.push(link.value);
|
||||
emit('onUpdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is selected.
|
||||
*/
|
||||
public get isFileSelected(): boolean {
|
||||
return !!(
|
||||
this.$store.state.files.selectedAnchorFile === this.file ||
|
||||
this.$store.state.files.selectedFiles.find(
|
||||
(file) => file === this.file,
|
||||
) ||
|
||||
this.$store.state.files.shiftSelectedFiles.find(
|
||||
(file) => file === this.file,
|
||||
)
|
||||
/**
|
||||
* Set the selected file/folder in the store.
|
||||
*/
|
||||
function setSelectedFile(command: boolean): void {
|
||||
/* this function is responsible for selecting and unselecting a file on file click or [CMD + click] AKA command. */
|
||||
const shiftSelectedFiles =
|
||||
store.state.files.shiftSelectedFiles;
|
||||
const selectedFiles = store.state.files.selectedFiles;
|
||||
|
||||
const files = [
|
||||
...selectedFiles,
|
||||
...shiftSelectedFiles,
|
||||
];
|
||||
|
||||
const selectedAnchorFile =
|
||||
store.state.files.selectedAnchorFile;
|
||||
|
||||
if (command && props.file === selectedAnchorFile) {
|
||||
/* if it's [CMD + click] and the file selected is the actual selectedAnchorFile, then unselect the file but store it under unselectedAnchorFile in case the user decides to do a [shift + click] right after this action. */
|
||||
|
||||
store.commit('files/setUnselectedAnchorFile', props.file);
|
||||
store.commit('files/setSelectedAnchorFile', null);
|
||||
} else if (command && files.includes(props.file)) {
|
||||
/* if it's [CMD + click] and the file selected is a file that has already been selected in selectedFiles and shiftSelectedFiles, then unselect it by filtering it out. */
|
||||
|
||||
store.dispatch(
|
||||
'files/updateSelectedFiles',
|
||||
selectedFiles.filter(
|
||||
(fileSelected) => fileSelected !== props.file,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is a folder.
|
||||
*/
|
||||
public get fileTypeIsFolder(): boolean {
|
||||
return this.file.type === 'folder';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is a folder.
|
||||
*/
|
||||
public get fileTypeIsFile(): boolean {
|
||||
return this.file.type === 'file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the modal for the current file.
|
||||
*/
|
||||
public openModal(): void {
|
||||
this.$store.commit('files/setObjectPathForModal', this.path + this.file.Key);
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_OBJECT_DETAILS_MODAL_SHOWN);
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean signifying whether the current file/folder is in the process of being deleted, therefore a spinner shoud be shown.
|
||||
*/
|
||||
public loadingSpinner(): boolean {
|
||||
return !!this.$store.state.files.filesToBeDeleted.find(
|
||||
(file) => file === this.file,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the current file/folder whether it be a click, click + shiftKey, click + metaKey or ctrlKey, or unselect the rest.
|
||||
*/
|
||||
public selectFile(event: KeyboardEvent): void {
|
||||
if (this.$store.state.files.openedDropdown) {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
}
|
||||
|
||||
if (event.shiftKey) {
|
||||
this.setShiftSelectedFiles();
|
||||
} else if (event.metaKey || event.ctrlKey) {
|
||||
this.setSelectedFile(true);
|
||||
} else {
|
||||
this.setSelectedFile(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected file/folder in the store.
|
||||
*/
|
||||
private setSelectedFile(command: boolean): void {
|
||||
/* this function is responsible for selecting and unselecting a file on file click or [CMD + click] AKA command. */
|
||||
|
||||
const files = [
|
||||
...this.$store.state.files.selectedFiles,
|
||||
...this.$store.state.files.shiftSelectedFiles,
|
||||
];
|
||||
|
||||
const selectedAnchorFile =
|
||||
this.$store.state.files.selectedAnchorFile;
|
||||
const shiftSelectedFiles =
|
||||
this.$store.state.files.shiftSelectedFiles;
|
||||
const selectedFiles = this.$store.state.files.selectedFiles;
|
||||
|
||||
if (command && this.file === selectedAnchorFile) {
|
||||
/* if it's [CMD + click] and the file selected is the actual selectedAnchorFile, then unselect the file but store it under unselectedAnchorFile in case the user decides to do a [shift + click] right after this action. */
|
||||
|
||||
this.$store.commit('files/setUnselectedAnchorFile', this.file);
|
||||
this.$store.commit('files/setSelectedAnchorFile', null);
|
||||
} else if (command && files.includes(this.file)) {
|
||||
/* if it's [CMD + click] and the file selected is a file that has already been selected in selectedFiles and shiftSelectedFiles, then unselect it by filtering it out. */
|
||||
|
||||
this.$store.dispatch(
|
||||
'files/updateSelectedFiles',
|
||||
selectedFiles.filter(
|
||||
(fileSelected) => fileSelected !== this.file,
|
||||
),
|
||||
);
|
||||
|
||||
this.$store.dispatch(
|
||||
'files/updateShiftSelectedFiles',
|
||||
shiftSelectedFiles.filter(
|
||||
(fileSelected) => fileSelected !== this.file,
|
||||
),
|
||||
);
|
||||
} else if (command && selectedAnchorFile) {
|
||||
/* if it's [CMD + click] and there is already a selectedAnchorFile, then add the selectedAnchorFile and shiftSelectedFiles into the array of selectedFiles, set selectedAnchorFile to the file that was clicked, set unselectedAnchorFile to null, and set shiftSelectedFiles to an empty array. */
|
||||
|
||||
const filesSelected = [...selectedFiles];
|
||||
|
||||
if (!filesSelected.includes(selectedAnchorFile)) {
|
||||
filesSelected.push(selectedAnchorFile);
|
||||
}
|
||||
|
||||
this.$store.dispatch('files/updateSelectedFiles', [
|
||||
...filesSelected,
|
||||
...shiftSelectedFiles.filter(
|
||||
(file) => !filesSelected.includes(file),
|
||||
),
|
||||
]);
|
||||
|
||||
this.$store.commit('files/setSelectedAnchorFile', this.file);
|
||||
this.$store.commit('files/setUnselectedAnchorFile', null);
|
||||
this.$store.dispatch('files/updateShiftSelectedFiles', []);
|
||||
} else if (command) {
|
||||
/* if it's [CMD + click] and it has not met any of the above conditions, then set selectedAnchorFile to file and set unselectedAnchorfile to null, update the selectedFiles, and update the shiftSelectedFiles */
|
||||
|
||||
this.$store.commit('files/setSelectedAnchorFile', this.file);
|
||||
this.$store.commit('files/setUnselectedAnchorFile', null);
|
||||
|
||||
this.$store.dispatch('files/updateSelectedFiles', [
|
||||
...selectedFiles,
|
||||
...shiftSelectedFiles,
|
||||
]);
|
||||
|
||||
this.$store.dispatch('files/updateShiftSelectedFiles', []);
|
||||
} else {
|
||||
/* if it's just a file click without any modifier, then set selectedAnchorFile to the file that was clicked, set shiftSelectedFiles and selectedFiles to an empty array. */
|
||||
|
||||
this.$store.commit('files/setSelectedAnchorFile', this.file);
|
||||
this.$store.dispatch('files/updateShiftSelectedFiles', []);
|
||||
this.$store.dispatch('files/updateSelectedFiles', []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set files/folders selected using shift key in the store.
|
||||
*/
|
||||
private setShiftSelectedFiles(): void {
|
||||
/* this function is responsible for selecting all files from selectedAnchorFile to the file that was selected with [shift + click] */
|
||||
|
||||
const files = this.$store.getters['files/sortedFiles'];
|
||||
const unselectedAnchorFile =
|
||||
this.$store.state.files.unselectedAnchorFile;
|
||||
|
||||
if (unselectedAnchorFile) {
|
||||
/* if there is an unselectedAnchorFile, meaning that in the previous action the user unselected the anchor file but is now chosing to do a [shift + click] on another file, then reset the selectedAnchorFile, the achor file, to unselectedAnchorFile. */
|
||||
|
||||
this.$store.commit(
|
||||
'files/setSelectedAnchorFile',
|
||||
unselectedAnchorFile,
|
||||
);
|
||||
this.$store.commit('files/setUnselectedAnchorFile', null);
|
||||
}
|
||||
|
||||
const selectedAnchorFile =
|
||||
this.$store.state.files.selectedAnchorFile;
|
||||
|
||||
if (!selectedAnchorFile) {
|
||||
this.$store.commit('files/setSelectedAnchorFile', this.file);
|
||||
return;
|
||||
}
|
||||
|
||||
const anchorIdx = files.findIndex(
|
||||
(file) => file === selectedAnchorFile,
|
||||
);
|
||||
const shiftIdx = files.findIndex((file) => file === this.file);
|
||||
|
||||
const start = Math.min(anchorIdx, shiftIdx);
|
||||
const end = Math.max(anchorIdx, shiftIdx) + 1;
|
||||
|
||||
this.$store.dispatch(
|
||||
store.dispatch(
|
||||
'files/updateShiftSelectedFiles',
|
||||
files
|
||||
.slice(start, end)
|
||||
.filter(
|
||||
(file) =>
|
||||
!this.$store.state.files.selectedFiles.includes(
|
||||
file,
|
||||
) && file !== selectedAnchorFile,
|
||||
),
|
||||
shiftSelectedFiles.filter(
|
||||
(fileSelected) => fileSelected !== props.file,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if (command && selectedAnchorFile) {
|
||||
/* if it's [CMD + click] and there is already a selectedAnchorFile, then add the selectedAnchorFile and shiftSelectedFiles into the array of selectedFiles, set selectedAnchorFile to the file that was clicked, set unselectedAnchorFile to null, and set shiftSelectedFiles to an empty array. */
|
||||
|
||||
/**
|
||||
* Open the share modal for the current file.
|
||||
*/
|
||||
public share(): void {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
this.$store.commit('files/setObjectPathForModal', this.path + this.file.Key);
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_SHARE_OBJECT_MODAL_SHOWN);
|
||||
}
|
||||
const filesSelected = [...selectedFiles];
|
||||
|
||||
/**
|
||||
* Toggle the dropdown for the current file/folder.
|
||||
*/
|
||||
public toggleDropdown(): void {
|
||||
if (this.$store.state.files.openedDropdown === this.file.Key) {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
} else {
|
||||
this.$store.dispatch('files/openDropdown', this.file.Key);
|
||||
if (!filesSelected.includes(selectedAnchorFile)) {
|
||||
filesSelected.push(selectedAnchorFile);
|
||||
}
|
||||
|
||||
// remove the dropdown delete confirmation
|
||||
this.deleteConfirmation = false;
|
||||
store.dispatch('files/updateSelectedFiles', [
|
||||
...filesSelected,
|
||||
...shiftSelectedFiles.filter(
|
||||
(file) => !filesSelected.includes(file),
|
||||
),
|
||||
]);
|
||||
|
||||
store.commit('files/setSelectedAnchorFile', props.file);
|
||||
store.commit('files/setUnselectedAnchorFile', null);
|
||||
store.dispatch('files/updateShiftSelectedFiles', []);
|
||||
} else if (command) {
|
||||
/* if it's [CMD + click] and it has not met any of the above conditions, then set selectedAnchorFile to file and set unselectedAnchorfile to null, update the selectedFiles, and update the shiftSelectedFiles */
|
||||
|
||||
store.commit('files/setSelectedAnchorFile', props.file);
|
||||
store.commit('files/setUnselectedAnchorFile', null);
|
||||
|
||||
store.dispatch('files/updateSelectedFiles', [
|
||||
...selectedFiles,
|
||||
...shiftSelectedFiles,
|
||||
]);
|
||||
|
||||
store.dispatch('files/updateShiftSelectedFiles', []);
|
||||
} else {
|
||||
/* if it's just a file click without any modifier, then set selectedAnchorFile to the file that was clicked, set shiftSelectedFiles and selectedFiles to an empty array. */
|
||||
|
||||
store.commit('files/setSelectedAnchorFile', props.file);
|
||||
store.dispatch('files/updateShiftSelectedFiles', []);
|
||||
store.dispatch('files/updateSelectedFiles', []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set files/folders selected using shift key in the store.
|
||||
*/
|
||||
function setShiftSelectedFiles(): void {
|
||||
/* this function is responsible for selecting all files from selectedAnchorFile to the file that was selected with [shift + click] */
|
||||
|
||||
const files = store.getters['files/sortedFiles'];
|
||||
const unselectedAnchorFile =
|
||||
store.state.files.unselectedAnchorFile;
|
||||
|
||||
if (unselectedAnchorFile) {
|
||||
/* if there is an unselectedAnchorFile, meaning that in the previous action the user unselected the anchor file but is now chosing to do a [shift + click] on another file, then reset the selectedAnchorFile, the achor file, to unselectedAnchorFile. */
|
||||
store.commit(
|
||||
'files/setSelectedAnchorFile',
|
||||
unselectedAnchorFile,
|
||||
);
|
||||
|
||||
store.commit('files/setUnselectedAnchorFile', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the current file.
|
||||
*/
|
||||
public download(): void {
|
||||
try {
|
||||
this.$store.dispatch('files/download', this.file);
|
||||
this.$notify.warning('Do not share download link with other people. If you want to share this data better use "Share" option.');
|
||||
} catch (error) {
|
||||
this.$notify.error('Can not download your file');
|
||||
}
|
||||
const selectedAnchorFile = store.state.files.selectedAnchorFile;
|
||||
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
this.deleteConfirmation = false;
|
||||
if (!selectedAnchorFile) {
|
||||
store.commit('files/setSelectedAnchorFile', props.file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data property deleteConfirmation to true, signifying that this user does in fact want the current selected file/folder.
|
||||
*/
|
||||
public confirmDeletion(): void {
|
||||
this.deleteConfirmation = true;
|
||||
const anchorIdx = files.findIndex(
|
||||
(file) => file === selectedAnchorFile,
|
||||
);
|
||||
const shiftIdx = files.findIndex((file) => file === props.file);
|
||||
|
||||
const start = Math.min(anchorIdx, shiftIdx);
|
||||
const end = Math.max(anchorIdx, shiftIdx) + 1;
|
||||
|
||||
store.dispatch(
|
||||
'files/updateShiftSelectedFiles',
|
||||
files
|
||||
.slice(start, end)
|
||||
.filter(
|
||||
(file) =>
|
||||
!store.state.files.selectedFiles.includes(
|
||||
file,
|
||||
) && file !== selectedAnchorFile,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the share modal for the current file.
|
||||
*/
|
||||
function share(): void {
|
||||
store.dispatch('files/closeDropdown');
|
||||
store.commit('files/setObjectPathForModal', this.path + this.file.Key);
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_SHARE_OBJECT_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the dropdown for the current file/folder.
|
||||
*/
|
||||
function toggleDropdown(): void {
|
||||
(store.state.files.openedDropdown === props.file.Key) ?
|
||||
store.dispatch('files/closeDropdown')
|
||||
: store.dispatch('files/openDropdown', props.file.Key);
|
||||
|
||||
// remove the dropdown delete confirmation
|
||||
deleteConfirmation.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the current file.
|
||||
*/
|
||||
function download(): void {
|
||||
try {
|
||||
store.dispatch('files/download', props.file);
|
||||
notify.warning('Do not share download link with other people. If you want to share this data better use "Share" option.');
|
||||
} catch (error) {
|
||||
notify.error('Can not download your file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the selected file/folder.
|
||||
*/
|
||||
public async finalDelete(): Promise<void> {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
this.$store.dispatch('files/addFileToBeDeleted', this.file);
|
||||
store.dispatch('files/closeDropdown');
|
||||
deleteConfirmation.value = false;
|
||||
}
|
||||
|
||||
const params = {
|
||||
path: this.path,
|
||||
file: this.file,
|
||||
};
|
||||
/**
|
||||
* Set the data property deleteConfirmation to true, signifying that this user does in fact want the current selected file/folder.
|
||||
*/
|
||||
function confirmDeletion(): void {
|
||||
deleteConfirmation.value = true;
|
||||
}
|
||||
|
||||
if (this.file.type === 'file') {
|
||||
await this.$store.dispatch('files/delete', params);
|
||||
} else {
|
||||
this.$store.dispatch('files/deleteFolder', params);
|
||||
}
|
||||
/**
|
||||
* Delete the selected file/folder.
|
||||
*/
|
||||
async function finalDelete(): Promise<void> {
|
||||
store.dispatch('files/closeDropdown');
|
||||
store.dispatch('files/addFileToBeDeleted', props.file);
|
||||
|
||||
// refresh the files displayed
|
||||
await this.$store.dispatch('files/list');
|
||||
this.$store.dispatch('files/removeFileFromToBeDeleted', this.file);
|
||||
this.deleteConfirmation = false;
|
||||
}
|
||||
const params = { ...props };
|
||||
|
||||
/**
|
||||
* Abort the deletion of the current file/folder.
|
||||
*/
|
||||
public cancelDeletion(): void {
|
||||
this.$store.dispatch('files/closeDropdown');
|
||||
this.deleteConfirmation = false;
|
||||
}
|
||||
(props.file.type === 'file') ? await store.dispatch('files/delete', params) : store.dispatch('files/deleteFolder', params);
|
||||
|
||||
// refresh the files displayed
|
||||
await store.dispatch('files/list');
|
||||
store.dispatch('files/removeFileFromToBeDeleted', props.file);
|
||||
deleteConfirmation.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort the deletion of the current file/folder.
|
||||
*/
|
||||
function cancelDeletion(): void {
|
||||
store.dispatch('files/closeDropdown');
|
||||
deleteConfirmation.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -26,35 +26,19 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
<script setup lang="ts">
|
||||
import { OnPageClickCallback } from '@/types/pagination';
|
||||
|
||||
import TablePagination from '@/components/common/TablePagination.vue';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
TablePagination,
|
||||
},
|
||||
})
|
||||
export default class VTable extends Vue {
|
||||
@Prop({ default: false })
|
||||
public readonly selectable: boolean;
|
||||
@Prop({ default: 0 })
|
||||
private readonly totalPageCount: number;
|
||||
@Prop({ default: 'items' })
|
||||
private readonly itemsLabel: string;
|
||||
@Prop({ default: 0 })
|
||||
private readonly limit: number;
|
||||
@Prop({ default: () => [] })
|
||||
private readonly items: object[];
|
||||
@Prop({ default: 0 })
|
||||
private readonly totalItemsCount: number;
|
||||
@Prop({ default: () => () => new Promise(() => false) })
|
||||
private readonly onPageClickCallback: OnPageClickCallback;
|
||||
}
|
||||
const props = defineProps({
|
||||
selectable: { type: Boolean, default: false },
|
||||
totalPageCount: { type: Number, default: 0 },
|
||||
itemsLabel: { type: String, default: 'items' },
|
||||
limit: { type: Number, default: 0 },
|
||||
totalItemsCount: { type: Number, default: 0 },
|
||||
onPageClickCallback: { type: Function as OnPageClickCallback, default: () => () => new Promise(() => false) },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -21,66 +21,62 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { useRoute, useRouter, useStore } from '@/utils/hooks';
|
||||
|
||||
import ArrowDownIcon from '@/../static/images/objects/arrowDown.svg';
|
||||
import DetailsIcon from '@/../static/images/objects/details.svg';
|
||||
import ShareIcon from '@/../static/images/objects/share.svg';
|
||||
import GearIcon from '@/../static/images/common/gearIcon.svg';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
ArrowDownIcon,
|
||||
GearIcon,
|
||||
DetailsIcon,
|
||||
ShareIcon,
|
||||
},
|
||||
})
|
||||
export default class BucketSettingsNav extends Vue {
|
||||
@Prop({ default: '' })
|
||||
public readonly bucketName: string;
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
|
||||
public isDropdownOpen = false;
|
||||
const props = defineProps({
|
||||
bucketName: { type: String, default: '' },
|
||||
});
|
||||
|
||||
public closeDropdown(): void {
|
||||
if (!this.isDropdownOpen) return;
|
||||
const isDropdownOpen = ref(false);
|
||||
|
||||
this.isDropdownOpen = false;
|
||||
}
|
||||
/**
|
||||
* Returns files amount from store.
|
||||
*/
|
||||
const filesCount: number = computed((): number => {
|
||||
return store.getters['files/sortedFiles'].length;
|
||||
});
|
||||
|
||||
/**
|
||||
* Redirects to bucket details page.
|
||||
*/
|
||||
public onDetailsClick(): void {
|
||||
this.$router.push({
|
||||
name: RouteConfig.BucketsDetails.name,
|
||||
params: {
|
||||
bucketName: this.bucketName,
|
||||
backRoute: this.$route.name ? this.$route.name : '',
|
||||
},
|
||||
});
|
||||
this.isDropdownOpen = false;
|
||||
}
|
||||
function closeDropdown(): void {
|
||||
if (!isDropdownOpen) return;
|
||||
|
||||
/**
|
||||
* Toggles share bucket modal.
|
||||
*/
|
||||
public onShareBucketClick(): void {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_SHARE_BUCKET_MODAL_SHOWN);
|
||||
this.isDropdownOpen = false;
|
||||
}
|
||||
isDropdownOpen.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns files amount from store.
|
||||
*/
|
||||
public get filesCount(): number {
|
||||
return this.$store.getters['files/sortedFiles'].length;
|
||||
}
|
||||
/**
|
||||
* Redirects to bucket details page.
|
||||
*/
|
||||
function onDetailsClick(): void {
|
||||
router.push({
|
||||
name: RouteConfig.BucketsDetails.name,
|
||||
params: {
|
||||
bucketName: props.bucketName,
|
||||
backRoute: route.name || '',
|
||||
},
|
||||
});
|
||||
|
||||
isDropdownOpen.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles share bucket modal.
|
||||
*/
|
||||
function onShareBucketClick(): void {
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_SHARE_BUCKET_MODAL_SHOWN);
|
||||
isDropdownOpen.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
class="buckets-view__list"
|
||||
:limit="bucketsPage.limit"
|
||||
:total-page-count="bucketsPage.pageCount"
|
||||
:items="bucketsPage.buckets"
|
||||
items-label="buckets"
|
||||
:on-page-click-callback="fetchBuckets"
|
||||
:total-items-count="bucketsPage.totalCount"
|
||||
|
@ -24,7 +24,6 @@
|
||||
class="projects-list-items"
|
||||
:limit="projectsPage.limit"
|
||||
:total-page-count="projectsPage.pageCount"
|
||||
:items="projectsPage.projects"
|
||||
items-label="projects"
|
||||
:on-page-click-callback="onPageClick"
|
||||
:total-items-count="projectsPage.totalCount"
|
||||
|
@ -24,7 +24,6 @@
|
||||
:selectable="true"
|
||||
:limit="projectMemberLimit"
|
||||
:total-page-count="totalPageCount"
|
||||
:items="projectMembers"
|
||||
:total-items-count="projectMembersTotalCount"
|
||||
:on-page-click-callback="onPageClick"
|
||||
>
|
||||
|
21
web/satellite/src/utils/hooks.ts
Normal file
21
web/satellite/src/utils/hooks.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { getCurrentInstance } from 'vue';
|
||||
|
||||
// TODO: remove after updating router and store deps.
|
||||
export function useRoute() {
|
||||
return getCurrentInstance()?.proxy.$route;
|
||||
}
|
||||
|
||||
export function useRouter() {
|
||||
return getCurrentInstance()?.proxy.$router;
|
||||
}
|
||||
|
||||
export function useStore() {
|
||||
return getCurrentInstance()?.proxy.$store;
|
||||
}
|
||||
|
||||
export function useNotify() {
|
||||
return getCurrentInstance()?.proxy.$notify;
|
||||
}
|
@ -21,7 +21,7 @@ exports[`ProjectMembersArea.vue renders correctly 1`] = `
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<v-table-stub selectable="true" totalpagecount="1" itemslabel="project members" limit="6" items="[object Object]" totalitemscount="1" onpageclickcallback="[Function]" class="team-area__table"></v-table-stub>
|
||||
<v-table-stub items-label="project members" selectable="true" limit="6" total-page-count="1" total-items-count="1" on-page-click-callback="function () { [native code] }" class="team-area__table"></v-table-stub>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -32,6 +32,6 @@ exports[`ProjectMembersArea.vue team area renders correctly 1`] = `
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<v-table-stub selectable="true" totalpagecount="1" itemslabel="project members" limit="6" items="[object Object]" totalitemscount="1" onpageclickcallback="[Function]" class="team-area__table"></v-table-stub>
|
||||
<v-table-stub items-label="project members" selectable="true" limit="6" total-page-count="1" total-items-count="1" on-page-click-callback="function () { [native code] }" class="team-area__table"></v-table-stub>
|
||||
</div>
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user