Skip to content

Commit 3ec5481

Browse files
authored
feat: use new dry run api (#513)
* feat: dry run api * feat: pipeline view * feat: ui * style: outline * style: expand input height
1 parent 81a95d9 commit 3ec5481

File tree

2 files changed

+160
-41
lines changed

2 files changed

+160
-41
lines changed

src/api/pipeline.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,14 @@ export function debug(name: string, content: any) {
9393
})
9494
}
9595

96-
export function debugContent(pipeline: string, data: any) {
96+
export function debugContent(pipeline: string, data: any, contentType: string) {
9797
const appStore = useAppStore()
9898
return axios.post(
9999
`${url}/dryrun?&db=${appStore.database}`,
100100
{
101101
data,
102102
pipeline,
103+
data_type: contentType,
103104
},
104105
{
105106
headers: {

src/views/dashboard/logs/pipelines/PipeFileView.vue

Lines changed: 158 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
a-page-header(title="Pipeline Configuration" :show-back="false")
33

44
a-alert Pipeline is a mechanism in GreptimeDB for parsing and transforming log data, <a href="https://docs.greptime.com/user-guide/logs/pipeline-config" target="_blank">read more</a>
5-
a-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08)")
6-
a-layout-sider(:resize-directions="['right']" :width="650")
5+
a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08)")
6+
a-layout-sider(:resize-directions="['right']" :width="800")
77
a-card(title="Pipeline" :bordered="false")
88
template(#extra)
99
a-space
@@ -25,52 +25,58 @@ a-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08)")
2525
:disabled="!isCreating"
2626
:rules="rules"
2727
)
28+
.form-description Input the pipeline configuration here to define how logs are parsed and transformed, You can test on the right side whether it's already saved.
2829
a-form-item(field="name" label="Pipeline name" style="width: 200px")
2930
a-input(v-model="currFile.name" placeholder="Pipeline name")
3031
a-form-item(v-if="!isCreating" field="version" label="Version")
3132
| {{ currFile.version }}
3233
a-form-item(field="content" label="Yaml Content")
3334
template(#help)
3435
div
35-
YMLEditorSimple(v-model="currFile.content" style="width: 100%; height: 525px")
36+
.editor-container
37+
YMLEditorSimple(v-model="currFile.content" style="width: 100%; height: calc(-470px + 100vh)")
3638
a-layout-content
37-
div(style="display: flex; flex-direction: column")
38-
a-card.light-editor-card(title="Input" style="flex: 1" :bordered="false")
39+
.content-container
40+
a-card.light-editor-card(title="Input" :bordered="false")
3941
template(#extra)
4042
a-space
4143
a-button(size="small" @click="handleDebug") Test
42-
//- a(href="https://github.com/GreptimeTeam/demo-scene/tree/main/vector-ingestion" target="_blank") Write Log Demo
43-
44+
a-select(v-model="selectedContentType" style="width: 150px" placeholder="Content Type")
45+
a-option(value="text/plain") text
46+
a-option(value="application/json") json
47+
a-option(value="application/x-ndjson") ndjson
4448
.right-content
4549
a-alert(v-if="ymlError" type="error")
4650
| {{ ymlError }}
4751
a-typography-text(type="secondary")
4852
| Input your original log to see parse results.
49-
CodeMirror(
50-
v-model="debugForm.content"
51-
style="height: 320px; width: 100%; margin-top: 5px"
52-
:extensions="extensions"
53-
:spellcheck="true"
54-
:autofocus="true"
55-
:indent-with-tab="true"
56-
:tabSize="2"
57-
:placeholder="debugTip"
58-
)
59-
60-
a-card.light-editor-card(title="Output" style="flex: 1" :bordered="false")
53+
.input-editor
54+
CodeMirror(
55+
v-model="debugForm.content"
56+
style="width: 100%; height: 100%"
57+
:extensions="extensions"
58+
:spellcheck="true"
59+
:autofocus="true"
60+
:indent-with-tab="true"
61+
:tabSize="2"
62+
:placeholder="debugTip"
63+
)
64+
65+
a-card.light-editor-card(title="Output" :bordered="false")
6166
.right-content
6267
a-typography-text(type="secondary")
6368
| Parsed logs displayed here. Logs that ingested via API will follow this structure.
64-
CodeMirror(
65-
style="height: 340px; width: 100%; margin-top: 5px"
66-
:model-value="debugResponse"
67-
:extensions="extensions"
68-
:spellcheck="true"
69-
:autofocus="true"
70-
:indent-with-tab="true"
71-
:tabSize="2"
72-
:disabled="true"
73-
)
69+
.output-editor
70+
CodeMirror(
71+
style="width: 100%; height: 100%"
72+
:model-value="debugResponse"
73+
:extensions="extensions"
74+
:spellcheck="true"
75+
:autofocus="true"
76+
:indent-with-tab="true"
77+
:tabSize="2"
78+
:disabled="true"
79+
)
7480
</template>
7581

7682
<script setup name="PipeFileView" lang="ts">
@@ -86,7 +92,6 @@ a-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08)")
8692
filename: undefined | string
8793
}>()
8894
89-
const debugTip = 'Input raw Strings or JSON Object Array'
9095
const currFile = reactive<PipeFile>({
9196
name: '',
9297
content: `processors:
@@ -171,19 +176,42 @@ transform:
171176
'210.207.142.115 - AnthraX [26/Dec/2024:16:47:19 +0800] "DELETE /do-not-access/needs-work HTTP/2.0" 200 4488',
172177
})
173178
179+
const selectedContentType = ref('text/plain')
180+
// Watch for content changes to auto-detect content type
181+
watch(
182+
() => debugForm.content,
183+
(newContent) => {
184+
try {
185+
JSON.parse(newContent)
186+
selectedContentType.value = 'application/json'
187+
} catch (e) {
188+
// If content contains newlines and each line is valid JSON, it's NDJSON
189+
if (newContent.includes('\n')) {
190+
const lines = newContent.split('\n').filter((line) => line.trim())
191+
const isNDJSON = lines.every((line) => {
192+
try {
193+
JSON.parse(line)
194+
return true
195+
} catch {
196+
return false
197+
}
198+
})
199+
if (isNDJSON) {
200+
selectedContentType.value = 'application/x-ndjson'
201+
} else {
202+
selectedContentType.value = 'text/plain'
203+
}
204+
} else {
205+
selectedContentType.value = 'text/plain'
206+
}
207+
}
208+
}
209+
)
210+
174211
const extensions = [basicSetup, json()]
175212
const debugResponse = ref('')
176213
function handleDebug() {
177-
let content
178-
try {
179-
content = JSON.parse(debugForm.content)
180-
if (!Array.isArray(content)) {
181-
content = [content]
182-
}
183-
} catch (e) {
184-
content = debugForm.content.split('\n')
185-
}
186-
debugContent(currFile.content, content).then((result) => {
214+
debugContent(currFile.content, debugForm.content, selectedContentType.value).then((result) => {
187215
debugResponse.value = JSON.stringify(result, null, 2)
188216
})
189217
}
@@ -208,11 +236,101 @@ transform:
208236
}
209237
.right-content {
210238
padding: 0 10px 10px 10px;
239+
height: 100%;
240+
display: flex;
241+
flex-direction: column;
211242
}
212243
:deep(.arco-card.light-editor-card) {
213244
padding-right: 0;
245+
flex: 1;
246+
display: flex;
247+
flex-direction: column;
248+
min-height: 0;
214249
}
215250
:deep(.arco-layout-sider-light) {
216251
box-shadow: none;
217252
}
253+
:deep(.arco-form-item-content-flex) {
254+
display: block;
255+
}
256+
257+
.content-container {
258+
height: 100%;
259+
display: flex;
260+
flex-direction: column;
261+
gap: 16px;
262+
padding-bottom: 16px;
263+
}
264+
265+
.input-editor,
266+
.output-editor {
267+
flex: 1;
268+
min-height: 0;
269+
margin-top: 5px;
270+
271+
:deep(.cm-editor) {
272+
height: 100%;
273+
}
274+
}
275+
276+
.output-editor {
277+
:deep(.cm-editor) {
278+
background-color: var(--color-fill-2);
279+
cursor: not-allowed;
280+
}
281+
282+
:deep(.cm-content) {
283+
color: var(--color-text-2);
284+
}
285+
}
286+
287+
.form-description {
288+
color: var(--color-text-3);
289+
font-size: 14px;
290+
margin-bottom: 16px;
291+
}
292+
293+
.full-height-layout {
294+
height: calc(100vh - 133px); // Subtract header height and alert height
295+
296+
:deep(.arco-layout) {
297+
height: 100%;
298+
}
299+
300+
:deep(.arco-layout-content) {
301+
height: 100%;
302+
overflow: auto;
303+
}
304+
305+
:deep(.arco-layout-sider) {
306+
height: 100%;
307+
overflow: auto;
308+
overflow-x: hidden; // Prevent horizontal scrollbar
309+
}
310+
311+
:deep(.arco-card-body) {
312+
padding: 0; // Remove default padding that might cause overflow
313+
height: 100%;
314+
}
315+
}
316+
317+
.editor-container {
318+
min-height: 300px; // Set a minimum height
319+
}
320+
321+
// Add styles for editor borders
322+
:deep(.cm-editor) {
323+
border: 1px solid var(--color-border);
324+
border-radius: 4px;
325+
}
326+
327+
:deep(.editor-container) {
328+
.cm-editor {
329+
border: 1px solid var(--color-border);
330+
border-radius: 4px;
331+
}
332+
}
333+
:deep(.cm-editor.cm-focused) {
334+
outline: 0;
335+
}
218336
</style>

0 commit comments

Comments
 (0)