Create three panel view (#26)

* Create three panel view
This commit is contained in:
Jonas Plum
2022-01-20 10:08:37 +01:00
committed by GitHub
parent a152b6663b
commit 8e8a7ec2a2
9 changed files with 184 additions and 92 deletions

View File

@@ -31,6 +31,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"luxon": "^1.27.0", "luxon": "^1.27.0",
"register-service-worker": "^1.7.2", "register-service-worker": "^1.7.2",
"splitpanes": "^2.3.8",
"swagger-ui": "^3.50.0", "swagger-ui": "^3.50.0",
"vue": "2.6.14", "vue": "2.6.14",
"vue-axios": "^3.2.4", "vue-axios": "^3.2.4",

View File

@@ -148,6 +148,7 @@
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from "vue";
import AppLink from "./components/AppLink.vue"; import AppLink from "./components/AppLink.vue";
import router from "vue-router";
export default Vue.extend({ export default Vue.extend({
name: "App", name: "App",
@@ -164,7 +165,7 @@ export default Vue.extend({
{ icon: "mdi-cogs", name: "User Data", to: "UserDataList", role: "admin:userdata:write" }, { icon: "mdi-cogs", name: "User Data", to: "UserDataList", role: "admin:userdata:write" },
{ icon: "mdi-format-list-checks", name: "Jobs", to: "JobList", role: "admin:job:write" }, { icon: "mdi-format-list-checks", name: "Jobs", to: "JobList", role: "admin:job:write" },
], ],
mini: false, mini: true,
goto: "", goto: "",
snackbar: false, snackbar: false,
@@ -214,11 +215,12 @@ export default Vue.extend({
} }
this.$router.push({ this.$router.push({
name: "Ticket", name: "Ticket",
params: { id: this.goto.toString(), type: "-" } params: { id: this.goto.toString() }
}); });
}, },
openTicketList: function (type: string) { openTicketList: function (type: string) {
this.$router.push({ name: "TicketList", params: { type: type } }) (this.$router as any).history.current = router.START_LOCATION;
this.$router.push({ name: "TicketList", params: { type: type } });
}, },
hasRole: function (s: string) { hasRole: function (s: string) {
if (this.$store.state.user.roles) { if (this.$store.state.user.roles) {

View File

@@ -1,13 +1,28 @@
<template> <template>
<v-container> <div>
<v-row v-if="type"> <v-row v-if="type" class="mx-0 my-2" dense>
<v-col cols="12"> <v-col :cols="this.$route.params.id ? 4 : 2">
<v-btn elevation="0" rounded class="float-right" :to="{ name: 'TicketNew', params: { type: type } }"> <v-select
v-model="selectedtype"
:items="tickettypes"
item-text="name"
item-value="id"
solo
rounded
label="Type"
dense
flat
hide-details
height="48px"></v-select>
</v-col>
<v-col :cols="this.$route.params.id ? 8 : 10">
<v-btn elevation="0" rounded class="float-right mb-2" @click="opennew({ name: 'Ticket', params: { type: type, id: 'new' } })">
<v-icon class="mr-1">mdi-plus</v-icon> <v-icon class="mr-1">mdi-plus</v-icon>
New {{ type | capitalize }} New {{ type | capitalize }}
</v-btn> </v-btn>
</v-col> </v-col>
</v-row> </v-row>
<v-toolbar <v-toolbar
rounded rounded
filled filled
@@ -76,22 +91,26 @@
> >
<template v-slot:item="{ item }"> <template v-slot:item="{ item }">
<tr @click="open(item)"> <tr @click="open(item)">
<td colspan="5"> <td colspan="5" class="pa-0">
<ticketSnippet :ticket="item" class="pa-0"></ticketSnippet> <!--ticketSnippet :ticket="item" class="pa-0"></ticketSnippet-->
<v-list-item :to="{ name: 'Ticket', params: { type: item.type, id: item.id } }" class="pa-0" style="background: none">
<ticketSnippet :ticket="item"></ticketSnippet>
</v-list-item>
</td> </td>
</tr> </tr>
</template> </template>
</v-data-table> </v-data-table>
</v-container> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from "vue";
import { Ticket } from "@/client"; import { Ticket, TicketType } from "@/client";
import { API } from "@/services/api"; import { API } from "@/services/api";
import TicketSnippet from "../components/snippets/TicketSnippet.vue"; import TicketSnippet from "../components/snippets/TicketSnippet.vue";
import {validateCAQL} from "@/suggestions/suggestions"; import {validateCAQL} from "@/suggestions/suggestions";
import {DateTime} from "luxon"; import {DateTime} from "luxon";
import router from "vue-router";
interface State { interface State {
term: string; term: string;
@@ -111,6 +130,9 @@ interface State {
focus: boolean; focus: boolean;
caql: boolean; caql: boolean;
defaultcaql?: number; defaultcaql?: number;
tickettypes: Array<TicketType>;
selectedtype: string;
} }
interface QuerySuggestion { interface QuerySuggestion {
@@ -135,6 +157,9 @@ export default Vue.extend({
focus: false, focus: false,
caql: true, caql: true,
defaultcaql: 0, defaultcaql: 0,
tickettypes: [],
selectedtype: "",
}), }),
computed: { computed: {
fields(): Array<string> { fields(): Array<string> {
@@ -211,7 +236,13 @@ export default Vue.extend({
}, },
deep: true, deep: true,
}, },
selectedtype: function () {
// this.type = this.selectedtype;
(this.$router as any).history.current = router.START_LOCATION;
this.$router.push({ name: "TicketList", params: { type: this.selectedtype } });
},
$route: function () { $route: function () {
this.selectedtype = this.type;
this.loadTickets(); this.loadTickets();
}, },
}, },
@@ -228,6 +259,11 @@ export default Vue.extend({
open: function (ticket: Ticket) { open: function (ticket: Ticket) {
this.$emit("click", ticket); this.$emit("click", ticket);
}, },
opennew: function (to) {
this.$router.push(to).then(() => {
this.$emit("new");
})
},
select: function (e: string) { select: function (e: string) {
this.loadTerm(e); this.loadTerm(e);
}, },
@@ -238,6 +274,11 @@ export default Vue.extend({
} }
this.loadTerm(term); this.loadTerm(term);
}, },
loadTicketTypes() {
API.listTicketTypes().then((reponse) => {
this.tickettypes = reponse.data;
})
},
loadTerm(term: string) { loadTerm(term: string) {
this.loading = true; this.loading = true;
let offset = 0; let offset = 0;
@@ -257,16 +298,16 @@ export default Vue.extend({
sortDesc = this.options.sortDesc; sortDesc = this.options.sortDesc;
} }
let t = this.type; let ticketType = this.type;
if (!t) { if (!ticketType) {
t = ""; ticketType = "";
} }
if (!this.caql && this.term.length > 0) { if (!this.caql && term.length > 0) {
term = "'" + this.lodash.join(this.lodash.split(term, " "), "'&&'") + "'" term = "'" + this.lodash.join(this.lodash.split(term, " "), "'&&'") + "'"
} }
API.listTickets(t, offset, count, sortBy, sortDesc, term) API.listTickets(ticketType, offset, count, sortBy, sortDesc, term)
.then((response) => { .then((response) => {
if (response.data.tickets) { if (response.data.tickets) {
this.tickets = response.data.tickets; this.tickets = response.data.tickets;
@@ -303,6 +344,8 @@ export default Vue.extend({
this.term = this.query; this.term = this.query;
} }
this.selectedtype = this.type;
this.loadTicketTypes();
this.loadTickets(); this.loadTickets();
}, },
}); });

View File

@@ -2,7 +2,6 @@ import Vue from "vue";
import VueRouter, { RouteConfig, RawLocation, Route } from "vue-router"; import VueRouter, { RouteConfig, RawLocation, Route } from "vue-router";
import ArtifactPopup from "../views/ArtifactPopup.vue"; import ArtifactPopup from "../views/ArtifactPopup.vue";
import Ticket from "../views/Ticket.vue"; import Ticket from "../views/Ticket.vue";
import TicketNew from "../views/TicketNew.vue";
import TicketList from "../views/TicketList.vue"; import TicketList from "../views/TicketList.vue";
import Graph from "../views/Graph.vue"; import Graph from "../views/Graph.vue";
import Playbook from "../views/Playbook.vue"; import Playbook from "../views/Playbook.vue";
@@ -74,28 +73,19 @@ const routes: Array<RouteConfig> = [
{ {
path: "/tickets", path: "/tickets",
name: "TicketListAll", name: "TicketList",
component: TicketList, component: TicketList,
meta: { title: "Tickets" }, meta: { title: "Tickets" },
props: true, props: true,
}, children: [
{ {
path: "/tickets/:type", path: ":id",
name: "TicketList",
component: TicketList,
props: true,
},
{
path: "/tickets/:type?/:id",
name: "Ticket", name: "Ticket",
component: Ticket, component: Ticket,
}
]
}, },
{
path: "/tickets/:type/new",
name: "TicketNew",
meta: { title: "New Ticket" },
component: TicketNew,
},
{ {
path: "/tickets/:type?/:id/artifact/:artifact", path: "/tickets/:type?/:id/artifact/:artifact",
name: "ArtifactPopup", name: "ArtifactPopup",

View File

@@ -20,3 +20,4 @@ declare module 'graphlib';
declare module 'ant-design-vue/es/_util/antInputDirective'; declare module 'ant-design-vue/es/_util/antInputDirective';
declare module 'flat'; declare module 'flat';
declare module 'crypto'; declare module 'crypto';
declare module 'splitpanes';

View File

@@ -1,6 +1,9 @@
<template> <template>
<v-main> <div>
<div v-if="ticket === undefined" class="text-sm-center py-16"> <div v-if="$route.params.id === 'new'">
<TicketNew></TicketNew>
</div>
<div v-else-if="ticket === undefined" class="text-sm-center py-16">
<v-progress-circular <v-progress-circular
indeterminate indeterminate
color="primary" color="primary"
@@ -10,7 +13,7 @@
> >
</v-progress-circular> </v-progress-circular>
</div> </div>
<v-container v-else> <div v-else>
<!--v-row-- class="mt-5"> <!--v-row-- class="mt-5">
<v-col> <v-col>
<div style="display: flex; justify-content: flex-end" class="pb-1"> <div style="display: flex; justify-content: flex-end" class="pb-1">
@@ -26,7 +29,7 @@
</v-col> </v-col>
</v-row--> </v-row-->
<v-row class="mt-2"> <v-row class="mt-2">
<v-col cols="8"> <v-col cols="12" lg="8">
<h1 class="d-flex"> <h1 class="d-flex">
<v-menu offset-y> <v-menu offset-y>
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
@@ -222,7 +225,7 @@
</div> </div>
</div> </div>
</v-col> </v-col>
<v-col cols="4"> <v-col cols="12" lg="4" >
<v-btn <v-btn
v-if="$store.state.settings.tier === 'enterprise'" v-if="$store.state.settings.tier === 'enterprise'"
:to="{ name: 'Graph', params: { col: 'tickets', id: ticket.id } }" :to="{ name: 'Graph', params: { col: 'tickets', id: ticket.id } }"
@@ -775,8 +778,8 @@
</v-dialog> </v-dialog>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </div>
</v-main> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
@@ -799,7 +802,7 @@ import {
Type, Type,
TypeColorEnum, TypeColorEnum,
TaskResponse, PlaybookResponse, UserResponse, TaskTypeEnum, TicketWithTickets, TaskResponse, PlaybookResponse, UserResponse, TaskTypeEnum, TicketWithTickets,
} from "../client"; } from "@/client";
import {API} from "@/services/api"; import {API} from "@/services/api";
import {Dashboard} from "@uppy/vue"; import {Dashboard} from "@uppy/vue";
@@ -813,6 +816,7 @@ import {AxiosError, AxiosResponse} from "axios";
import {DateTime} from "luxon"; import {DateTime} from "luxon";
import VueMarkdown from "vue-markdown"; import VueMarkdown from "vue-markdown";
import JSONHTML from "../components/JSONHTML.vue"; import JSONHTML from "../components/JSONHTML.vue";
import TicketNew from "@/views/TicketNew.vue";
interface State { interface State {
valid: boolean; valid: boolean;
@@ -879,6 +883,7 @@ interface TaskWithID {
export default Vue.extend({ export default Vue.extend({
name: "Ticket", name: "Ticket",
components: { components: {
TicketNew,
Dashboard, Dashboard,
ArtifactSnippet, ArtifactSnippet,
TicketSnippet, TicketSnippet,
@@ -1533,6 +1538,10 @@ export default Vue.extend({
} }
}, },
mounted() { mounted() {
if (this.$route.params.id === 'new') {
return
}
this.loadTicket(); this.loadTicket();
API.listUsers().then(response => { API.listUsers().then(response => {
this.users = response.data; this.users = response.data;

View File

@@ -1,30 +1,77 @@
<template> <template>
<v-main> <v-main style="min-height: 100vh">
<TicketListComponent :type="this.$route.params.type" :query="query" @click="open"></TicketListComponent> <splitpanes class="default-theme" @resize="paneSize = $event[0].size">
<pane class="pa-3" :size="paneSize">
<TicketListComponent :type="$route.params.type" :query="query" @click="open" @new="opennew"></TicketListComponent>
</pane>
<pane v-if="this.$route.params.id" class="pa-3" :size="100 - paneSize">
<v-row>
<v-spacer></v-spacer>
<v-btn @click="close" outlined rounded class="mt-3 mr-3">
<v-icon>mdi-close</v-icon>
Close
</v-btn>
</v-row>
<router-view></router-view>
</pane>
</splitpanes>
</v-main> </v-main>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from "vue";
import {TicketResponse} from "@/client"; import {TicketResponse} from "@/client";
import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import TicketListComponent from "../components/TicketList.vue"; import TicketListComponent from "../components/TicketList.vue";
export default Vue.extend({ export default Vue.extend({
name: "TicketList", name: "TicketList",
components: {TicketListComponent}, components: {
props: ['query'], TicketListComponent,
Splitpanes, Pane,
},
props: ['query', 'type'],
data: () => ({
paneSize: 30,
}),
methods: { methods: {
numeric: function (n: any): boolean {
return !isNaN(parseFloat(n)) && !isNaN(n - 0);
},
open: function (ticket: TicketResponse) { open: function (ticket: TicketResponse) {
if (ticket.id === undefined) {
return;
}
this.$router.push({ this.$router.push({
name: "Ticket", name: "Ticket",
params: {type: this.$route.params.type, id: ticket.id.toString()} params: {type: this.$route.params.type, id: ticket.id.toString()}
}).then(() => {
this.paneSize = 30;
}); });
},
opennew: function () {
this.paneSize = 30;
},
close: function () {
this.$router.push({
name: "TicketList",
params: {type: this.$route.params.type},
}).then(() => {
this.paneSize = 100;
});
},
hidelist: function () {
this.paneSize = 0;
} }
} }
}); });
</script> </script>
<style lang="scss">
.splitpanes.default-theme .splitpanes__pane {
background: none;
}
.splitpanes.default-theme .splitpanes__splitter {
background: none;
border: none;
}
</style>

View File

@@ -1,9 +1,6 @@
<template> <template>
<v-main> <div class="mt-8">
<v-container> <h2>New {{ $route.params.type | capitalize }}</h2>
<v-card color="cards">
<v-card-title>New {{ $route.params.type | capitalize }}</v-card-title>
<v-card-text>
<v-form class="create clearfix"> <v-form class="create clearfix">
<v-text-field label="Title" v-model="name"></v-text-field> <v-text-field label="Title" v-model="name"></v-text-field>
@@ -39,10 +36,7 @@
Create Create
</v-btn> </v-btn>
</v-form> </v-form>
</v-card-text> </div>
</v-card>
</v-container>
</v-main>
</template> </template>
<script lang="ts"> <script lang="ts">
@@ -54,7 +48,7 @@ import {
TicketForm, TicketForm,
TicketTemplateResponse, TicketTemplateResponse,
TicketType TicketType
} from "../client"; } from "@/client";
import { API } from "@/services/api"; import { API } from "@/services/api";
interface State { interface State {

View File

@@ -11207,6 +11207,11 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies: dependencies:
extend-shallow "^3.0.0" extend-shallow "^3.0.0"
splitpanes@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/splitpanes/-/splitpanes-2.3.8.tgz#371655e5c8c6356d76bbf2f6f22d5564927b5bb4"
integrity sha512-eM/qZ1v7U5BMV8FQR7oeqVlllz3sTGTm0//g/eJMa0hZ4s+A1VK68j26FWzcaVlw2P5+dCXk7/X6ZRjjwcbrgw==
sprintf-js@~1.0.2: sprintf-js@~1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"