mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
incremental work on NBUI
This commit is contained in:
parent
50c1cd2a1d
commit
69dbd0a6ed
@ -5,11 +5,6 @@
|
|||||||
<v-btn to="/ui/run/" title="Run a workload">Run</v-btn>
|
<v-btn to="/ui/run/" title="Run a workload">Run</v-btn>
|
||||||
<v-btn to="/ui/watch/" title="Watch workload status">Watch</v-btn>
|
<v-btn to="/ui/watch/" title="Watch workload status">Watch</v-btn>
|
||||||
<v-btn to="/docs/" title="Documentation">Docs</v-btn>
|
<v-btn to="/docs/" title="Documentation">Docs</v-btn>
|
||||||
<v-btn
|
|
||||||
title="Give us your feedback!"
|
|
||||||
href="https://github.com/nosqlbench/nosqlbench/wiki/Submitting-Feedback">
|
|
||||||
<v-icon>mdi-lightbulb-on-outline</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,11 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app-bar app fluid>
|
<v-app-bar app fluid>
|
||||||
<!-- <v-app-bar app dark fluid dense flat>-->
|
<!-- <v-app-bar app dark fluid dense flat>-->
|
||||||
<v-toolbar-title><slot></slot></v-toolbar-title>
|
<v-toolbar-title>
|
||||||
|
<slot></slot>
|
||||||
|
</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-toolbar-items>
|
<v-toolbar-items>
|
||||||
<app-selector></app-selector>
|
<app-selector></app-selector>
|
||||||
<workspace-selector></workspace-selector>
|
<workspace-selector></workspace-selector>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-btn icon large
|
||||||
|
title="Give us your feedback!"
|
||||||
|
href="https://github.com/nosqlbench/nosqlbench/wiki/Submitting-Feedback">
|
||||||
|
<v-icon>mdi-lightbulb-on-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
</v-toolbar-items>
|
</v-toolbar-items>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
<div class="markdown-body" v-html="rendered"></div>
|
<div class="markdown-body" v-html="rendered"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!--previously: https://github.com/ravenq/markdown-it-vue/blob/master/src/markdown-it-vue.vue-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import "markdown-it"
|
import "markdown-it"
|
||||||
import "markdown-it-imsize"
|
import "markdown-it-imsize"
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
v-model="new_workspace"
|
v-model="new_workspace"
|
||||||
ref="new_workspace_input"
|
ref="new_workspace_input"
|
||||||
hint="workspace name"
|
hint="workspace name"
|
||||||
@blur="commitWorkspace(new_workspace)"
|
@blur="initializeWorkspace(new_workspace)"
|
||||||
@keydown.enter="commitWorkspace(new_workspace)"
|
@keydown.enter="initializeWorkspace(new_workspace)"
|
||||||
@keydown.esc="cancelWorkspace()"
|
@keydown.esc="cancelWorkspace()"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
<!-- label="workspace"-->
|
<!-- label="workspace"-->
|
||||||
@ -77,7 +77,7 @@ export default {
|
|||||||
this.$refs.new_workspace_input.focus();
|
this.$refs.new_workspace_input.focus();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
commitWorkspace: function ({$store}) {
|
initializeWorkspace: function ({$store}) {
|
||||||
// console.log("commit:" + JSON.stringify(this.new_workspace));
|
// console.log("commit:" + JSON.stringify(this.new_workspace));
|
||||||
this.$store.dispatch("workspaces/activateWorkspace", this.new_workspace);
|
this.$store.dispatch("workspaces/activateWorkspace", this.new_workspace);
|
||||||
this.new_workspace = "";
|
this.new_workspace = "";
|
||||||
|
@ -114,36 +114,27 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style scoped>
|
||||||
.container {
|
/*.title {*/
|
||||||
min-height: 60vh;
|
/* font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,*/
|
||||||
display: flex;
|
/* 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;*/
|
||||||
justify-content: flex-start;
|
/* display: block;*/
|
||||||
align-items: flex-start;
|
/* font-weight: 300;*/
|
||||||
text-align: start;
|
/* font-size: 100px;*/
|
||||||
margin: 0 auto 0 15px;
|
/* color: #35495e;*/
|
||||||
}
|
/* letter-spacing: 1px;*/
|
||||||
|
/*}*/
|
||||||
|
|
||||||
.title {
|
/*.subtitle {*/
|
||||||
font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
|
/* font-weight: 300;*/
|
||||||
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
/* font-size: 42px;*/
|
||||||
display: block;
|
/* color: #526488;*/
|
||||||
font-weight: 300;
|
/* word-spacing: 5px;*/
|
||||||
font-size: 100px;
|
/* padding-bottom: 15px;*/
|
||||||
color: #35495e;
|
/*}*/
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
/*.links {*/
|
||||||
font-weight: 300;
|
/* padding-top: 15px;*/
|
||||||
font-size: 42px;
|
/*}*/
|
||||||
color: #526488;
|
|
||||||
word-spacing: 5px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.links {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -1,52 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app>
|
<v-app>
|
||||||
<main-app-bar>NoSQLBench - Workload Builder</main-app-bar>
|
<main-app-bar>NoSQLBench - Workload Builder</main-app-bar>
|
||||||
|
|
||||||
<v-layout>
|
|
||||||
|
|
||||||
|
<v-row>
|
||||||
<v-main>
|
<v-main>
|
||||||
<v-container fluid>
|
<v-container fluid>
|
||||||
<v-layout row>
|
<v-row>
|
||||||
<v-flex>
|
<v-alert
|
||||||
<v-card>
|
v-if="!enabled"
|
||||||
<v-card-title>
|
>This component is not online. This is only a preview. To use this, you must be running a local instance of NoSQLBench in appserver mode.</v-alert>
|
||||||
Workload details
|
</v-row>
|
||||||
</v-card-title>
|
|
||||||
<v-col
|
|
||||||
cols="12"
|
|
||||||
sm="6"
|
|
||||||
md="10"
|
|
||||||
lg="10"
|
|
||||||
>
|
|
||||||
<v-text-field
|
|
||||||
outlined
|
|
||||||
label="Workload name"
|
|
||||||
v-model="workloadName"
|
|
||||||
></v-text-field>
|
|
||||||
|
|
||||||
<v-textarea
|
<v-row class="d-flex justify-center">
|
||||||
outlined
|
<v-btn
|
||||||
label="Create Table Statement"
|
:disabled="buildmode==='cql'"
|
||||||
v-model="createTableDef"
|
title="Build CQL workload from schema"
|
||||||
v-on:blur="parseStatement()"
|
@click="buildmode=(buildmode==='cql' ? null : 'cql')"
|
||||||
></v-textarea>
|
>CQL
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
</v-col>
|
<v-btn
|
||||||
|
:disabled="buildmode==='openapi'"
|
||||||
|
title="Build OpenAPI workload from OpenAPI spec"
|
||||||
|
@click="buildmode='openapi'"
|
||||||
|
>OpenAPI
|
||||||
|
</v-btn>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
<v-col cols="12">
|
<v-row row v-if="buildmode==='openapi'">
|
||||||
<v-btn :title="save_title" v-if="parseSuccess" v-on:click="saveWorkloadToWorkspace()">{{ save_button }}</v-btn>
|
<OpenApiBuilder></OpenApiBuilder>
|
||||||
<v-btn :title="dl_title" v-if="parseSuccess" v-on:click="downloadWorkload()">{{ dl_button }}</v-btn>
|
</v-row>
|
||||||
</v-col>
|
|
||||||
</v-card>
|
|
||||||
</v-flex>
|
|
||||||
|
|
||||||
</v-layout>
|
|
||||||
|
|
||||||
|
<v-row row v-if="buildmode==='cql'">
|
||||||
|
<CqlBuilder></CqlBuilder>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
</v-main>
|
</v-main>
|
||||||
</v-layout>
|
</v-row>
|
||||||
|
|
||||||
<v-footer app>
|
<v-footer app>
|
||||||
<span>© 2020</span>
|
<span>© 2020</span>
|
||||||
@ -55,222 +47,35 @@
|
|||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import antlr4 from "antlr4";
|
|
||||||
import {saveAs} from "file-saver";
|
|
||||||
import yamlDumper from "js-yaml";
|
|
||||||
import CQL3Parser from '@/antlr/CQL3Parser.js';
|
|
||||||
import CQL3Lexer from '@/antlr/CQL3Lexer.js';
|
|
||||||
import defaultYaml from 'assets/default.yaml';
|
|
||||||
import basictypes from 'assets/basictypes.yaml';
|
|
||||||
import WorkspaceSelector from "@/components/WorkspaceSelector";
|
import WorkspaceSelector from "@/components/WorkspaceSelector";
|
||||||
import AppSelector from "@/components/AppSelector";
|
import AppSelector from "@/components/AppSelector";
|
||||||
import MainAppBar from "@/components/MainAppBar";
|
import MainAppBar from "@/components/MainAppBar";
|
||||||
|
import CqlBuilder from "~/components/builders/CqlBuilder";
|
||||||
|
import OpenApiBuilder from "~/components/builders/OpenApiBuilder";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MainAppBar,
|
MainAppBar,
|
||||||
AppSelector,
|
AppSelector,
|
||||||
WorkspaceSelector
|
WorkspaceSelector,
|
||||||
|
CqlBuilder,
|
||||||
|
OpenApiBuilder
|
||||||
},
|
},
|
||||||
data(context) {
|
data(context) {
|
||||||
let data = {
|
let data = {
|
||||||
enabled: false,
|
buildmode: 'cql',
|
||||||
createTableDef: "",
|
|
||||||
workloadName: "",
|
|
||||||
parseSuccess: false,
|
|
||||||
blob: null,
|
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
computed: {
|
async asyncData({store}) {
|
||||||
save_button: function () {
|
await store.dispatch("service_status/loadEndpoints")
|
||||||
return "Save to workspace '" + this.$store.getters["workspaces/getWorkspace"] + "'";
|
return {
|
||||||
},
|
enabled: store.getters["service_status/getEnabled"]
|
||||||
dl_button: function () {
|
|
||||||
return "Download as " + this.filename;
|
|
||||||
},
|
|
||||||
dl_title: function () {
|
|
||||||
return "Click to download the workload as '" + this.filename + "'";
|
|
||||||
},
|
|
||||||
filename: function () {
|
|
||||||
return this.workloadName + ".yaml";
|
|
||||||
},
|
|
||||||
save_title: function () {
|
|
||||||
return "Click to save this workload in the '" + this.workspace + "' workspace, or change the workspace in the app bar first.\n"
|
|
||||||
},
|
|
||||||
workspace: function () {
|
|
||||||
return this.$store.getters["workspaces/getWorkspace"]
|
|
||||||
},
|
|
||||||
enabled: function () {
|
|
||||||
return this.$store.getters["service_status/getEndpoints"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
computed: {
|
||||||
async parseStatement() {
|
workspace: function () {
|
||||||
console.log(this.$data.createTableDef);
|
return this.$store.getters["workspaces/getWorkspace"]
|
||||||
|
|
||||||
const input = this.$data.createTableDef;
|
|
||||||
|
|
||||||
const chars = new antlr4.InputStream(input);
|
|
||||||
const lexer = new CQL3Lexer.CQL3Lexer(chars);
|
|
||||||
|
|
||||||
lexer.strictMode = false; // do not use js strictMode
|
|
||||||
|
|
||||||
const tokens = new antlr4.CommonTokenStream(lexer);
|
|
||||||
const parser = new CQL3Parser.CQL3Parser(tokens);
|
|
||||||
|
|
||||||
const context = parser.create_table_stmt();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const keyspaceName = context.table_name().keyspace_name().getChild(0).getText()
|
|
||||||
const tableName = context.table_name().table_name_noks().getChild(0).getText()
|
|
||||||
|
|
||||||
const columnDefinitions = context.column_definitions().column_definition();
|
|
||||||
|
|
||||||
let columns = [];
|
|
||||||
let partitionKeys = [];
|
|
||||||
let clusteringKeys = [];
|
|
||||||
columnDefinitions.forEach(columnDef => {
|
|
||||||
if (columnDef.column_name() != null) {
|
|
||||||
columns.push({
|
|
||||||
"name": columnDef.column_name().getText(),
|
|
||||||
"type": columnDef.column_type().getText()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const primaryKeyContext = columnDef.primary_key()
|
|
||||||
if (primaryKeyContext.partition_key() != null) {
|
|
||||||
const partitionKeysContext = primaryKeyContext.partition_key().column_name();
|
|
||||||
partitionKeysContext.map((partitionKey, i) => {
|
|
||||||
const partitionKeyName = partitionKey.getText()
|
|
||||||
const col = {
|
|
||||||
"name": partitionKeyName,
|
|
||||||
"type": columns.filter(x => x.name == partitionKeyName)[0].type
|
|
||||||
}
|
|
||||||
partitionKeys.push(col)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (primaryKeyContext.clustering_column().length != 0) {
|
|
||||||
const clusteringKeysContext = primaryKeyContext.clustering_column();
|
|
||||||
clusteringKeysContext.map((clusteringKey, i) => {
|
|
||||||
const clusteringKeyName = clusteringKey.getText()
|
|
||||||
const col = {
|
|
||||||
"name": clusteringKeyName,
|
|
||||||
"type": columns.filter(x => x.name == clusteringKeyName)[0].type
|
|
||||||
}
|
|
||||||
clusteringKeys.push(col)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
columns = columns.filter(col => {
|
|
||||||
return partitionKeys.filter(pk => pk.name == col.name).length == 0 && clusteringKeys.filter(cc => cc.name == col.name).length == 0
|
|
||||||
})
|
|
||||||
|
|
||||||
const allColumns = [].concat(columns, partitionKeys, clusteringKeys)
|
|
||||||
|
|
||||||
this.$data.tableName = tableName;
|
|
||||||
this.$data.keyspaceName = keyspaceName;
|
|
||||||
this.$data.columns = columns;
|
|
||||||
this.$data.clusteringKeys = clusteringKeys;
|
|
||||||
this.$data.partitionKeys = partitionKeys;
|
|
||||||
this.$data.allColumns = allColumns;
|
|
||||||
|
|
||||||
console.log(this.$data)
|
|
||||||
|
|
||||||
console.log(defaultYaml)
|
|
||||||
|
|
||||||
// schema and bindings
|
|
||||||
let createTableStatement = "CREATE TABLE IF NOT EXISTS <<keyspace:" + keyspaceName + ">>." + tableName + " (\n";
|
|
||||||
|
|
||||||
console.log(basictypes)
|
|
||||||
defaultYaml.bindings = {}
|
|
||||||
allColumns.forEach(column => {
|
|
||||||
let recipe = basictypes.bindings[column.type + "val"];
|
|
||||||
if (recipe == undefined) {
|
|
||||||
const chars = new antlr4.InputStream(column.type);
|
|
||||||
const lexer = new CQL3Lexer.CQL3Lexer(chars);
|
|
||||||
lexer.strictMode = false; // do not use js strictMode
|
|
||||||
const tokens = new antlr4.CommonTokenStream(lexer);
|
|
||||||
const parser = new CQL3Parser.CQL3Parser(tokens);
|
|
||||||
|
|
||||||
const typeContext = parser.column_type();
|
|
||||||
const collectionTypeContext = typeContext.data_type().collection_type();
|
|
||||||
const collectionType = collectionTypeContext.children[0].getText();
|
|
||||||
if (collectionType.toLowerCase() == "set") {
|
|
||||||
const type = collectionTypeContext.children[2].getText();
|
|
||||||
recipe = "Set(HashRange(1,<<set-count-" + column.name + ":5>>)," + basictypes.bindings[type + "val"] + ") -> java.util.Set"
|
|
||||||
} else if (collectionType.toLowerCase() == "list") {
|
|
||||||
const type = collectionTypeContext.children[2].getText();
|
|
||||||
recipe = "List(HashRange(1,<<list-count-" + column.name + ":5>>)," + basictypes.bindings[type + "val"] + ") -> java.util.List"
|
|
||||||
|
|
||||||
} else if (collectionType.toLowerCase() == "map") {
|
|
||||||
const type1 = collectionTypeContext.children[2].getText();
|
|
||||||
const type2 = collectionTypeContext.children[4].getText();
|
|
||||||
recipe = "Map(HashRange(1,<<map-count-" + column.name + ":5>>)," + basictypes.bindings[type1 + "val"] + "," + basictypes.bindings[type2 + "val"] + ") -> java.util.Map"
|
|
||||||
} else {
|
|
||||||
alert("Could not generate recipe for type: " + column.type + " for column: " + column.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defaultYaml.bindings[column.name] = recipe
|
|
||||||
createTableStatement = createTableStatement + column.name + " " + column.type + ",\n";
|
|
||||||
})
|
|
||||||
|
|
||||||
let pk = "PRIMARY KEY (("
|
|
||||||
pk = pk + partitionKeys.map(x => x.name).reduce((x, acc) => acc = acc + "," + x)
|
|
||||||
pk = pk + ")"
|
|
||||||
if (clusteringKeys.length > 0) {
|
|
||||||
pk = pk + "," + clusteringKeys.map(x => x.name).reduce((x, acc) => acc = acc + "," + x)
|
|
||||||
}
|
|
||||||
pk = pk + ")"
|
|
||||||
createTableStatement = createTableStatement + pk + "\n);"
|
|
||||||
defaultYaml.blocks[0].statements[0] = {"create-table": createTableStatement}
|
|
||||||
|
|
||||||
//rampup
|
|
||||||
let insertStatement = "INSERT INTO <<keyspace:" + keyspaceName + ">>." + tableName + " (\n";
|
|
||||||
insertStatement = insertStatement + allColumns.map(x => x.name).reduce((x, acc) => acc = acc + ",\n" + x) + "\n) VALUES (\n";
|
|
||||||
insertStatement = insertStatement + allColumns.map(x => "{" + x.name + "}").reduce((x, acc) => acc = acc + ",\n" + x) + "\n);"
|
|
||||||
|
|
||||||
defaultYaml.blocks[1].statements[0] = {"insert-rampup": insertStatement}
|
|
||||||
|
|
||||||
//main-write
|
|
||||||
defaultYaml.blocks[2].statements[0] = {"insert-main": insertStatement}
|
|
||||||
|
|
||||||
//main-read-partition
|
|
||||||
let readPartitionStatement = "SELECT * from <<keyspace:" + keyspaceName + ">>." + tableName + " WHERE ";
|
|
||||||
readPartitionStatement = readPartitionStatement + partitionKeys.map(x => x.name + "={" + x.name + "}").reduce((x, acc) => acc = acc + " AND " + x);
|
|
||||||
let readRowStatement = readPartitionStatement + ";";
|
|
||||||
if (clusteringKeys.length > 0) {
|
|
||||||
readPartitionStatement = readPartitionStatement + " AND " + clusteringKeys.map(x => x.name + "={" + x.name + "}").reduce((x, acc) => acc = acc + " AND " + x);
|
|
||||||
}
|
|
||||||
readPartitionStatement = readPartitionStatement + ";";
|
|
||||||
|
|
||||||
defaultYaml.blocks[3].statements[0] = {"read-partition": readPartitionStatement}
|
|
||||||
|
|
||||||
//main-read-row
|
|
||||||
defaultYaml.blocks[4].statements[0] = {"read-row": readRowStatement}
|
|
||||||
|
|
||||||
defaultYaml.description = this.$data.workloadName
|
|
||||||
|
|
||||||
const yamlOutputText = yamlDumper.dump(defaultYaml)
|
|
||||||
this.blob = new Blob([yamlOutputText], {type: "text/plain;charset=utf-8"});
|
|
||||||
this.parseSuccess = true;
|
|
||||||
} catch (e) {
|
|
||||||
console.log("blur, invalid create table def")
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
downloadWorkload() {
|
|
||||||
saveAs(this.blob, this.$data.filename);
|
|
||||||
},
|
|
||||||
saveWorkloadToWorkspace() {
|
|
||||||
this.$store.dispatch("workspaces/putFile",{
|
|
||||||
workspace: this.workspace,
|
|
||||||
filename: this.filename,
|
|
||||||
content: this.blob
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -279,33 +84,4 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
/*.container {*/
|
|
||||||
/* margin: 0 auto;*/
|
|
||||||
/* display: flex;*/
|
|
||||||
/* justify-content: center;*/
|
|
||||||
/* align-items: center;*/
|
|
||||||
/* text-align: center;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*.title {*/
|
|
||||||
/* font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,*/
|
|
||||||
/* 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;*/
|
|
||||||
/* display: block;*/
|
|
||||||
/* font-weight: 300;*/
|
|
||||||
/* font-size: 100px;*/
|
|
||||||
/* color: #35495e;*/
|
|
||||||
/* letter-spacing: 1px;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*.subtitle {*/
|
|
||||||
/* font-weight: 300;*/
|
|
||||||
/* font-size: 42px;*/
|
|
||||||
/* color: #526488;*/
|
|
||||||
/* word-spacing: 5px;*/
|
|
||||||
/* padding-bottom: 15px;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*.links {*/
|
|
||||||
/* padding-top: 15px;*/
|
|
||||||
/*}*/
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -28,12 +28,10 @@
|
|||||||
|
|
||||||
<v-btn-toggle v-model="toggle_builtins" @change="validateAndSearch()">
|
<v-btn-toggle v-model="toggle_builtins" @change="validateAndSearch()">
|
||||||
<v-btn :disabled="this.toggle_workspaces===undefined">
|
<v-btn :disabled="this.toggle_workspaces===undefined">
|
||||||
<v-container fluid class="d-flex">
|
|
||||||
<v-icon title="include built-in workloads">mdi-folder-open</v-icon>
|
<v-icon title="include built-in workloads">mdi-folder-open</v-icon>
|
||||||
<div class="ma-2">bundled</div>
|
<div class="ma-2">bundled</div>
|
||||||
<v-icon v-if="this.toggle_builtins===0">mdi-check</v-icon>
|
<v-icon v-if="this.toggle_builtins===0">mdi-check</v-icon>
|
||||||
|
|
||||||
</v-container>
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-toggle>
|
</v-btn-toggle>
|
||||||
|
|
||||||
|
@ -3,31 +3,42 @@ import {mapGetters} from "vuex";
|
|||||||
import endpoints from "@/js/endpoints";
|
import endpoints from "@/js/endpoints";
|
||||||
|
|
||||||
export const state = () => ({
|
export const state = () => ({
|
||||||
endpoints: {},
|
endpoints: null,
|
||||||
enabled: false
|
enabled: null
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getEndpoints: (state, getters) => {
|
getEndpoints: (state, getters) => {
|
||||||
return state.endpoints;
|
return state.endpoints;
|
||||||
|
},
|
||||||
|
getEnabled: (state, getters) => {
|
||||||
|
return state.enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
setEndpoints(state, endpoints) {
|
setEndpoints(state, endpoints) {
|
||||||
state.endpoints = endpoints;
|
state.endpoints = endpoints;
|
||||||
|
},
|
||||||
|
setEnabled(state, enabled) {
|
||||||
|
state.enabled = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
async loadEndpoints(context, reason) {
|
async loadEndpoints(context, reason) {
|
||||||
console.log("loading endpoint status because '" + reason + "'")
|
let enabled = context.getters["getEnabled"]
|
||||||
await this.$axios.get(endpoints.url(document, context, "/services/status"))
|
if (enabled === null || enabled === undefined) {
|
||||||
.then(res => {
|
console.log("loading endpoint status because '" + reason + "'")
|
||||||
context.commit('setEndpoints', res)
|
await this.$axios.get(endpoints.url(document, context, "/services/status"))
|
||||||
})
|
.then(res => {
|
||||||
.catch((e) => {
|
context.commit('setEndpoints', res.data.endpoints)
|
||||||
console.error("axios/nuxt status async error:" + e);
|
context.commit('setEnabled', res.data.enabled)
|
||||||
})
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error("axios/nuxt status async error:" + e);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// else use cache defined status
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,8 @@ import endpoints from "@/js/endpoints";
|
|||||||
export const state = () => ({
|
export const state = () => ({
|
||||||
workspace: 'default',
|
workspace: 'default',
|
||||||
workspaces: [],
|
workspaces: [],
|
||||||
fileview: []
|
all_ws_files: [],
|
||||||
|
matching_ws_files: []
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
@ -15,8 +16,11 @@ export const getters = {
|
|||||||
getWorkspaces: (state, getters) => {
|
getWorkspaces: (state, getters) => {
|
||||||
return state.workspaces;
|
return state.workspaces;
|
||||||
},
|
},
|
||||||
getFileview: (state, getters) => {
|
getAllFiles: (state, getters) => {
|
||||||
return state.fileview;
|
return state.all_ws_files;
|
||||||
|
},
|
||||||
|
getMatchingFiles: (state, getters) => {
|
||||||
|
return state.matching_ws_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...mapGetters(['workspace','workspaces'])
|
// ...mapGetters(['workspace','workspaces'])
|
||||||
@ -29,21 +33,73 @@ export const mutations = {
|
|||||||
setWorkspaces(state, workspaces) {
|
setWorkspaces(state, workspaces) {
|
||||||
state.workspaces = workspaces;
|
state.workspaces = workspaces;
|
||||||
},
|
},
|
||||||
setFileview(state, fileview) {
|
setAllFiles(state, files) {
|
||||||
state.fileview = fileview;
|
state.all_ws_files = files;
|
||||||
|
},
|
||||||
|
setMatchingFiles(state, files) {
|
||||||
|
state.matching_ws_files = files;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
|
async importUrlToWorkspace(context, params) {
|
||||||
|
console.log("importUrlToWorkspace(ctx," + JSON.stringify(params, null, 2));
|
||||||
|
let workspace = params.workspace;
|
||||||
|
let import_url = params.import_url;
|
||||||
|
let import_as = params.import_as;
|
||||||
|
if (!workspace || !import_url || !import_as) {
|
||||||
|
throw("Unable to save file to workspace without params workspace, import_url, import_as");
|
||||||
|
}
|
||||||
|
this.$axios.$get(import_url)
|
||||||
|
.then(res => {
|
||||||
|
console.log('save url data:' + JSON.stringify(res, null, 2))
|
||||||
|
return res
|
||||||
|
}).then(data => {
|
||||||
|
context.dispatch("putFile", {
|
||||||
|
workspace: workspace,
|
||||||
|
filename: import_as,
|
||||||
|
content: data
|
||||||
|
}).catch((e) => {
|
||||||
|
throw "error while saving data:" + e
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
throw "axios/nuxt workspaces async error:" + e
|
||||||
|
})
|
||||||
|
},
|
||||||
async setWorkspace(context, val) {
|
async setWorkspace(context, val) {
|
||||||
// console.log("committing setWorkspace:" + JSON.stringify(val));
|
// console.log("committing setWorkspace:" + JSON.stringify(val));
|
||||||
context.commit('setWorkspace', val);
|
context.commit('setWorkspace', val);
|
||||||
|
await context.dispatch("listWorkspaceFiles", {wsname: val})
|
||||||
},
|
},
|
||||||
async setWorkspaces(context, val) {
|
async setWorkspaces(context, val) {
|
||||||
// console.log("committing setWorkspaces:" + JSON.stringify(val));
|
// console.log("committing setWorkspaces:" + JSON.stringify(val));
|
||||||
context.commit('setWorkspaces', val);
|
context.commit('setWorkspaces', val);
|
||||||
},
|
},
|
||||||
async initWorkspaces(context, reason) {
|
async listWorkspaceFiles(context, params) {
|
||||||
|
let wsname = params.wsname;
|
||||||
|
let contains = params.contains;
|
||||||
|
console.log("list params:" + JSON.stringify(params, null, 2))
|
||||||
|
|
||||||
|
let query = "?ls";
|
||||||
|
if (contains) {
|
||||||
|
query = query + "&contains=" + contains
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.$axios.$get(endpoints.url(document, context, "/services/workspaces/" + wsname) + query)
|
||||||
|
.then(res => {
|
||||||
|
console.log("ls ws:" + JSON.stringify(res, null, 2))
|
||||||
|
if (contains) {
|
||||||
|
context.commit("setContains", res["ls"]);
|
||||||
|
} else {
|
||||||
|
context.commit("setFileview", res["ls"])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
throw "axios/nuxt workspaces async error:" + e
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async loadWorkspaces(context, reason) {
|
||||||
// console.log("initializing workspaces because '" + reason + "'")
|
// console.log("initializing workspaces because '" + reason + "'")
|
||||||
this.$axios.$get(endpoints.url(document, context, "/services/workspaces/"))
|
this.$axios.$get(endpoints.url(document, context, "/services/workspaces/"))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -52,7 +108,7 @@ export const actions = {
|
|||||||
context.commit('setWorkspaces', res)
|
context.commit('setWorkspaces', res)
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("axios/nuxt workspaces async error:", e);
|
throw "axios/nuxt workspaces async error:" + e
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async putFile(context, params) {
|
async putFile(context, params) {
|
||||||
@ -60,25 +116,27 @@ export const actions = {
|
|||||||
let to_filename = params.filename;
|
let to_filename = params.filename;
|
||||||
let to_content = params.content;
|
let to_content = params.content;
|
||||||
if (!to_workspace || !to_filename || !to_content) {
|
if (!to_workspace || !to_filename || !to_content) {
|
||||||
|
console.log("params:" + JSON.stringify(params, null, 2))
|
||||||
throw("Unable to save file to workspace without params having workspace, filename, content");
|
throw("Unable to save file to workspace without params having workspace, filename, content");
|
||||||
}
|
}
|
||||||
const result = await this.$axios.$post(endpoints.url(document, context, "/services/workspaces/" + to_workspace + "/" + to_filename, to_content))
|
console.log("to_content:" + JSON.stringify(to_content, null, 2))
|
||||||
|
const result = await this.$axios.put(endpoints.url(document, context, "/services/workspaces/" + to_workspace + "/" + to_filename), to_content)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
console.log("axios/vuex workspace put:" + JSON.stringify(res));
|
console.log("axios/vuex workspace put:" + JSON.stringify(res));
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("axios/vuex workspace put:", e)
|
throw "axios/vuex workspace put:" + e
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async activateWorkspace(context, workspace) {
|
async initializeWorkspace(context, workspace) {
|
||||||
const fresh_workspace = await this.$axios.$get(endpoints.url(document, context, "/services/workspaces/" + workspace))
|
const fresh_workspace = await this.$axios.$get(endpoints.url(document, context, "/services/workspaces/" + workspace) + "?ls")
|
||||||
.then(res => {
|
.then(res => {
|
||||||
// console.log("axios/vuex workspace async get:" + JSON.stringify(res))
|
// console.log("axios/vuex workspace async get:" + JSON.stringify(res))
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("axios/nuxt getWorkspace async error:", e)
|
throw "axios/nuxt getWorkspace async error:" + e
|
||||||
})
|
})
|
||||||
await context.dispatch('initWorkspaces', "workspace '" + workspace + "' added");
|
await context.dispatch('initWorkspaces', "workspace '" + workspace + "' added");
|
||||||
// await dispatch.initWorkspaces({commit, state, dispatch}, "workspace '" + workspace + "' added")
|
// await dispatch.initWorkspaces({commit, state, dispatch}, "workspace '" + workspace + "' added")
|
||||||
@ -94,7 +152,7 @@ export const actions = {
|
|||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("axios/nuxt purgeWorkspace error:", e)
|
throw "axios/nuxt purgeWorkspace error:" + e
|
||||||
})
|
})
|
||||||
const found = this.state.workspaces.workspaces.find(w => w.name === workspace);
|
const found = this.state.workspaces.workspaces.find(w => w.name === workspace);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -16,6 +16,7 @@ import javax.ws.rs.core.*;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Path("/services/workspaces")
|
@Path("/services/workspaces")
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -79,7 +80,7 @@ public class WorkspacesEndpoint implements WebServiceObject {
|
|||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@PUT
|
||||||
@Path("/{workspaceName}/{filepath:.+}")
|
@Path("/{workspaceName}/{filepath:.+}")
|
||||||
@Consumes(MediaType.WILDCARD)
|
@Consumes(MediaType.WILDCARD)
|
||||||
@Produces(MediaType.WILDCARD)
|
@Produces(MediaType.WILDCARD)
|
||||||
@ -103,17 +104,20 @@ public class WorkspacesEndpoint implements WebServiceObject {
|
|||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response getWorkspaceInfo(
|
public Response getWorkspaceInfo(
|
||||||
@PathParam("workspace") String workspace,
|
@PathParam("workspace") String workspace,
|
||||||
@QueryParam("ls") String ls
|
@QueryParam("ls") String ls,
|
||||||
|
@QueryParam("contains") String contains
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
if (ls!=null && !ls.toLowerCase().equals("false")) {
|
WorkSpace ws = getSvc().getWorkspace(workspace);
|
||||||
WorkSpace ws = getSvc().getWorkspace(workspace);
|
WorkspaceView wsview = ws.getWorkspaceView();
|
||||||
|
if (ls != null && !ls.toLowerCase().equals("false")) {
|
||||||
List<WorkspaceItemView> listing = ws.getWorkspaceListingView("");
|
List<WorkspaceItemView> listing = ws.getWorkspaceListingView("");
|
||||||
return Response.ok(listing).build();
|
if (contains != null) {
|
||||||
} else {
|
listing = listing.stream().filter(i -> i.contains(contains)).collect(Collectors.toList());
|
||||||
WorkspaceView workpaceView = getSvc().getWorkspaceView(workspace);
|
}
|
||||||
return Response.ok(workpaceView).build();
|
wsview.setListing(listing);
|
||||||
}
|
}
|
||||||
|
return Response.ok(wsview).build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return Response.serverError().entity(e.getMessage()).build();
|
return Response.serverError().entity(e.getMessage()).build();
|
||||||
}
|
}
|
||||||
@ -128,7 +132,7 @@ public class WorkspacesEndpoint implements WebServiceObject {
|
|||||||
@QueryParam("ls") String ls) {
|
@QueryParam("ls") String ls) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (ls!=null && !ls.toLowerCase().equals("false")) {
|
if (ls != null && !ls.toLowerCase().equals("false")) {
|
||||||
WorkSpace ws = getSvc().getWorkspace(workspace);
|
WorkSpace ws = getSvc().getWorkspace(workspace);
|
||||||
List<WorkspaceItemView> listing = ws.getWorkspaceListingView(filename);
|
List<WorkspaceItemView> listing = ws.getWorkspaceListingView(filename);
|
||||||
return Response.ok(listing).build();
|
return Response.ok(listing).build();
|
||||||
|
@ -11,6 +11,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
import java.nio.file.SimpleFileVisitor;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class WorkspaceView {
|
public class WorkspaceView {
|
||||||
|
|
||||||
@ -25,6 +26,9 @@ public class WorkspaceView {
|
|||||||
private final Path workspaceRoot;
|
private final Path workspaceRoot;
|
||||||
private Summary summary;
|
private Summary summary;
|
||||||
|
|
||||||
|
@JsonProperty("ls")
|
||||||
|
private List<WorkspaceItemView> listing = null;
|
||||||
|
|
||||||
public WorkspaceView(Path workspaceRoot) {
|
public WorkspaceView(Path workspaceRoot) {
|
||||||
this.workspaceRoot = workspaceRoot;
|
this.workspaceRoot = workspaceRoot;
|
||||||
}
|
}
|
||||||
@ -56,13 +60,17 @@ public class WorkspaceView {
|
|||||||
return this.summary;
|
return this.summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setListing(List<WorkspaceItemView> listing) {
|
||||||
|
this.listing = listing;
|
||||||
|
}
|
||||||
|
|
||||||
public final static class Summary extends SimpleFileVisitor<Path> {
|
public final static class Summary extends SimpleFileVisitor<Path> {
|
||||||
|
|
||||||
private final Path root;
|
private final Path root;
|
||||||
|
|
||||||
public long total_bytes = 0L;
|
public long total_bytes = 0L;
|
||||||
public long total_files = 0L;
|
public long total_files = 0L;
|
||||||
public long last_changed_epoch =Long.MIN_VALUE;
|
public long last_changed_epoch = Long.MIN_VALUE;
|
||||||
public String last_changed_filename = "";
|
public String last_changed_filename = "";
|
||||||
|
|
||||||
public String getLast_changed_ago() {
|
public String getLast_changed_ago() {
|
||||||
|
Loading…
Reference in New Issue
Block a user