Skip to content
Snippets Groups Projects
Commit d5a6e295 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Added input field for changing node name during copy of single nodes and added...

Added input field for changing node name during copy of single nodes and added comments on moveOrCopyNodes method
parent 5b9e1610
Branches
Tags
No related merge requests found
Pipeline #2301 passed
......@@ -210,6 +210,7 @@ public class NodesController extends BaseController {
@PostMapping(value = "/moveOrCopy")
public ResponseEntity<List<Job>> moveOrCopyNodes(@RequestBody MoveOrCopyRequest request) throws Exception {
// Creates a transfer request for each copy or move operation
CompletableFuture<JobSummary>[] futureJobs = request.getTargets().stream().map(t -> {
String target = urlEncodePath(t);
String direction = urlEncodePath(request.getDirection());
......@@ -220,12 +221,21 @@ public class NodesController extends BaseController {
return CompletableFuture.supplyAsync(() -> client.startTransferJob(transfer), Runnable::run);
}).collect(Collectors.toList()).toArray(CompletableFuture[]::new);
// starts all HTTP requests in parallel
CompletableFuture.allOf(futureJobs).join();
// parses all the responses and populates a list of jobs to check the
// completion status using polling mechanism
List<JobSummary> jobs = Stream.of(futureJobs).map(j -> j.join()).collect(Collectors.toList());
// Job statuses are checked for some time and if completion takes too much
// time sends the execution phase to the UI and let it handles the polling.
// Since CompletableFutures can't really be aborted (see cancel method
// documentation) an AtomicReference containing a boolean flag it is
// passed to handle polling abortion.
AtomicReference<Boolean> cancelled = new AtomicReference<>(false);
// CompletableFuture that triggers the timeout
CompletableFuture timeout = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(pollingTimeout * 1000);
......@@ -235,6 +245,7 @@ public class NodesController extends BaseController {
});
try {
// performs polling of job statuses or timeout
CompletableFuture.anyOf(jobsPolling(jobs, cancelled), timeout).join();
} catch (CompletionException ex) {
if (ex.getCause() != null && ex.getCause() instanceof VOSpaceException) {
......@@ -243,8 +254,6 @@ public class NodesController extends BaseController {
throw ex;
}
// Try to perform polling until completion. If it takes too much time
// sends the execution phase to the UI and let it handles the polling.
Job.JobType type = request.isKeepBytes() ? Job.JobType.COPY : Job.JobType.MOVE;
return ResponseEntity.ok(jobs.stream().map(j -> new Job(j, type))
......
......@@ -5,6 +5,12 @@
-->
<template>
<b-modal id="move-or-copy-modal" :title="title" :okTitle="okTitle" @show="afterShow" @ok.prevent="moveOrCopyNodes" :ok-disabled="!writable" size="lg">
<b-form inline v-if="this.nodesToMoveOrCopy.length === 1 && this.moveOrCopy === 'copy'" class="mb-3">
<label class="w-25" for="new-name-input">New name</label>
<b-form-input v-model.trim="newName" id="new-name-input" class="w-75" aria-describedby="new-name-input-feedback" :state="newNameState" v-on:input="resetNewNameError" @keydown.native.enter="moveOrCopyNodes">
</b-form-input>
<b-form-invalid-feedback id="new-folder-name-input-feedback" class="text-right">{{newNameError}}</b-form-invalid-feedback>
</b-form>
<ol class="breadcrumb">
<li class="breadcrumb-item" v-for="(item, i) in breadcrumbs" :key="i" :class="{ 'active' : item.active }">
<a href="#" @click.stop.prevent="breadcrumbClick(i)" v-if="!item.active">{{item.text}}</a>
......@@ -66,13 +72,31 @@ export default {
}
}
return items;
},
newNameState() {
if (this.newNameError) {
return false;
}
return null;
}
},
data() {
return {
newName: null,
newNameError: null
}
},
methods: {
afterShow() {
// starts from parent path
let firstSelectedNode = this.nodesToMoveOrCopy[0];
this.$store.dispatch('openNodeInMoveOrCopyModal', firstSelectedNode.substring(0, firstSelectedNode.lastIndexOf('/')));
let lastSlashPos = firstSelectedNode.lastIndexOf('/');
this.$store.dispatch('openNodeInMoveOrCopyModal', firstSelectedNode.substring(0, lastSlashPos));
if (this.nodesToMoveOrCopy.length === 1 && this.moveOrCopy === 'copy') {
this.newName = firstSelectedNode.substring(lastSlashPos + 1);
} else {
this.newName = null;
}
},
breadcrumbClick(i) {
let pathSplit = this.destinationPath.split('/');
......@@ -84,14 +108,31 @@ export default {
window.openNodeInMoveOrCopyModal(event, path);
},
moveOrCopyNodes() {
let direction = this.destinationPath;
if (this.nodesToMoveOrCopy.length === 1 && this.moveOrCopy === 'copy') {
if (!this.newName) {
this.newNameError = "Name is required";
return;
} else if (/[<>?":\\/`|'*]/.test(this.newName)) {
this.newNameError = "Name contains an illegal character. Following characters are not allowed: < > ? \" : \\ / | ' * `";
return;
}
direction += '/' + this.newName;
}
this.$store.dispatch('moveOrCopyNodes', {
targets: this.nodesToMoveOrCopy,
direction: this.destinationPath,
direction,
keepBytes: this.moveOrCopy === 'copy'
})
.then(() => {
this.$bvModal.hide('move-or-copy-modal');
})
},
resetNewNameError() {
this.newNameError = null;
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment