mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
incremental work on ui
This commit is contained in:
parent
9717487db4
commit
1d6e4f29a6
@ -11,6 +11,9 @@ package io.nosqlbench.docsys.api;
|
||||
* .io/documentation/latest/jaxrs-resources.html#d0e2040">Jersey jax-rs
|
||||
* resources documentation</A>
|
||||
*
|
||||
* @see <A href="https://repo1.maven.org/maven2/org/glassfish/jersey/jersey-documentation/2.5
|
||||
* .1/jersey-documentation-2.5.1-user-guide.pdf">Jersey 2.5.1 user guide</a>
|
||||
*
|
||||
* @see <A href="https://github.com/jax-rs/spec/blob/master/spec
|
||||
* .pdf">JAX-RS: Java™ API for RESTful Web Services Version 2.1
|
||||
* Proposed Final Draft June 9, 2017</A>
|
||||
|
@ -1,22 +1,77 @@
|
||||
<template>
|
||||
<v-container fluid>
|
||||
<v-select :items="workspaces" label="default workspace"></v-select>
|
||||
<v-container>
|
||||
<v-text-field dense
|
||||
label="Name of new workspace"
|
||||
v-if="mode=='adding'"
|
||||
v-model="new_workspace"
|
||||
ref="new_workspace_input"
|
||||
hint="workspace name"
|
||||
@blur="commitWorkspace(new_workspace)"
|
||||
@keydown.enter="commitWorkspace(new_workspace)"
|
||||
></v-text-field>
|
||||
<v-select dense
|
||||
label="workspace"
|
||||
v-if="mode=='showing'"
|
||||
v-model="workspace"
|
||||
:items="workspaces"
|
||||
item-text="name"
|
||||
item-value="name"
|
||||
>
|
||||
<template v-slot:append-item>
|
||||
<v-list-item>
|
||||
<v-btn @click="addWorkspace()">+ Add Workspace</v-btn>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
</v-container>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceSelector',
|
||||
name: 'workspace-selector',
|
||||
data(context) {
|
||||
let data = {
|
||||
workspaces: [],
|
||||
workspace: 'default',
|
||||
new_workspace: "",
|
||||
mode: "showing",
|
||||
workspaces: [{name: 'default'}],
|
||||
workspace: {name: 'default'},
|
||||
enabled: false
|
||||
};
|
||||
return data;
|
||||
},
|
||||
methods: {
|
||||
addWorkspace: function (evt) {
|
||||
this.mode = "adding";
|
||||
setTimeout(() => {
|
||||
this.$refs.new_workspace_input.$el.focus()
|
||||
});
|
||||
console.log("add evt:" + JSON.stringify(evt));
|
||||
},
|
||||
commitWorkspace: function (evt) {
|
||||
console.log("commit evt:" + JSON.stringify(evt));
|
||||
let committed = this.$axios.$get("/services/workspaces/" + evt)
|
||||
.then(res => {
|
||||
return res;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("create: error: " + e)
|
||||
});
|
||||
console.log("committed: " + JSON.stringify(committed))
|
||||
this.workspaces = this.$axios.$get("/services/workspaces/")
|
||||
.then(res => {
|
||||
console.log("workspaces async:" + JSON.stringify(res));
|
||||
return res;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("refresh error: " + e)
|
||||
});
|
||||
this.workspace = evt;
|
||||
this.mode = "showing"
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
async asyncData({$axios, store}) {
|
||||
let enabled = await $axios.$get("/services/nb/enabled")
|
||||
let enabled = await $axios.$get("/services/status")
|
||||
.then(res => {
|
||||
return res
|
||||
})
|
||||
|
@ -14,7 +14,7 @@
|
||||
justify-center
|
||||
align-center>
|
||||
|
||||
<v-content>
|
||||
<v-main>
|
||||
<v-container fluid>
|
||||
<v-layout row>
|
||||
<v-flex>
|
||||
@ -53,7 +53,7 @@
|
||||
|
||||
</v-container>
|
||||
|
||||
</v-content>
|
||||
</v-main>
|
||||
</v-layout>
|
||||
|
||||
<v-footer app dark color="secondary">
|
||||
@ -251,7 +251,7 @@
|
||||
return data;
|
||||
},
|
||||
async asyncData({ $axios, store }) {
|
||||
let enabled = await $axios.$get("/services/nb/enabled")
|
||||
let enabled = await $axios.$get("/services/status")
|
||||
.then(res => {
|
||||
return res
|
||||
})
|
||||
|
@ -4,7 +4,9 @@
|
||||
<v-toolbar-title>NoSQLBench - Workspaces</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-toolbar-items>
|
||||
<v-btn title="start a new workspace">
|
||||
<workspace-selector></workspace-selector>
|
||||
|
||||
<v-btn title="start a new workspace" @click="startNewWorkspace()">
|
||||
<v-icon>mdi-folder-plus-outline</v-icon>
|
||||
</v-btn>
|
||||
<v-btn title="upload a workspace zip file">
|
||||
@ -35,9 +37,9 @@
|
||||
]
|
||||
-->
|
||||
|
||||
<v-main justify-start align-start class="pa-4">
|
||||
<v-main justify-start align-start class="d-flex pa-4 ma-4">
|
||||
<v-main>
|
||||
<v-card max-width="344" v-for="(workspace,w) in workspaces" :key="w" class="pa-4">
|
||||
<v-card max-width="344" v-for="(workspace,w) in workspaces" :key="w" class="pa-4 ma-4">
|
||||
<v-card-title title="workspace name">{{ workspace.name }}</v-card-title>
|
||||
<v-card-subtitle title="last change">{{ abbrev(workspace.summary.last_changed_filename) }}</v-card-subtitle>
|
||||
<v-divider></v-divider>
|
||||
@ -51,6 +53,10 @@
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-list-item>
|
||||
<v-btn title="view details of workspace">
|
||||
<v-icon>mdi-magnify</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn title="use this workspace">
|
||||
<v-icon>mdi-play</v-icon>
|
||||
</v-btn>
|
||||
@ -58,12 +64,13 @@
|
||||
<v-btn title="download zipped workspace">
|
||||
<v-icon>mdi-folder-download</v-icon>
|
||||
</v-btn>
|
||||
<v-btn title="add one or more files">
|
||||
<v-icon>mdi-file-plus</v-icon>
|
||||
</v-btn>
|
||||
<v-btn title="view details of workspace">
|
||||
<v-icon>mdi-magnify</v-icon>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-btn title="purge workspace">
|
||||
<v-icon @click="purgeWorkspace(workspace.name)">mdi-trash-can</v-icon>
|
||||
</v-btn>
|
||||
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card>
|
||||
@ -74,8 +81,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import WorkspaceSelector from "~/components/WorkspaceSelector";
|
||||
|
||||
export default {
|
||||
name: "workspaces.vue",
|
||||
components: {
|
||||
WorkspaceSelector
|
||||
},
|
||||
data(context) {
|
||||
let data = {
|
||||
workspaces: [
|
||||
@ -89,10 +102,22 @@ export default {
|
||||
methods: {
|
||||
abbrev(name) {
|
||||
return name;
|
||||
},
|
||||
purgeWorkspace: function(ws) {
|
||||
console.log("purging " + ws);
|
||||
this.$axios.$delete("/services/workspaces/" + ws)
|
||||
.then(res => { return res })
|
||||
.catch((e) => {
|
||||
console.log("error: " + e)
|
||||
});
|
||||
this.$forceUpdate();
|
||||
},
|
||||
startNewWorkspace() {
|
||||
console.log("starting new workspace");
|
||||
}
|
||||
},
|
||||
async asyncData({$axios, store}) {
|
||||
let enabled = await $axios.$get("/services/nb/enabled")
|
||||
let enabled = await $axios.$get("/services/status")
|
||||
.then(res => {
|
||||
return res
|
||||
})
|
||||
|
@ -12,6 +12,8 @@ import io.nosqlbench.engine.rest.services.WorkspaceService;
|
||||
import io.nosqlbench.engine.rest.transfertypes.RunScenarioRequest;
|
||||
import io.nosqlbench.engine.rest.transfertypes.ScenarioInfo;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.*;
|
||||
@ -27,6 +29,7 @@ import java.util.*;
|
||||
@Singleton
|
||||
@Path("/services/executor/")
|
||||
public class ScenarioExecutorEndpoint implements WebServiceObject {
|
||||
private final static Logger logger = LogManager.getLogger(ScenarioExecutorEndpoint.class);
|
||||
|
||||
private ScenariosExecutor executor = new ScenariosExecutor("executor-service", 1);
|
||||
|
||||
|
@ -39,12 +39,30 @@ public class WorkspacesEndpoint implements WebServiceObject {
|
||||
return Response.ok(wsviews).build();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{workspace}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response deleteWorkspace(@PathParam("workspace") String workspace,
|
||||
@QueryParam("deleteCount") String deleteCount) {
|
||||
try {
|
||||
int dc = deleteCount!=null ? Integer.valueOf(deleteCount):0;
|
||||
getSvc().purgeWorkspace(workspace,dc);
|
||||
return Response.ok("removed workspace " + workspace).build();
|
||||
} catch (Exception e) {
|
||||
return Response.serverError().entity(e.getMessage()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{workspace}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getWorkspaceInfo(@PathParam("workspace") String workspace) {
|
||||
WorkspaceView workpaceView = getSvc().getWorkspaceView(workspace);
|
||||
return Response.ok(workpaceView).build();
|
||||
try {
|
||||
WorkspaceView workpaceView = getSvc().getWorkspaceView(workspace);
|
||||
return Response.ok(workpaceView).build();
|
||||
} catch (Exception e) {
|
||||
return Response.serverError().entity(e.getMessage()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
|
@ -2,6 +2,8 @@ package io.nosqlbench.engine.rest.services;
|
||||
|
||||
import io.nosqlbench.engine.rest.domain.WorkSpace;
|
||||
import io.nosqlbench.engine.rest.transfertypes.WorkspaceView;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.ws.rs.core.Configuration;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
@ -9,9 +11,13 @@ import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WorkspaceService {
|
||||
private final static Logger logger = LogManager.getLogger(WorkspaceService.class);
|
||||
|
||||
private final Path root;
|
||||
public static String DEFAULT = "default";
|
||||
public static final String WORKSPACE_ROOT = "workspaces_root";
|
||||
@ -65,13 +71,12 @@ public class WorkspaceService {
|
||||
|
||||
public WorkSpace getWorkspace(String workspaceName) {
|
||||
assertLegalWorkspaceName(workspaceName);
|
||||
return new WorkSpace(this.root,workspaceName);
|
||||
return new WorkSpace(this.root, workspaceName);
|
||||
}
|
||||
|
||||
public static void assertLegalWorkspaceName(String workspaceName) {
|
||||
if (!workspaceName.matches("[a-zA-Z][a-zA-Z0-9]+")) {
|
||||
throw new RuntimeException("Workspaces must start with an alphabetic" +
|
||||
" character, and contain only letters and numbers.");
|
||||
if (!workspaceName.matches("[a-zA-Z0-9]+")) {
|
||||
throw new RuntimeException("Workspace names must contain only letters and numbers.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,6 +119,47 @@ public class WorkspaceService {
|
||||
return root.resolve(workspaceName);
|
||||
}
|
||||
|
||||
public void purgeWorkspace(String workspaceName, int deleteCount) {
|
||||
assertLegalWorkspaceName(workspaceName);
|
||||
Path path = workspacePath(workspaceName);
|
||||
if (Files.exists(path)) {
|
||||
try (Stream<Path> counter = Files.walk(path)) {
|
||||
long foundFiles = counter.count();
|
||||
if (foundFiles > 100 && deleteCount != foundFiles) {
|
||||
throw new RuntimeException(
|
||||
"To delete " + foundFiles + " files, you must provide a deleteCount=<count> " +
|
||||
"parameter that matches. This is a safety mechanism."
|
||||
);
|
||||
}
|
||||
logger.debug("found " + foundFiles + " to delete.");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Path relativize = root.relativize(path);
|
||||
if (relativize.toString().contains("..")) {
|
||||
throw new RuntimeException("Illegal path to delete: " + path.toString());
|
||||
}
|
||||
|
||||
|
||||
try (Stream<Path> walk = Files.walk(path)) {
|
||||
walk.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
// .peek(System.out::println)
|
||||
.forEach(f -> {
|
||||
logger.debug("deleting '" + f.toString() + "'");
|
||||
if (!f.delete()) {
|
||||
throw new RuntimeException("Unable to delete " + f.toString());
|
||||
};
|
||||
});
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public final static class FileInfo {
|
||||
private final Path path;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user