Skip to content

Commit 736488b

Browse files
committed
feat: Add pipeline debugging.
1 parent 3dc5b65 commit 736488b

File tree

14 files changed

+587
-121
lines changed

14 files changed

+587
-121
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<template>
2+
<list-page
3+
:icon="icon"
4+
title="Pipeline Event Log"
5+
loadingMessage="Loading event pipeline logs ..."
6+
:loaded="loaded"
7+
:results="results"
8+
@pagingUpdated="onPagingUpdated"
9+
>
10+
<v-flex xs12>
11+
<v-data-table
12+
class="log-table"
13+
:headers="headers"
14+
:items="matches"
15+
:hide-default-footer="true"
16+
no-data-text="No Event Pipeline Log Entries Found"
17+
>
18+
<template slot="item" slot-scope="props">
19+
<tr>
20+
<td :title="props.item.source">
21+
<span
22+
style="max-width: 150px"
23+
class="d-inline-block text-truncate"
24+
>{{ props.item.source }}</span
25+
>
26+
</td>
27+
<td :title="props.item.level">
28+
<span
29+
style="max-width: 150px"
30+
class="d-inline-block text-truncate"
31+
>{{ props.item.level }}</span
32+
>
33+
</td>
34+
<td :title="props.item.deviceToken">
35+
<span
36+
style="max-width: 300px"
37+
class="d-inline-block text-truncate"
38+
>{{ props.item.deviceToken }}</span
39+
>
40+
</td>
41+
<td :title="props.item.microservice">
42+
<span
43+
style="max-width: 200px"
44+
class="d-inline-block text-truncate"
45+
>{{ props.item.microservice }}</span
46+
>
47+
</td>
48+
<td width="40%" :title="props.item.message">
49+
{{ props.item.message }}
50+
</td>
51+
</tr>
52+
</template>
53+
</v-data-table>
54+
</v-flex>
55+
<template slot="actions">
56+
<delete-button tooltip="Clear Log" @action="onClearLog" />
57+
</template>
58+
<template slot="dialogs"> </template>
59+
</list-page>
60+
</template>
61+
62+
<script lang="ts">
63+
import { Component } from "vue-property-decorator";
64+
import {
65+
IPageSizes,
66+
ITableHeaders,
67+
NavigationIcon,
68+
listInstancePipelineLogEntries,
69+
deleteInstancePipelineLogEntries,
70+
formatDate,
71+
handleError,
72+
} from "sitewhere-ide-common";
73+
import { ListComponent, ListPage } from "sitewhere-ide-components";
74+
75+
import DeleteButton from "../common/navbuttons/DeleteButton.vue";
76+
77+
import { AxiosPromise } from "axios";
78+
79+
import {
80+
IEventPipelineLog,
81+
IEventPipelineLogSearchCriteria,
82+
IEventPipelineLogResponseFormat,
83+
IEventPipelineLogSearchResults,
84+
} from "sitewhere-rest-api";
85+
86+
@Component({
87+
components: {
88+
ListPage,
89+
DeleteButton,
90+
},
91+
})
92+
export default class EventPipelineLogging extends ListComponent<
93+
IEventPipelineLog,
94+
IEventPipelineLogSearchCriteria,
95+
IEventPipelineLogResponseFormat,
96+
IEventPipelineLogSearchResults
97+
> {
98+
headers: ITableHeaders = [
99+
{
100+
align: "left",
101+
sortable: false,
102+
text: "Source",
103+
value: "source",
104+
},
105+
{
106+
align: "left",
107+
sortable: false,
108+
text: "Level",
109+
value: "level",
110+
},
111+
{
112+
align: "left",
113+
sortable: false,
114+
text: "Device Token",
115+
value: "deviceToken",
116+
},
117+
{
118+
align: "left",
119+
sortable: false,
120+
text: "Microservice",
121+
value: "microservice",
122+
},
123+
{
124+
align: "left",
125+
sortable: false,
126+
text: "Message",
127+
value: "message",
128+
},
129+
];
130+
pageSizes: IPageSizes = [
131+
{
132+
text: "25",
133+
value: 25,
134+
},
135+
{
136+
text: "50",
137+
value: 50,
138+
},
139+
{
140+
text: "100",
141+
value: 100,
142+
},
143+
];
144+
145+
/** Get page icon */
146+
get icon(): NavigationIcon {
147+
return NavigationIcon.Device;
148+
}
149+
150+
/** Build search criteria for list */
151+
buildSearchCriteria(): IEventPipelineLogSearchCriteria {
152+
const criteria: IEventPipelineLogSearchCriteria = {};
153+
return criteria;
154+
}
155+
156+
/** Build response format for list */
157+
buildResponseFormat(): IEventPipelineLogResponseFormat {
158+
const format: IEventPipelineLogResponseFormat = {};
159+
return format;
160+
}
161+
162+
/** Perform search */
163+
performSearch(
164+
criteria: IEventPipelineLogSearchCriteria,
165+
format: IEventPipelineLogResponseFormat
166+
): AxiosPromise<IEventPipelineLogSearchResults> {
167+
const tenant = this.$store.getters.selectedTenant;
168+
return listInstancePipelineLogEntries(
169+
this.$store,
170+
tenant.token,
171+
criteria,
172+
format
173+
);
174+
}
175+
176+
/** Clear event pipeline log */
177+
onClearLog(): void {
178+
const tenant = this.$store.getters.selectedTenant;
179+
try {
180+
deleteInstancePipelineLogEntries(this.$store, tenant.token);
181+
this.refresh();
182+
} catch (err) {
183+
handleError(err);
184+
}
185+
}
186+
187+
// Format a date.
188+
format(date: Date) {
189+
formatDate(date);
190+
}
191+
}
192+
</script>
193+
194+
<style scoped>
195+
.log-table >>> td {
196+
font-size: 12px;
197+
height: 38px;
198+
}
199+
</style>

