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

Add UI to manage OTRS for buckets

parent a20abc63
No related branches found
No related tags found
1 merge request!143Resolve "Add UI for ownership tranfers"
Showing
with 2039 additions and 440 deletions
Source diff could not be displayed: it is too large. Options to address this: view the blob.
......@@ -60,7 +60,7 @@
"rollup-plugin-node-polyfills": "~0.2.1",
"sass": "^1.66.0",
"typescript": "~5.5.0",
"vite": "~5.3.0",
"vite": "~5.4.0",
"vue-tsc": "~2.0.0"
}
}
......@@ -28,6 +28,9 @@ export type { HTTPValidationError } from './models/HTTPValidationError';
export type { IconUpdateOut } from './models/IconUpdateOut';
export { NextflowVersion } from './models/NextflowVersion';
export { OIDCProvider } from './models/OIDCProvider';
export type { OwnershipTransferRequestIn } from './models/OwnershipTransferRequestIn';
export type { OwnershipTransferRequestOut } from './models/OwnershipTransferRequestOut';
export { OwnershipTypeEnum } from './models/OwnershipTypeEnum';
export type { ParameterExtension } from './models/ParameterExtension';
export { Permission } from './models/Permission';
export { PermissionStatus } from './models/PermissionStatus';
......
......@@ -19,7 +19,7 @@ export type BucketPermissionIn = {
/**
* Permission
*/
permission?: (Permission | string);
permission?: (Permission | 'READ' | 'WRITE' | 'READWRITE');
/**
* UID of the grantee
*/
......
......@@ -22,7 +22,7 @@ export type BucketPermissionOut = {
/**
* Permission
*/
permission?: (Permission | string);
permission?: (Permission | 'READ' | 'WRITE' | 'READWRITE');
/**
* UID of the grantee
*/
......
......@@ -22,6 +22,6 @@ export type BucketPermissionParameters = {
/**
* Permission
*/
permission?: (Permission | string);
permission?: (Permission | 'READ' | 'WRITE' | 'READWRITE');
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type OwnershipTransferRequestIn = {
/**
* The new owner that get the request
*/
new_owner_uid: string;
/**
* An optional comment for the transfer request
*/
comment?: (string | null);
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { OwnershipTypeEnum } from './OwnershipTypeEnum';
export type OwnershipTransferRequestOut = {
/**
* The new owner that get the request
*/
new_owner_uid: string;
/**
* An optional comment for the transfer request
*/
comment?: string;
/**
* Time when the ownership transfer was requested as UNIX timestamp
*/
created_at: number;
/**
* The current uid of the current owner if he exists
*/
current_owner_uid?: (string | null);
/**
* Id of the target that gets its ownership transferred
*/
target_id: string;
/**
* Name of the target
*/
target_name: string;
/**
* Description of then target
*/
target_description: string;
/**
* Target type of the ownership transfer
*/
target_type: OwnershipTypeEnum;
};
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export enum OwnershipTypeEnum {
BUCKET = 'bucket',
WORKFLOW = 'workflow',
RESOURCE = 'resource',
}
......@@ -24,6 +24,10 @@ export type ResourceVersionOut = {
* Timestamp when the version was created as UNIX timestamp
*/
created_at: number;
/**
* Size of the compressed resource in bytes
*/
compressed_size: number;
/**
* Path to the resource on the cluster if the resource is synchronized
*/
......
......@@ -171,27 +171,30 @@ export class BucketPermissionService {
});
}
/**
* Delete a bucket permission
* Delete the bucket permissions for the specific combination of bucket and user.
* Update a bucket permission
* Update a permission for a bucket and user.
*
* Permission `bucket_permission:delete` required if current user is the target or owner of the bucket permission,
* otherwise `bucket_permission:delete_any` required.
* Permission `bucket_permission:update` required.
* @param bucketName Name of bucket
* @param uid UID of a user
* @returns void
* @param requestBody
* @returns BucketPermissionOut Successful Response
* @throws ApiError
*/
public static bucketPermissionDeletePermission(
public static bucketPermissionUpdatePermission(
bucketName: string,
uid: string,
): CancelablePromise<void> {
requestBody: BucketPermissionParameters,
): CancelablePromise<BucketPermissionOut> {
return __request(OpenAPI, {
method: 'DELETE',
method: 'PUT',
url: '/permissions/bucket/{bucket_name}/user/{uid}',
path: {
'bucket_name': bucketName,
'uid': uid,
},
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
......@@ -202,30 +205,27 @@ export class BucketPermissionService {
});
}
/**
* Update a bucket permission
* Update a permission for a bucket and user.
* Delete a bucket permission
* Delete the bucket permissions for the specific combination of bucket and user.
*
* Permission `bucket_permission:update` required.
* Permission `bucket_permission:delete` required if current user is the target or owner of the bucket permission,
* otherwise `bucket_permission:delete_any` required.
* @param bucketName Name of bucket
* @param uid UID of a user
* @param requestBody
* @returns BucketPermissionOut Successful Response
* @returns void
* @throws ApiError
*/
public static bucketPermissionUpdatePermission(
public static bucketPermissionDeletePermission(
bucketName: string,
uid: string,
requestBody: BucketPermissionParameters,
): CancelablePromise<BucketPermissionOut> {
): CancelablePromise<void> {
return __request(OpenAPI, {
method: 'PUT',
method: 'DELETE',
url: '/permissions/bucket/{bucket_name}/user/{uid}',
path: {
'bucket_name': bucketName,
'uid': uid,
},
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
......
......@@ -7,16 +7,18 @@ import type { BucketIn } from '../models/BucketIn';
import type { BucketOut } from '../models/BucketOut';
import type { BucketSizeLimits } from '../models/BucketSizeLimits';
import type { BucketType } from '../models/BucketType';
import type { OwnershipTransferRequestIn } from '../models/OwnershipTransferRequestIn';
import type { OwnershipTransferRequestOut } from '../models/OwnershipTransferRequestOut';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class BucketService {
/**
* List buckets of user
* List buckets
* List all the buckets in the system or of the desired user where the user has permissions for.
*
* Permission `bucket:list_all` required. See parameter `owner_id` for exception.
* @param ownerId UID of the user for whom to fetch the buckets for. Permission 'bucket:read_any' required if current user is not the target.
* @param ownerId UID of the user for whom to fetch the buckets for. Permission `bucket:read_any` required if current user is not the target.
* @param bucketType Type of the bucket to get. Ignored when `user` parameter not set
* @returns BucketOut Successful Response
* @throws ApiError
......@@ -71,6 +73,37 @@ export class BucketService {
},
});
}
/**
* List bucket OTRs
* Get the ownership transfer requests for buckets.
*
* Permission `bucket:list` required if `current_owner_id` or `new_owner_id` is the current users id,
* otherwise `bucket:list_all`
* @param currentOwnerId UID of user who is the current owner.
* @param newOwnerId UID of user who will be the new owner.
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static bucketListBucketOtrs(
currentOwnerId?: string,
newOwnerId?: string,
): CancelablePromise<Array<OwnershipTransferRequestOut>> {
return __request(OpenAPI, {
method: 'GET',
url: '/buckets/ownership_transfer_request',
query: {
'current_owner_id': currentOwnerId,
'new_owner_id': newOwnerId,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Get a bucket by its name
* Get a bucket by its name if the current user has READ permissions for the bucket.
......@@ -132,6 +165,122 @@ export class BucketService {
},
});
}
/**
* Get a bucket OTR
* Get a specific bucket ownership transfer request.
*
* Permission `bucket:read` required if the current user is the current or new owner of the bucket,
* otherwise `bucket:read_any` required.
* @param bucketName Name of bucket
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static bucketGetBucketOtr(
bucketName: string,
): CancelablePromise<OwnershipTransferRequestOut> {
return __request(OpenAPI, {
method: 'GET',
url: '/buckets/{bucket_name}/ownership_transfer_request',
path: {
'bucket_name': bucketName,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Create a bucket OTR
* Create a ownership transfer request for a specific bucket.
*
* Permission `bucket:update` required if the current user is the current owner of the bucket,
* otherwise `bucket:update_any` required.
* @param bucketName Name of bucket
* @param requestBody
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static bucketCreateBucketOtr(
bucketName: string,
requestBody: OwnershipTransferRequestIn,
): CancelablePromise<OwnershipTransferRequestOut> {
return __request(OpenAPI, {
method: 'POST',
url: '/buckets/{bucket_name}/ownership_transfer_request',
path: {
'bucket_name': bucketName,
},
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Accept a bucket OTR
* Accept an ownership transfer request for a specific workflow.
*
* Permission `bucket:update` required if the current user is the new owner of the workflow,
* otherwise `bucket:update_any` required.
* @param bucketName Name of bucket
* @returns BucketOut Successful Response
* @throws ApiError
*/
public static bucketAcceptBucketOtr(
bucketName: string,
): CancelablePromise<BucketOut> {
return __request(OpenAPI, {
method: 'PATCH',
url: '/buckets/{bucket_name}/ownership_transfer_request',
path: {
'bucket_name': bucketName,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Delete a bucket OTR
* Delete/Reject a bucket ownership transfer request.
*
* Permission `bucket:update` required if the current user is the current or new owner of the bucket,
* otherwise `bucket:update_any` required.
* @param bucketName Name of bucket
* @returns void
* @throws ApiError
*/
public static bucketDeleteBucketOtr(
bucketName: string,
): CancelablePromise<void> {
return __request(OpenAPI, {
method: 'DELETE',
url: '/buckets/{bucket_name}/ownership_transfer_request',
path: {
'bucket_name': bucketName,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Update public status
* Update the buckets public state.
......
......@@ -2,6 +2,8 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { OwnershipTransferRequestIn } from '../models/OwnershipTransferRequestIn';
import type { OwnershipTransferRequestOut } from '../models/OwnershipTransferRequestOut';
import type { ResourceIn } from '../models/ResourceIn';
import type { ResourceOut } from '../models/ResourceOut';
import type { ResourceVersionStatus } from '../models/ResourceVersionStatus';
......@@ -10,6 +12,32 @@ import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class ResourceService {
/**
* Request a new resource
* Request a new resources.
*
* Permission `resource:create` required.
* @param requestBody
* @returns ResourceOut Successful Response
* @throws ApiError
*/
public static resourceCreateResource(
requestBody: ResourceIn,
): CancelablePromise<ResourceOut> {
return __request(OpenAPI, {
method: 'POST',
url: '/resources',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* List resources
* List all resources.
......@@ -47,48 +75,53 @@ export class ResourceService {
});
}
/**
* Request a new resource
* Request a new resources.
* List resource sync requests
* List all resource sync requests.
*
* Permission `resource:create` required.
* @param requestBody
* @returns ResourceOut Successful Response
* Permission `resource:update_any` required.
* @returns UserSynchronizationRequestOut Successful Response
* @throws ApiError
*/
public static resourceCreateResource(
requestBody: ResourceIn,
): CancelablePromise<ResourceOut> {
public static resourceListSyncRequests(): CancelablePromise<Array<UserSynchronizationRequestOut>> {
return __request(OpenAPI, {
method: 'POST',
url: '/resources',
body: requestBody,
mediaType: 'application/json',
method: 'GET',
url: '/resources/sync_requests',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* List resource sync requests
* List all resource sync requests.
* List resource OTRs
* Get the ownership transfer requests for resources.
*
* Permission `resource:update_any` required.
* @returns UserSynchronizationRequestOut Successful Response
* Permission `resource:list` required if `current_owner_id` or `new_owner_id` is the current users id,
* otherwise `resource:list_all`
* @param currentOwnerId UID of user who is the current owner.
* @param newOwnerId UID of user who will be the new owner.
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static resourceListSyncRequests(): CancelablePromise<Array<UserSynchronizationRequestOut>> {
public static resourceListResourceOtrs(
currentOwnerId?: string,
newOwnerId?: string,
): CancelablePromise<Array<OwnershipTransferRequestOut>> {
return __request(OpenAPI, {
method: 'GET',
url: '/resources/sync_requests',
url: '/resources/ownership_transfer_request',
query: {
'current_owner_id': currentOwnerId,
'new_owner_id': newOwnerId,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
......@@ -151,4 +184,120 @@ export class ResourceService {
},
});
}
/**
* Get a resource OTR
* Get a specific resource ownership transfer request.
*
* Permission `resource:read` required if the current user is the current or new owner of the resource,
* otherwise `resource:read_any` required.
* @param rid
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static resourceGetResourceOtr(
rid: string,
): CancelablePromise<OwnershipTransferRequestOut> {
return __request(OpenAPI, {
method: 'GET',
url: '/resources/{rid}/ownership_transfer_request',
path: {
'rid': rid,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Create a resource OTR
* Create a ownership transfer request for a specific resource.
*
* Permission `resource:update` required if the current user is the current owner of the resource,
* otherwise `resource:update_any` required.
* @param rid
* @param requestBody
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static resourceCreateResourceOtr(
rid: string,
requestBody: OwnershipTransferRequestIn,
): CancelablePromise<OwnershipTransferRequestOut> {
return __request(OpenAPI, {
method: 'POST',
url: '/resources/{rid}/ownership_transfer_request',
path: {
'rid': rid,
},
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Accept a resource OTR
* Accept an ownership transfer request for a specific resource.
*
* Permission `resource:update` required if the current user is the new owner of the resource,
* otherwise `resource:update_any` required.
* @param rid
* @returns ResourceOut Successful Response
* @throws ApiError
*/
public static resourceAcceptResourceOtr(
rid: string,
): CancelablePromise<ResourceOut> {
return __request(OpenAPI, {
method: 'PATCH',
url: '/resources/{rid}/ownership_transfer_request',
path: {
'rid': rid,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Delete a resource OTR
* Delete/Reject a resource ownership transfer request.
*
* Permission `resource:update` required if the current user is the current or new owner of the resource,
* otherwise `resource:update_any` required.
* @param rid
* @returns void
* @throws ApiError
*/
public static resourceDeleteResourceOtr(
rid: string,
): CancelablePromise<void> {
return __request(OpenAPI, {
method: 'DELETE',
url: '/resources/{rid}/ownership_transfer_request',
path: {
'rid': rid,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
}
......@@ -142,7 +142,7 @@ export class UserService {
});
}
/**
* Update Roles
* Update user roles
* Update the roles of a user.
*
* Permission `user:update` required.
......
......@@ -3,6 +3,8 @@
/* tslint:disable */
/* eslint-disable */
import type { AnonymizedWorkflowExecution } from '../models/AnonymizedWorkflowExecution';
import type { OwnershipTransferRequestIn } from '../models/OwnershipTransferRequestIn';
import type { OwnershipTransferRequestOut } from '../models/OwnershipTransferRequestOut';
import type { WorkflowIn } from '../models/WorkflowIn';
import type { WorkflowOut } from '../models/WorkflowOut';
import type { WorkflowStatistic } from '../models/WorkflowStatistic';
......@@ -13,6 +15,36 @@ import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class WorkflowService {
/**
* Create a new workflow
* Create a new workflow.
*
* For private Gitlab repositories, a Project Access Token with the role Reporter and scope `read_api` is needed.
*
* For private GitHub repositories, a Personal Access Token (classic) with scope `repo` is needed.
*
* Permission `workflow:create` required.
* @param requestBody
* @returns WorkflowOut Successful Response
* @throws ApiError
*/
public static workflowCreateWorkflow(
requestBody: WorkflowIn,
): CancelablePromise<WorkflowOut> {
return __request(OpenAPI, {
method: 'POST',
url: '/workflows',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* List workflows
* List all workflows.
......@@ -47,26 +79,27 @@ export class WorkflowService {
});
}
/**
* Create a new workflow
* Create a new workflow.
*
* For private Gitlab repositories, a Project Access Token with the role Reporter and scope `read_api` is needed.
* List workflow OTRs
* Get the ownership transfer requests for workflows.
*
* For private GitHub repositories, a Personal Access Token (classic) with scope `repo` is needed.
*
* Permission `workflow:create` required.
* @param requestBody
* @returns WorkflowOut Successful Response
* Permission `workflow:list` required if `current_owner_id` or `new_owner_id` is the current users id,
* otherwise `workflow:list_all`
* @param currentOwnerId UID of user who is the current owner.
* @param newOwnerId UID of user who will be the new owner.
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static workflowCreateWorkflow(
requestBody: WorkflowIn,
): CancelablePromise<WorkflowOut> {
public static workflowListWorkflowOtrs(
currentOwnerId?: string,
newOwnerId?: string,
): CancelablePromise<Array<OwnershipTransferRequestOut>> {
return __request(OpenAPI, {
method: 'POST',
url: '/workflows',
body: requestBody,
mediaType: 'application/json',
method: 'GET',
url: '/workflows/ownership_transfer_request',
query: {
'current_owner_id': currentOwnerId,
'new_owner_id': newOwnerId,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
......@@ -173,6 +206,122 @@ export class WorkflowService {
},
});
}
/**
* Get a workflow OTR
* Get a specific workflow ownership transfer request.
*
* Permission `workflow:read` required if current user is the current or new owner of the workflow,
* otherwise `workflow:read_any` required.
* @param wid ID of a workflow
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static workflowGetWorkflowOtr(
wid: string,
): CancelablePromise<OwnershipTransferRequestOut> {
return __request(OpenAPI, {
method: 'GET',
url: '/workflows/{wid}/ownership_transfer_request',
path: {
'wid': wid,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Create a workflow OTR
* Create a ownership transfer request for a specific workflow.
*
* Permission `workflow:update` required if the current user is the current owner of the workflow,
* otherwise `workflow:update_any` required.
* @param wid ID of a workflow
* @param requestBody
* @returns OwnershipTransferRequestOut Successful Response
* @throws ApiError
*/
public static workflowCreateBucketOtr(
wid: string,
requestBody: OwnershipTransferRequestIn,
): CancelablePromise<OwnershipTransferRequestOut> {
return __request(OpenAPI, {
method: 'POST',
url: '/workflows/{wid}/ownership_transfer_request',
path: {
'wid': wid,
},
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Accept a workflow OTR
* Accept an ownership transfer request for a specific workflow.
*
* Permission `workflow:update` required if the current user is the new owner of the workflow,
* otherwise `workflow:update_any` required.
* @param wid ID of a workflow
* @returns WorkflowOut Successful Response
* @throws ApiError
*/
public static workflowAcceptWorkflowOtr(
wid: string,
): CancelablePromise<WorkflowOut> {
return __request(OpenAPI, {
method: 'PATCH',
url: '/workflows/{wid}/ownership_transfer_request',
path: {
'wid': wid,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Delete a workflow OTR
* Delete/Reject a workflow ownership transfer request.
*
* Permission `workflow:update` required if current user is the current or new owner of the workflow,
* otherwise `workflow:update_any` required.
* @param wid ID of a workflow
* @returns void
* @throws ApiError
*/
public static workflowDeleteWorkflowOtr(
wid: string,
): CancelablePromise<void> {
return __request(OpenAPI, {
method: 'DELETE',
url: '/workflows/{wid}/ownership_transfer_request',
path: {
'wid': wid,
},
errors: {
400: `Error decoding JWT Token`,
401: `Not Authenticated`,
403: `Not Authorized`,
404: `Entity not Found`,
422: `Validation Error`,
},
});
}
/**
* Get statistics for a workflow
* Get the number of started workflow per day.
......
......@@ -12,6 +12,13 @@ const props = defineProps({
toastId: { type: String, required: true },
});
const emit = defineEmits<{
(e: "hide.bs.toast"): void;
(e: "hidden.bs.toast"): void;
(e: "show.bs.toast"): void;
(e: "shown.bs.toast"): void;
}>();
const colorClassName = computed<string>(() => {
return `text-bg-${props.colorClass}`;
});
......@@ -27,6 +34,12 @@ const colorClassName = computed<string>(() => {
:class="colorClassName"
data-bs-autohide="true"
:id="props.toastId"
v-on="{
'hidden.bs.toast': emit('hidden.bs.toast'),
'hide.bs.toast': emit('hide.bs.toast'),
'show.bs.toast': emit('show.bs.toast'),
'shown.bs.toast': emit('shown.bs.toast'),
}"
>
<div class="toast-body">
<div class="d-flex justify-content-between fs-6">
......
<template>
<span
class="align-middle"
ref="iconElement"
:class="icon"
:style="{
color: props.fill,
}"
:data-bs-toogle="tooltip.length > 0 ? 'tooltip' : undefined"
:data-bs-title="tooltip.length > 0 ? tooltip : undefined"
></span>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { Tooltip } from "bootstrap";
const iconElement = ref<HTMLSpanElement | undefined>(undefined);
const props = defineProps({
icon: { type: String, required: true },
fill: { type: String, default: "currentColor", required: false },
tooltip: { type: String, required: false, default: "" },
});
onMounted(() => {
if (props.tooltip.length > 0 && iconElement.value != undefined) {
new Tooltip(iconElement.value);
}
});
</script>
......
<script setup lang="ts">
import {
OwnershipTypeEnum,
type OwnershipTransferRequestIn,
type ResourceOut,
type UserOut,
type WorkflowOut,
type BucketOut,
} from "@/client";
import BootstrapModal from "@/components/modals/BootstrapModal.vue";
import { computed, onMounted, reactive, ref, watch } from "vue";
import SearchUserModal from "@/components/modals/SearchUserModal.vue";
import { Modal, Toast } from "bootstrap";
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import { useNameStore } from "@/stores/names";
import { useOTRStore } from "@/stores/otrs";
import BootstrapToast from "@/components/BootstrapToast.vue";
type OtrTypes = BucketOut | WorkflowOut | ResourceOut;
const props = defineProps<{
modalId: string;
target: OtrTypes;
backModalId?: string;
}>();
const randomIDSuffix = Math.random().toString(16).substring(2, 8);
let createOtrModal: Modal | null = null;
let successToast: Toast | null = null;
const nameRepository = useNameStore();
const otrRepository = useOTRStore();
const otrCreateForm = ref<HTMLFormElement | undefined>(undefined);
const formState = reactive<{
validated: boolean;
requestIn: OwnershipTransferRequestIn;
}>({
validated: false,
requestIn: {
new_owner_uid: "",
comment: undefined,
},
});
const targetType = computed<OwnershipTypeEnum>(() => {
if (isBucket(props.target)) {
return OwnershipTypeEnum.BUCKET;
} else if (isWorkflow(props.target)) {
return OwnershipTypeEnum.WORKFLOW;
}
return OwnershipTypeEnum.RESOURCE;
});
const targetName = computed<string>(() => props.target.name);
const targetId = computed<string>(() => {
if (isBucket(props.target)) {
return props.target.name;
} else if (isWorkflow(props.target)) {
return props.target.workflow_id;
} else if (isResource(props.target)) {
return props.target.resource_id;
}
return "";
});
watch(targetId, (newId, oldId) => {
if (newId !== oldId) {
resetForm();
}
});
function saveOtr() {
formState.validated = true;
formState.requestIn.comment = formState.requestIn.comment?.trim();
if (otrCreateForm.value?.checkValidity()) {
otrRepository
.createOtr(targetId.value, formState.requestIn, targetType.value)
.then(() => {
createOtrModal?.hide();
successToast?.show();
resetForm();
});
}
}
function isBucket(toBeDetermined: OtrTypes): toBeDetermined is BucketOut {
return !!(toBeDetermined as BucketOut).description;
}
function isWorkflow(toBeDetermined: OtrTypes): toBeDetermined is WorkflowOut {
return !!(toBeDetermined as WorkflowOut).workflow_id;
}
function isResource(toBeDetermined: OtrTypes): toBeDetermined is ResourceOut {
return !!(toBeDetermined as ResourceOut).resource_id;
}
function updateUser(user: UserOut) {
formState.requestIn.new_owner_uid = user.uid;
}
function resetForm() {
formState.validated = false;
formState.requestIn.new_owner_uid = "";
formState.requestIn.comment = undefined;
}
onMounted(() => {
createOtrModal = Modal.getOrCreateInstance(`#${props.modalId}`);
successToast = Toast.getOrCreateInstance("#create-otr-success-toast");
});
</script>
<template>
<bootstrap-toast toast-id="create-otr-success-toast" color-class="success">
Successfully created request for {{ targetType }} {{ targetName }}
</bootstrap-toast>
<search-user-modal
:modal-id="`search-user-for-otr-modal-${randomIDSuffix}`"
:back-modal-id="props.modalId"
:filter-user-self="true"
@user-found="updateUser"
/>
<bootstrap-modal
:modalId="props.modalId"
:static-backdrop="true"
size-modifier-modal="lg"
:modal-label="`Create ${targetType} OTR`"
>
<template #header
>Create Ownership transfer request for {{ targetType }}
<b>{{ targetName }}</b></template
>
<template #body>
<form
@submit.prevent="saveOtr"
:class="{ 'was-validated': formState.validated }"
id="create-otr-form"
ref="otrCreateForm"
>
<div class="m-1">
<label for="create-otr-user-search" class="form-label"
>Name of the new owner</label
>
<div class="input-group">
<div class="input-group-text">
<font-awesome-icon icon="fa-solid fa-user" />
</div>
<input
id="create-otr-user-search"
type="text"
class="form-control"
readonly
:value="nameRepository.getName(formState.requestIn.new_owner_uid)"
placeholder="Search for new owner"
data-bs-toggle="modal"
:data-bs-target="`#search-user-for-otr-modal-${randomIDSuffix}`"
/>
</div>
</div>
<div class="m-1">
<label for="create-otr-comment" class="form-label"> Comment </label>
<div class="input-group">
<textarea
class="form-control"
id="create-otr-comment"
rows="2"
maxlength="265"
v-model="formState.requestIn.comment"
placeholder="Optional comment for this request"
></textarea>
</div>
</div>
</form>
</template>
<template #footer>
<button
type="submit"
form="create-otr-form"
class="btn btn-success"
:disabled="formState.requestIn.new_owner_uid.length === 0"
>
Save
</button>
<button
type="button"
class="btn btn-secondary"
:data-bs-target="backModalId ? `#${backModalId}` : undefined"
:data-bs-toggle="backModalId ? 'modal' : undefined"
:data-bs-dismiss="backModalId ? undefined : 'modal'"
>
<template v-if="backModalId">Back</template>
<template v-else>Close</template>
</button>
</template>
</bootstrap-modal>
</template>
<style scoped></style>
<script setup lang="ts">
import BootstrapModal from "@/components/modals/BootstrapModal.vue";
import { type OwnershipTransferRequestOut, OwnershipTypeEnum } from "@/client";
import OtrModal from "@/components/modals/ShowOtrModal.vue";
import { ref } from "vue";
import dayjs from "dayjs";
import { useNameStore } from "@/stores/names";
const nameRepo = useNameStore();
const props = defineProps<{
modalId: string;
otrType: OwnershipTypeEnum;
otrs: OwnershipTransferRequestOut[];
}>();
const otrTargetId = ref<string>("");
const randomIDSuffix = Math.random().toString(16).substring(2, 8);
</script>
<template>
<otr-modal
:otr-target-id="otrTargetId"
:modalId="`view-bucket-otr-modal-${randomIDSuffix}`"
:back-modal-id="modalId"
/>
<bootstrap-modal
:modalId="props.modalId"
:static-backdrop="true"
size-modifier-modal="lg"
:modal-label="`List ${props.otrType} OTRs`"
>
<template #header
>Ownership transfer requests for {{ props.otrType }}s
</template>
<template #body>
<div v-if="otrs.length > 0">
<div class="d-flex justify-content-between w-100 px-3 py-2">
<span>Name</span>
<span>Current Owner</span>
<span>Requested at</span>
</div>
<div class="list-group">
<button
v-for="otr of otrs"
:key="otr.target_id"
type="button"
class="list-group-item list-group-item-action d-flex justify-content-between"
:data-bs-target="`#view-bucket-otr-modal-${randomIDSuffix}`"
data-bs-toggle="modal"
@click="otrTargetId = otr.target_id"
>
<span>{{ otr.target_name }}</span>
<span v-if="otr.current_owner_uid">{{
nameRepo.getName(otr.current_owner_uid)
}}</span>
<span>{{ dayjs.unix(otr.created_at).fromNow() }}</span>
</button>
</div>
</div>
<div v-else>
<h3 class="text-center">
No open {{ props.otrType }} ownership transfer requests
</h3>
</div>
</template>
<template #footer>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
Close
</button>
</template>
</bootstrap-modal>
</template>
<style scoped></style>
<script setup lang="ts">
import BootstrapModal from "@/components/modals/BootstrapModal.vue";
import { useOTRStore } from "@/stores/otrs";
import { computed, onMounted, ref } from "vue";
import type { OwnershipTransferRequestOut } from "@/client";
import { useNameStore } from "@/stores/names";
import dayjs from "dayjs";
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import DeleteModal from "@/components/modals/DeleteModal.vue";
import { useUserStore } from "@/stores/users";
import BootstrapToast from "@/components/BootstrapToast.vue";
import { Toast } from "bootstrap";
const otrRepository = useOTRStore();
const nameRepository = useNameStore();
const userRepository = useUserStore();
const randomIDSuffix = Math.random().toString(16).substring(2, 8);
let successToast: Toast | null = null;
const props = defineProps<{
modalId: string;
backModalId?: string;
otrTargetId: string;
}>();
const accepted = ref<boolean>(false);
const otr = computed<OwnershipTransferRequestOut | undefined>(
() => otrRepository.otrMapping[props.otrTargetId],
);
const emit = defineEmits<{
(e: "deleted-otr", otr: OwnershipTransferRequestOut): void;
(e: "accepted-otr", otr: OwnershipTransferRequestOut): void;
}>();
function acceptOtr(otr: OwnershipTransferRequestOut) {
accepted.value = true;
otrRepository.acceptOtr(otr).then(() => {
emit("accepted-otr", otr);
successToast?.show();
});
}
function deleteOtr(otr?: OwnershipTransferRequestOut) {
if (otr != undefined) {
accepted.value = false;
otrRepository.deleteOtr(otr).then(() => {
emit("deleted-otr", otr);
successToast?.show();
});
}
}
onMounted(() => {
successToast = Toast.getOrCreateInstance(
`#success-handle-otr-${randomIDSuffix}`,
);
});
</script>
<template>
<bootstrap-toast
:toast-id="`success-handle-otr-${randomIDSuffix}`"
color-class="success"
>
<template #default v-if="accepted">
Successfully accepted request for {{ otr?.target_type }}
{{ otr?.target_name }}
</template>
<template #default v-else>
Successfully deleted request for {{ otr?.target_type }}
{{ otr?.target_name }}
</template>
</bootstrap-toast>
<delete-modal
:modal-id="`delete-otr-modal-${randomIDSuffix}`"
:object-name-delete="`ownership transfer request for ${otr?.target_type} ${otr?.target_name}`"
:back-modal-id="modalId"
@confirm-delete="deleteOtr(otr)"
/>
<bootstrap-modal
:modalId="props.modalId"
:static-backdrop="true"
size-modifier-modal="lg"
:modal-label="`Show ${otr?.target_type} OTR`"
>
<template #header
>Ownership transfer request for {{ otr?.target_type }}
<b>{{ otr?.target_name }}</b></template
>
<template #extra-button>
<font-awesome-icon
v-if="
userRepository.admin ||
otr?.current_owner_uid === userRepository.currentUID
"
icon="fa-solid fa-trash"
class="me-2 cursor-pointer hover-danger"
data-bs-toggle="modal"
:data-bs-target="`#delete-otr-modal-${randomIDSuffix}`"
/>
</template>
<template #body>
<div v-if="otr">
<div class="row g-3">
<div class="col-md-6">
<label for="otr-to-user" class="form-label">To</label>
<input
readonly
class="form-control"
id="otr-to-user"
:value="nameRepository.getName(otr.new_owner_uid)"
/>
</div>
<div class="col-md-6" v-if="otr.current_owner_uid">
<label for="otr-from-user" class="form-label">From</label>
<input
class="form-control"
id="otr-from-user"
:value="nameRepository.getName(otr.current_owner_uid)"
/>
</div>
<div class="col-md-6">
<label for="otr-target-name" class="form-label text-capitalize"
>{{ otr?.target_type }} name</label
>
<input
class="form-control"
id="otr-target-name"
:value="otr.target_name"
/>
</div>
<div class="col-md-6" v-if="otr.current_owner_uid">
<label for="otr-timestamp" class="form-label"
>Request created at</label
>
<input
type="datetime-local"
class="form-control"
id="otr-timestamp"
readonly
:value="
dayjs.unix(otr.created_at ?? 0).format('YYYY-MM-DDTHH:mm')
"
/>
</div>
<div class="col-12">
<label for="otr-description" class="form-label text-capitalize"
>{{ otr?.target_type }} description</label
>
<textarea
class="form-control"
id="otr-description"
readonly
rows="2"
:value="otr.target_description"
/>
</div>
<div v-if="otr.comment?.trim().length !== 0" class="col-12">
<label for="otr-comment" class="form-label">Request comment</label>
<textarea
class="form-control"
id="otr-comment"
readonly
rows="2"
:value="otr.comment"
/>
</div>
</div>
<div
v-if="
userRepository.admin ||
otr.new_owner_uid === userRepository.currentUID
"
class="row mt-3 justify-content-md-center"
>
<button
type="button"
class="btn btn-danger btn-lg col-5 mx-2"
@click="deleteOtr(otr)"
data-bs-dismiss="modal"
>
Reject
</button>
<button
type="button"
class="btn btn-success btn-lg col-5 mx-2"
@click="acceptOtr(otr)"
data-bs-dismiss="modal"
>
Accept
</button>
</div>
</div>
<div v-else>Noting to see</div>
</template>
<template #footer>
<button
type="button"
class="btn btn-secondary"
:data-bs-target="backModalId ? `#${backModalId}` : undefined"
:data-bs-toggle="backModalId ? 'modal' : undefined"
:data-bs-dismiss="backModalId ? undefined : 'modal'"
>
<template v-if="backModalId">Back</template>
<template v-else>Close</template>
</button>
</template>
</bootstrap-modal>
</template>
<style scoped></style>
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