Skip to content
Snippets Groups Projects
Verified Commit 6055aa6c authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Improve UI for making a bucket public

parent f644a949
No related branches found
No related tags found
1 merge request!108Resolve "Add checkbox for public buckets"
Pipeline #51008 passed
......@@ -5,8 +5,8 @@ import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import PermissionModal from "@/components/object-storage/modals/PermissionModal.vue";
import BucketDetailModal from "@/components/object-storage/modals/BucketDetailModal.vue";
import dayjs from "dayjs";
import { computed, onMounted, ref } from "vue";
import { Tooltip } from "bootstrap";
import { computed, onMounted, reactive, ref } from "vue";
import { Toast, Tooltip } from "bootstrap";
import { useBucketStore } from "@/stores/buckets";
import { useRouter } from "vue-router";
import { useAuthStore } from "@/stores/users";
......@@ -15,6 +15,7 @@ import { useNameStore } from "@/stores/names";
import { environment } from "@/environment";
import { useS3ObjectStore } from "@/stores/s3objects";
import { filesize } from "filesize";
import BootstrapToast from "@/components/BootstrapToast.vue";
const props = defineProps<{
active: boolean;
......@@ -32,6 +33,17 @@ const bucketRepository = useBucketStore();
const objectRepository = useS3ObjectStore();
const router = useRouter();
let successToast: Toast | null;
let errorToast: Toast | null;
const requestState = reactive<{
error: string;
loading: boolean;
}>({
error: "",
loading: false,
});
const permission = computed<BucketPermissionOut | undefined>(
() => permissionRepository.ownPermissions[props.bucket.name],
);
......@@ -56,12 +68,21 @@ function permissionDeleted() {
}
function toggleBucketPublicState() {
requestState.loading = true;
bucketRepository
.togglePublicState(props.bucket.name, !props.bucket.public)
.catch(() => {
.then(() => {
successToast?.show();
})
.catch((err) => {
requestState.error = err.toString();
if (publicCheckbox.value) {
publicCheckbox.value.checked = props.bucket.public;
}
errorToast?.show();
})
.finally(() => {
requestState.loading = false;
});
}
......@@ -70,11 +91,28 @@ onMounted(() => {
new Tooltip("#tooltip-" + randomIDSuffix);
new Tooltip("#ownBucketIcon-" + randomIDSuffix);
new Tooltip("#sharedBucketIcon-" + randomIDSuffix);
successToast = new Toast("#success-public-bucket-" + randomIDSuffix);
errorToast = new Toast("#error-public-bucket-" + randomIDSuffix);
}
});
</script>
<template>
<bootstrap-toast
:toast-id="'success-public-bucket-' + randomIDSuffix"
v-if="!loading"
>
Bucket {{ bucket.name }} is now {{ bucket.public ? "public" : "private" }}
</bootstrap-toast>
<bootstrap-toast
:toast-id="'error-public-bucket-' + randomIDSuffix"
color-class="danger"
v-if="!loading"
>
Error making the bucket {{ bucket.name }}
{{ !bucket.public ? "public" : "private" }}:<br />
{{ requestState.error }}
</bootstrap-toast>
<permission-modal
v-if="permission != undefined && props.active"
:modalId="'view-permission-modal' + randomIDSuffix"
......@@ -236,30 +274,35 @@ onMounted(() => {
</tr>
<tr v-if="bucket.owner_constraint == undefined">
<th scope="row">
<label
:for="'public-checkbox-' + randomIDSuffix"
class="fw-bold"
>
Public</label
<div
:class="{ 'form-check': !loading && permission == undefined }"
>
<input
v-if="!loading && permission == undefined"
ref="publicCheckbox"
class="form-check-input"
type="checkbox"
:disabled="requestState.loading"
:checked="bucket.public"
:id="'public-checkbox-' + randomIDSuffix"
@change="toggleBucketPublicState"
/>
<label
:for="'public-checkbox-' + randomIDSuffix"
class="fw-bold"
>
Public</label
>
</div>
</th>
<td>
<input
ref="publicCheckbox"
class="form-check-input"
:disabled="loading || permission != undefined"
type="checkbox"
:checked="bucket.public"
:id="'public-checkbox-' + randomIDSuffix"
@change="toggleBucketPublicState"
/>
<a
class="ms-4"
v-if="bucket.public"
target="_blank"
:href="environment.S3_URL + '/' + bucket.name"
>Show</a
>Link</a
>
<span v-else>Disabled</span>
</td>
</tr>
</tbody>
......
......@@ -34,11 +34,11 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
<template #body>
<h5>Resource</h5>
<div class="mb-3 row">
<div class="col-8">
<div class="col-7">
<label
for="resource-version-info-modal-resource-id"
class="form-label"
>ID</label
>Resource ID</label
>
<div class="input-group">
<input
......@@ -54,7 +54,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
/></span>
</div>
</div>
<div class="col-4">
<div class="col-5">
<label
for="resource-version-info-modal-resource-name"
class="form-label"
......@@ -72,7 +72,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
</div>
</div>
<div class="mb-3 row">
<div class="col-8">
<div class="col-7">
<label
for="resource-version-info-modal-maintainer-id"
class="form-label"
......@@ -92,7 +92,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
/></span>
</div>
</div>
<div class="col-4">
<div class="col-5">
<label
for="resource-version-info-modal-maintainer-name"
class="form-label"
......@@ -143,7 +143,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
</div>
<h5>Resource Version</h5>
<div class="mb-3 row">
<div class="col-8">
<div class="col-7">
<label
for="resource-version-info-modal-resource-version-id"
class="form-label"
......@@ -163,7 +163,7 @@ const resourceVersion = computed<ResourceVersionOut | undefined>(
/></span>
</div>
</div>
<div class="col-4">
<div class="col-5">
<label
for="resource-version-info-modal-resource-version-release"
class="form-label"
......
......@@ -2,7 +2,7 @@
import type { WorkflowOut, WorkflowVersion } from "@/client/workflow";
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import dayjs from "dayjs";
import { onMounted, ref, computed } from "vue";
import { onMounted, computed } from "vue";
import { Tooltip } from "bootstrap";
import { latestVersion as calculateLatestVersion } from "@/utils/Workflow";
......@@ -12,7 +12,6 @@ const props = defineProps<{
}>();
const randomIDSuffix: string = Math.random().toString(16).substring(2, 8);
const truncateDescription = ref<boolean>(true);
const latestVersion = computed<WorkflowVersion | undefined>(() =>
calculateLatestVersion(props.workflow.versions),
);
......@@ -55,18 +54,11 @@ onMounted(() => {
class="img-fluid float-end icon"
/>
</div>
<p class="card-text" :class="{ 'text-truncate': truncateDescription }">
<p class="card-text">
<span v-if="props.loading" class="placeholder-glow"
><span class="placeholder col-12"></span
></span>
<span
v-else
@click="truncateDescription = false"
:class="{
'cursor-pointer': truncateDescription,
}"
>{{ props.workflow.short_description }}</span
>
<span v-else>{{ props.workflow.short_description }}</span>
</p>
<div class="d-flex justify-content-between mb-0">
<div v-if="props.loading" class="placeholder-glow w-50">
......
......@@ -115,6 +115,10 @@ export const useResourceStore = defineStore({
return ResourceService.resourceListSyncRequests()
.then((requests) => {
this.__syncRequestsFetched = true;
const userStore = useAuthStore();
userStore.fetchUsernames(
requests.map((request) => request.requester_id),
);
const newMapping: Record<string, UserSynchronizationRequestOut> = {};
for (const request of requests) {
newMapping[request.resource_version_id] = request;
......@@ -136,6 +140,10 @@ export const useResourceStore = defineStore({
searchString,
_public,
).then((resources) => {
const userStore = useAuthStore();
userStore.fetchUsernames(
resources.map((resource) => resource.maintainer_id),
);
const nameStore = useNameStore();
for (const resource of resources) {
nameStore.addNameToMapping(resource.resource_id, resource.name);
......
......@@ -92,12 +92,22 @@ function searchUsers() {
Search
</button>
</form>
<table class="table table-striped align-middle" v-if="userState.users">
<table
class="table table-striped align-middle caption-top"
v-if="userState.users"
>
<caption>
Displaying
{{
userState.users.length
}}
Users
</caption>
<thead>
<tr>
<th scope="col"><b>Name</b></th>
<th scope="col">UID</th>
<th scope="col" class="text-center">Normal User</th>
<th scope="col" class="text-center">Approved User</th>
<th scope="col" class="text-center">Developer</th>
<th scope="col" class="text-center">Resource Maintainer</th>
<th scope="col" class="text-center">Reviewer</th>
......
......@@ -13,12 +13,12 @@ const workflowRepository = useWorkflowStore();
const workflowsState = reactive<{
loading: boolean;
filterString: string;
sortByAttribute: string;
sortByAttribute: "name" | "release";
sortDesc: boolean;
}>({
loading: true,
filterString: "",
sortByAttribute: "name",
sortByAttribute: "release",
sortDesc: true,
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment