Skip to content

Commit

Permalink
More refactoring for the file details page components
Browse files Browse the repository at this point in the history
use models to to pass current and latest versionId's
extend action to fetchMetadata/tags for all versions in one shot
  • Loading branch information
TimCsaky committed Feb 29, 2024
1 parent f165231 commit b779006
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 201 deletions.
13 changes: 2 additions & 11 deletions frontend/src/components/object/ObjectAccess.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { onMounted, ref, watch } from 'vue';
import { onMounted, ref } from 'vue';
import { usePermissionStore, useUserStore } from '@/store';
import { Permissions } from '@/utils/constants';
Expand All @@ -25,8 +25,7 @@ const { getUsers } = storeToRefs(userStore);
// State
const managedBy: Ref<string | undefined> = ref();
// Actions
async function load() {
onMounted(async () => {
await permissionStore.fetchObjectPermissions({ objectId: props.objectId });
const uniqueIds = [
Expand All @@ -44,14 +43,6 @@ async function load() {
.map((x: User) => x.fullName)
.join(', ');
}
}
onMounted(() => {
load();
});
watch(props, () => {
load();
});
</script>

Expand Down
145 changes: 64 additions & 81 deletions frontend/src/components/object/ObjectFileDetails.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { computed, onBeforeMount, ref, watch } from 'vue';
import { computed, onMounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import {
Expand Down Expand Up @@ -29,16 +29,15 @@ import { Permissions, RouteNames } from '@/utils/constants';
import { ButtonMode } from '@/utils/enums';
import type { Ref } from 'vue';
import type { COMSObject } from '@/types';
// Props
type Props = {
objectId: string;
versionId?: string;
versionId: string;
};
const props = withDefaults(defineProps<Props>(), {
versionId: undefined
});
const props = withDefaults(defineProps<Props>(), {});
const router = useRouter();
Expand All @@ -55,70 +54,58 @@ const { getObject } = storeToRefs(objectStore);
const { getVersionsByObjectId, getLatestVersionIdByObjectId } = storeToRefs(versionStore);
// State
const obj = computed((): any => getObject.value(props.objectId));
const object: Ref<COMSObject | undefined> = ref(undefined);
const bucketId: Ref<string> = ref('');
const currentVersionId: Ref<string | undefined> = ref(props.versionId);
const latestVersionId = computed(() => getLatestVersionIdByObjectId.value(props.objectId));
const versionId = computed(() => props.versionId ?? latestVersionId.value);
const permissionsVisible: Ref<boolean> = ref(false);
function onDeletedSuccess() {
router.push({
name: RouteNames.DETAIL_OBJECTS,
query: {
objectId: props.objectId,
versionId: latestVersionId.value
}
});
}
function onFileUploaded(newVersionId: string) {
// Navigate to new version
router.push({
name: RouteNames.DETAIL_OBJECTS,
query: {
objectId: props.objectId,
versionId: newVersionId
}
async function onVersionsChanged() {
await Promise.all([
versionStore.fetchVersions({ objectId: props.objectId }),
metadataStore.fetchMetadata({ objectId: props.objectId }),
tagStore.fetchTagging({ objectId: props.objectId })
]).then(async () => {
currentVersionId.value = latestVersionId.value;
currentVersionId === latestVersionId;
await Promise.all([
versionStore.fetchMetadata({ objectId: props.objectId }),
versionStore.fetchTagging({ objectId: props.objectId })
]);
});
}
onBeforeMount(async () => {
onMounted(async () => {
const head = await objectStore.headObject(props.objectId);
const isPublic = head?.status === 204;
await permissionStore.fetchBucketPermissions({ userId: getUserId.value, objectPerms: true });
await objectStore.fetchObjects({ objectId: props.objectId, userId: getUserId.value, bucketPerms: true });
object.value = getObject.value(props.objectId);
const bucketId = object.value?.bucketId;
if (
!isPublic &&
(!obj.value ||
!permissionStore.isObjectActionAllowed(obj.value.id, getUserId.value, Permissions.READ, obj.value.bucketId))
(!object.value ||
!permissionStore.isObjectActionAllowed(object.value.id, getUserId.value, Permissions.READ, object.value.bucketId))
) {
router.replace({ name: RouteNames.FORBIDDEN });
}
// fetch data for child components
await bucketStore.fetchBuckets({ bucketId: obj.value.bucketId });
await versionStore.fetchVersions({ objectId: props.objectId });
await metadataStore.fetchMetadata({ objectId: props.objectId });
await tagStore.fetchTagging({ objectId: props.objectId });
if (props.versionId) {
await versionStore.fetchTagging({ versionId: props.versionId });
await versionStore.fetchMetadata({ versionId: props.versionId });
}
});
// refresh data from COMS
watch([props], async () => {
await versionStore.fetchVersions({ objectId: props.objectId });
await metadataStore.fetchMetadata({ objectId: props.objectId });
await tagStore.fetchTagging({ objectId: props.objectId });
if (props.versionId) {
await versionStore.fetchTagging({ versionId: props.versionId });
await versionStore.fetchMetadata({ versionId: props.versionId });
}
await Promise.all([
bucketStore.fetchBuckets({ bucketId: bucketId }),
versionStore.fetchVersions({ objectId: props.objectId }),
metadataStore.fetchMetadata({ objectId: props.objectId }),
tagStore.fetchTagging({ objectId: props.objectId }),
versionStore.fetchTagging({ objectId: props.objectId }),
versionStore.fetchMetadata({ objectId: props.objectId })
]);
});
</script>

<template>
<div v-if="obj">
<div v-if="object">
<div class="grid grid-nogutter">
<div class="col-12">
<h1 class="heading">File details</h1>
Expand All @@ -130,23 +117,22 @@ watch([props], async () => {
class="text-3xl pr-3"
/>
<h2 class="">
{{ obj.name }}
{{ object.name }}
</h2>
</div>

<div class="action-buttons">
<ShareObjectButton :id="props.objectId" />
<ShareObjectButton :id="object.id" />
<DownloadObjectButton
v-if="
obj.public ||
permissionStore.isObjectActionAllowed(props.objectId, getUserId, Permissions.READ, obj.bucketId)
object.public || permissionStore.isObjectActionAllowed(object.id, getUserId, Permissions.READ, bucketId)
"
:mode="ButtonMode.ICON"
:ids="[props.objectId]"
:version-id="props.versionId"
:ids="[object.id]"
:version-id="currentVersionId"
/>
<Button
v-if="permissionStore.isObjectActionAllowed(props.objectId, getUserId, Permissions.MANAGE, obj.bucketId)"
v-if="permissionStore.isObjectActionAllowed(object.id, getUserId, Permissions.MANAGE, bucketId)"
v-tooltip.bottom="'Object permissions'"
class="p-button-lg p-button-text"
aria-label="Object permissions"
Expand All @@ -155,12 +141,12 @@ watch([props], async () => {
<font-awesome-icon icon="fa-solid fa-users" />
</Button>
<DeleteObjectButton
v-if="permissionStore.isObjectActionAllowed(props.objectId, getUserId, Permissions.DELETE, obj.bucketId)"
v-if="permissionStore.isObjectActionAllowed(object.id, getUserId, Permissions.DELETE, bucketId)"
:mode="ButtonMode.ICON"
:ids="[props.objectId]"
:version-id="props.versionId"
:disabled="getVersionsByObjectId(props.objectId).length === 1"
@on-deleted-success="onDeletedSuccess"
:ids="[object.id]"
:version-id="currentVersionId"
:disabled="getVersionsByObjectId(object.id).length === 1"
@on-deleted-success="onVersionsChanged"
/>
</div>
</div>
Expand All @@ -169,50 +155,47 @@ watch([props], async () => {
<div class="flex flex-row">
<div class="flex flex-column w-6 gap-3 py-5">
<ObjectProperties
:object-id="props.objectId"
:version-id="versionId"
:object-id="object.id"
:full-view="true"
/>
<ObjectAccess :object-id="props.objectId" />
<ObjectAccess :object-id="object.id" />
<ObjectMetadata
:editable="props.versionId === latestVersionId"
:object-id="props.objectId"
:version-id="versionId"
@on-file-uploaded="onFileUploaded"
v-model:version-id="currentVersionId"
:editable="currentVersionId === latestVersionId"
:object-id="object.id"
@on-metadata-success="onVersionsChanged"
/>
</div>
<Divider layout="vertical" />
<div class="flex flex-column w-6 gap-4 xl:pl-3 py-5">
<div class="flex flex-row-reverse">
<ObjectUploadBasic
v-if="permissionStore.isObjectActionAllowed(props.objectId, getUserId, Permissions.UPDATE, obj.bucketId)"
:bucket-id="obj.bucketId"
:object-id="props.objectId"
@on-file-uploaded="onFileUploaded"
v-if="permissionStore.isObjectActionAllowed(object.id, getUserId, Permissions.UPDATE, object.bucketId)"
:bucket-id="bucketId"
:object-id="object.id"
@on-file-uploaded="onVersionsChanged"
/>
</div>
<ObjectVersion
:bucket-id="obj?.bucketId"
:object-id="props.objectId"
:version-id="versionId"
v-model:version-id="currentVersionId"
:bucket-id="bucketId"
:object-id="object.id"
@on-deleted-success="onVersionsChanged"
/>
<ObjectTag
:object-id="props.objectId"
:version-id="versionId"
@on-file-uploaded="onFileUploaded"
:object-id="object.id"
v-model:version-id="currentVersionId"
/>
</div>
</div>
</div>

<!-- eslint-disable vue/no-v-model-argument -->
<Dialog
v-model:visible="permissionsVisible"
:draggable="false"
:modal="true"
class="bcbox-info-dialog"
>
<!-- eslint-enable vue/no-v-model-argument -->
<template #header>
<font-awesome-icon
icon="fas fa-users"
Expand All @@ -222,10 +205,10 @@ watch([props], async () => {
</template>

<h3 class="bcbox-info-dialog-subhead">
{{ obj?.name }}
{{ object?.name }}
</h3>

<ObjectPermission :object-id="props.objectId" />
<ObjectPermission :object-id="object?.id" />
</Dialog>
</template>

Expand Down
23 changes: 8 additions & 15 deletions frontend/src/components/object/ObjectMetadata.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,19 @@ import { Permissions } from '@/utils/constants';
import type { Ref } from 'vue';
import type { ObjectMetadataTagFormType } from '@/components/object/ObjectMetadataTagForm.vue';
import type { Metadata } from '@/types';
// Props
type Props = {
editable?: boolean;
objectId: string;
versionId?: string;
};
const props = withDefaults(defineProps<Props>(), {
editable: true,
versionId: undefined
editable: true
});
// Emits
const emit = defineEmits(['on-file-uploaded']);
const emit = defineEmits(['on-metadata-success']);
// Store
const metadataStore = useMetadataStore();
Expand All @@ -38,9 +35,7 @@ const { getMetadataByObjectId } = storeToRefs(metadataStore);
// State
const obj = computed(() => objectStore.getObject(props.objectId));
const objectMetadata: Ref<Metadata | undefined> = computed(() =>
props.versionId ? getMetadataByVersionId.value(props.versionId) : getMetadataByObjectId.value(props.objectId)
);
const versionId = defineModel<string>('versionId');
const editing: Ref<boolean> = ref(false);
const formData: Ref<ObjectMetadataTagFormType> = ref({
filename: ''
Expand All @@ -61,15 +56,15 @@ const confirmUpdate = (values: ObjectMetadataTagFormType) => {
const showModal = () => {
formData.value.filename = obj.value?.name ?? '';
formData.value.metadata = objectMetadata.value?.metadata;
formData.value.metadata = (
versionId.value ? getMetadataByVersionId.value(versionId.value) : getMetadataByObjectId.value(props.objectId)
)?.metadata;
editing.value = true;
};
const submitModal = async (values: ObjectMetadataTagFormType) => {
await metadataStore.replaceMetadata(props.objectId, values.metadata ?? [], props.versionId);
emit('on-file-uploaded');
await metadataStore.replaceMetadata(props.objectId, values.metadata ?? [], versionId.value);
closeModal();
};
Expand All @@ -84,7 +79,7 @@ const closeModal = () => {
<h2>Metadata</h2>
</div>
<GridRow
v-for="meta in objectMetadata?.metadata"
v-for="meta in (versionId ? getMetadataByVersionId(versionId) : getMetadataByObjectId(props.objectId))?.metadata"
:key="meta.key + meta.value"
:label="meta.key"
:value="meta.value"
Expand All @@ -107,14 +102,12 @@ const closeModal = () => {
</Button>
</div>

<!-- eslint-disable vue/no-v-model-argument -->
<Dialog
v-model:visible="editing"
:draggable="false"
:modal="true"
class="bcbox-info-dialog"
>
<!-- eslint-enable vue/no-v-model-argument -->
<template #header>
<font-awesome-icon
icon="fa-solid fa-pen-to-square"
Expand Down
Loading

0 comments on commit b779006

Please sign in to comment.