src/components/global/GlobalSettings.vue

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<template slot="tabs">
1818
<v-tab key="persistence">Persistence</v-tab>
1919
<v-tab key="infra">Infrastructure</v-tab>
20+
<v-tab key="debug">Debugging</v-tab>
2021
<v-tab key="json">JSON</v-tab>
2122
</template>
2223
<template slot="tab-items">
@@ -30,7 +31,15 @@
3031
:configuration="workingCopy"
3132
@updated="onInfrastructureUpdated"
3233
/>
33-
<instance-configuration-source tabkey="json" :configuration="workingCopy" />
34+
<debugging-editor
35+
tabkey="debug"
36+
:configuration="workingCopy"
37+
@updated="onDebuggingUpdated"
38+
/>
39+
<instance-configuration-source
40+
tabkey="json"
41+
:configuration="workingCopy"
42+
/>
3443
</template>
3544
<template slot="actions" />
3645
</detail-page>
@@ -44,12 +53,13 @@ import { Component, Watch } from "vue-property-decorator";
4453
import {
4554
NavigationIcon,
4655
getInstanceConfiguration,
47-
updateInstanceConfiguration
56+
updateInstanceConfiguration,
4857
} from "sitewhere-ide-common";
4958
import { DetailPage } from "sitewhere-ide-components";
5059
5160
import InfrastructureEditor from "./configuration/infrastructure/InfrastructureEditor.vue";
5261
import PersistenceConfigurationsEditor from "./configuration/persistence/PersistenceConfigurationsEditor.vue";
62+
import DebuggingEditor from "./configuration/debugging/DebuggingEditor.vue";
5363
import InstanceConfigurationSource from "./InstanceConfigurationSource.vue";
5464
import UnsavedUpdatesPanel from "./configuration/UnsavedUpdatesPanel.vue";
5565
@@ -60,9 +70,10 @@ import { IInstanceConfiguration } from "sitewhere-rest-api";
6070
DetailPage,
6171
InfrastructureEditor,
6272
PersistenceConfigurationsEditor,
73+
DebuggingEditor,
6374
InstanceConfigurationSource,
64-
UnsavedUpdatesPanel
65-
}
75+
UnsavedUpdatesPanel,
76+
},
6677
})
6778
export default class GlobalSettings extends Vue {
6879
configuration: IInstanceConfiguration | null = null;
@@ -105,6 +116,11 @@ export default class GlobalSettings extends Vue {
105116
this.checkDirty();
106117
}
107118
119+
/** Called when debugging settings are updated */
120+
onDebuggingUpdated(): void {
121+
this.checkDirty();
122+
}
123+
108124
/** Compares original with working copy for dirty check */
109125
checkDirty() {
110126
const orig: string = JSON.stringify(this.configuration);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<template>
2+
<instance-configuration-editor
3+
class="editor"
4+
:tabkey="tabkey"
5+
:configuration="configuration"
6+
header="Configure Global Debugging Settings"
7+
>
8+
<pipeline-debugging-section
9+
:configuration="configuration"
10+
@updated="onEventPipelineDebuggingUpdated"
11+
/>
12+
</instance-configuration-editor>
13+
</template>
14+
15+
<script lang="ts">
16+
import { Component, Prop } from "vue-property-decorator";
17+
18+
import Vue from "vue";
19+
import {
20+
IInstanceConfiguration,
21+
IEventPipelineDebugging,
22+
} from "sitewhere-rest-api";
23+
24+
import InstanceConfigurationEditor from "../InstanceConfigurationEditor.vue";
25+
import PipelineDebuggingSection from "./PipelineDebuggingSection.vue";
26+
27+
@Component({
28+
components: {
29+
InstanceConfigurationEditor,
30+
PipelineDebuggingSection,
31+
},
32+
})
33+
export default class DebuggingEditor extends Vue {
34+
@Prop() readonly tabkey!: string;
35+
@Prop() readonly configuration!: IInstanceConfiguration;
36+
37+
/** Called when event pipeline debugging values are updated. */
38+
onEventPipelineDebuggingUpdated(updated: IEventPipelineDebugging) {
39+
if (this.configuration) {
40+
this.configuration.debugging.eventPipeLine = updated;
41+
}
42+
this.$emit("updated");
43+
}
44+
}
45+
</script>
46+
47+
<style scoped>
48+
.editor {
49+
border-bottom: 1px solid #eee;
50+
}
51+
</style>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<template>
2+
<base-dialog
3+
ref="dialog"
4+
:icon="icon"
5+
title="Edit Pipeline Debugging Configuration"
6+
width="550"
7+
:loaded="true"
8+
:visible="dialogVisible"
9+
createLabel="Update"
10+
cancelLabel="Cancel"
11+
@createClicked="onUpdateClicked"
12+
@cancelClicked="onCancelClicked"
13+
>
14+
<pipeline-debugging-fields ref="details" />
15+
</base-dialog>
16+
</template>
17+
18+
<script lang="ts">
19+
import { Component, Ref, Prop } from "vue-property-decorator";
20+
import { NavigationIcon } from "sitewhere-ide-common";
21+
import { DialogComponent, BaseDialog } from "sitewhere-ide-components";
22+
23+
import PipelineDebuggingFields from "./PipelineDebuggingFields.vue";
24+
25+
import { IEventPipelineDebugging } from "sitewhere-rest-api";
26+
27+
@Component({
28+
components: { BaseDialog, PipelineDebuggingFields }
29+
})
30+
export default class PipelineDebuggingDialog extends DialogComponent<
31+
IEventPipelineDebugging
32+
> {
33+
@Prop() readonly pipelineDebugging!: IEventPipelineDebugging;
34+
@Ref() readonly dialog!: BaseDialog;
35+
@Ref() readonly details!: PipelineDebuggingFields;
36+
37+
/** Get icon for dialog */
38+
get icon(): NavigationIcon {
39+
return NavigationIcon.Settings;
40+
}
41+
42+
/** Generate payload from UI data */
43+
generatePayload(): IEventPipelineDebugging {
44+
return Object.assign({}, this.pipelineDebugging, this.details.save());
45+
}
46+
47+
/** Reset dialog content to default */
48+
reset() {
49+
if (this.details) {
50+
this.details.reset();
51+
}
52+
}
53+
54+
/** Load data from an existing configuration */
55+
load(payload: IEventPipelineDebugging) {
56+
this.reset();
57+
if (this.details) {
58+
this.details.load(payload);
59+
}
60+
}
61+
62+
/** Called after update button is clicked */
63+
onUpdateClicked() {
64+
if (!this.details.validate()) {
65+
return;
66+
}
67+
68+
const payload = this.generatePayload();
69+
this.$emit("payload", payload);
70+
this.dialogVisible = false;
71+
}
72+
}
73+
</script>

0 commit comments

Comments
 (0)