Skip to content

Commit 73065c9

Browse files
authored
feat: pipeline table legend (#563)
* style: pipeline table sematic color * build: tauri version * fix: sed version for mac * fix: datatype test * style: refine layout * style: more unify * fix: date type * fix: date format
1 parent 0e32985 commit 73065c9

File tree

3 files changed

+181
-17
lines changed

3 files changed

+181
-17
lines changed

.github/workflows/release.yml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
name: Build
1212
runs-on: ubuntu-latest
1313
outputs:
14-
tag_name: ${{ steps.get_tag.outputs.tag_name }} # Store tag for other jobs
14+
tag_name: ${{ steps.get_tag.outputs.tag_name }} # Store tag for other jobs
1515
steps:
1616
- name: Checkout sources
1717
uses: actions/checkout@v4
@@ -50,8 +50,6 @@ jobs:
5050
id: get_tag
5151
run: echo "tag_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
5252

53-
54-
5553
publish-tauri:
5654
needs: build
5755
permissions:
@@ -73,7 +71,7 @@ jobs:
7371
env:
7472
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
7573
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD}}
76-
RELEASE_TAG: ${{ needs.build.outputs.tag_name }} # Get the release tag from the build job
74+
RELEASE_TAG: ${{ needs.build.outputs.tag_name }} # Get the release tag from the build job
7775
steps:
7876
- uses: actions/checkout@v4
7977

@@ -133,6 +131,18 @@ jobs:
133131
Remove-Item -path certificate -include tempCert.txt
134132
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
135133
134+
- name: Update tauri version to match tag
135+
run: |
136+
# Extract version from tag (remove 'v' prefix if present)
137+
VERSION=${RELEASE_TAG#v}
138+
# Update tauri.conf.json with the tag version
139+
if [[ "$RUNNER_OS" == "Windows" ]]; then
140+
powershell -Command "(Get-Content src-tauri/tauri.conf.json) -replace '\"version\": \"[^\"]*\"', '\"version\": \"$VERSION\"' | Set-Content src-tauri/tauri.conf.json"
141+
else
142+
# Linux/macOS - use empty string for macOS compatibility
143+
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" src-tauri/tauri.conf.json
144+
fi
145+
136146
- uses: tauri-apps/tauri-action@v0
137147
env:
138148
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

src/components/data-table/index.vue

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,17 @@
3838
placement="top"
3939
:content="tsViewStr ? $t('dashboard.showTimestamp') : $t('dashboard.formatTimestamp')"
4040
)
41-
a-space(size="mini" :style="{ cursor: 'pointer' }" @click="changeTsView")
41+
a-space(
42+
size="mini"
43+
:style="{ cursor: 'pointer' }"
44+
:class="col.semantic_type?.toLowerCase()"
45+
@click="changeTsView"
46+
)
4247
svg.icon-12
4348
use(href="#time-index")
4449
| {{ col.name }}
4550
template(v-else)
46-
| {{ col.title || col.name }}
47-
51+
span(:class="col.semantic_type?.toLowerCase()") {{ col.title || col.name }}
4852
// Custom cell slot - allow parent components to override cell rendering
4953
template(#cell="{ record, rowIndex }")
5054
slot(
@@ -109,8 +113,10 @@ a-dropdown#td-context(
109113
import { ref, computed, shallowRef } from 'vue'
110114
import { useElementSize } from '@vueuse/core'
111115
import dayjs from 'dayjs'
116+
import { dateTypes } from '@/views/dashboard/config'
112117
import { convertTimestampToMilliseconds } from '@/utils/date-time'
113118
import type { ColumnType, TSColumn } from '@/types/query'
119+
import { dateFormatter } from '@/utils'
114120
115121
interface TableData {
116122
[key: string]: any
@@ -197,7 +203,7 @@ a-dropdown#td-context(
197203
198204
// Timestamp utilities
199205
function isTimeColumn(column: ColumnType) {
200-
return column.data_type.toLowerCase().includes('timestamp')
206+
return dateTypes.indexOf(column.data_type) > -1
201207
}
202208
203209
// Width calculation utilities
@@ -347,6 +353,7 @@ a-dropdown#td-context(
347353
348354
function renderTs(record: any, columnName: string) {
349355
const timestamp = record[columnName]
356+
350357
if (!timestamp) return timestamp
351358
352359
if (tsViewStr.value) {
@@ -355,7 +362,7 @@ a-dropdown#td-context(
355362
if (!column) return timestamp
356363
357364
// Use universal conversion function
358-
const ms = convertTimestampToMilliseconds(timestamp, column.data_type)
365+
const ms = dateFormatter(column.data_type, timestamp)
359366
return dayjs(ms).format('YYYY-MM-DD HH:mm:ss.SSS')
360367
}
361368

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

Lines changed: 155 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<template lang="pug">
2-
a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08); height: calc(100vh - 30px)")
2+
a-layout.full-height-layout.pipefile-view(
3+
style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08); height: calc(100vh - 30px)"
4+
)
35
a-layout-sider(style="width: 45%" :resize-directions="['right']")
46
a-card.light-editor-card(:bordered="false")
57
template(#title)
@@ -49,7 +51,7 @@ a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08);
4951
div
5052
.full-width-height-editor.pipeline-editor(:class="editorHeightClass")
5153
YMLEditorSimple(v-model="currFile.content" style="width: 100%; height: 100%")
52-
a-layout-content.content-wrapper(style="display: flex; flex-direction: column; gap: 24px; padding-bottom: 22px")
54+
a-layout-content.content-wrapper(style="display: flex; flex-direction: column; padding-bottom: 22px")
5355
a-card.light-editor-card(title="Input" :bordered="false")
5456
template(#extra)
5557
a-space
@@ -63,7 +65,7 @@ a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08);
6365
a-option(value="application/json") json
6466
a-option(value="application/x-ndjson") ndjson
6567

66-
a-button(size="small" @click="handleDebug") Test
68+
a-button(size="small" type="primary" @click="handleDebug") Test
6769

6870
template(#title)
6971
.card-title-with-description
@@ -82,7 +84,7 @@ a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08);
8284
:indent-with-tab="true"
8385
:tabSize="2"
8486
)
85-
87+
.section-divider
8688
a-card.light-editor-card.output(title="Output" :bordered="false")
8789
template(#extra)
8890
a-radio-group.output-view-toggle(v-model="outputViewMode" type="button" size="small")
@@ -94,17 +96,38 @@ a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08);
9496
.card-title Output
9597
.card-description Processed logs displayed here. Logs that ingested via API will follow this structure.
9698

99+
// Semantic Type Legend
100+
.semantic-legend(
101+
v-if="outputViewMode === 'table' && parsedOutputData.records && parsedOutputData.records.rows.length > 0"
102+
)
103+
.legend-items
104+
.legend-item
105+
.legend-color.field
106+
.legend-label Field
107+
.legend-item
108+
.legend-color.tag
109+
.legend-label Tag
110+
.legend-item
111+
.legend-color.timestamp
112+
.legend-label Timestamp
113+
97114
a-empty(
98115
v-if="parsedOutputData.records && parsedOutputData.records.rows.length === 0"
99-
style="border: 1px solid var(--color-border); border-radius: 2px; height: 100%; display: flex; align-items: center; justify-content: center; margin-top: 8px; flex: 1"
116+
style="border: 1px solid var(--color-border); border-radius: 2px; height: 100%; display: flex; align-items: center; justify-content: center; flex: 1"
100117
description="No parsed data. Click Test to see results."
101118
)
102119

103120
// Table View
104121
.output-table(
105122
v-if="outputViewMode === 'table' && parsedOutputData.records && parsedOutputData.records.rows.length > 0"
106123
)
107-
DataGrid(:data="parsedOutputData" :has-header="false")
124+
DataTable(
125+
:data="tableData"
126+
:columns="tableColumns"
127+
:loading="false"
128+
:show-context-menu="false"
129+
:wrap-line="true"
130+
)
108131

109132
// JSON View
110133
.full-width-height-editor(
@@ -129,7 +152,10 @@ a-layout.full-height-layout(style="box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.08);
129152
import { json } from '@codemirror/lang-json'
130153
import { create, list, del, debugContent, getByName } from '@/api/pipeline'
131154
import type { PipeFile } from '@/api/pipeline'
155+
import type { ColumnType } from '@/types/query'
132156
import router from '@/router'
157+
import DataTable from '@/components/data-table/index.vue'
158+
import { toObj } from '../query/until'
133159
134160
const emit = defineEmits(['refresh', 'del'])
135161
const props = defineProps<{
@@ -290,6 +316,10 @@ transform:
290316
type: 'table',
291317
})
292318
319+
// DataTable specific variables
320+
const tableData = ref<Array<any>>([])
321+
const tableColumns = ref<Array<ColumnType>>([])
322+
293323
function handleDebug() {
294324
debugContent(currFile.content, debugForm.content, selectedContentType.value).then((result) => {
295325
debugResponse.value = JSON.stringify(result[0], null, 2)
@@ -300,7 +330,7 @@ transform:
300330
})
301331
const schema = result[0].schema || []
302332
303-
// Parse response for DataGrid format
333+
// Parse response for DataGrid format (keep for compatibility)
304334
parsedOutputData.value = {
305335
records: {
306336
rows,
@@ -318,6 +348,19 @@ transform:
318348
key: Date.now(),
319349
type: 'table',
320350
}
351+
352+
// Update DataTable format
353+
const schemas = schema.map((col) => ({
354+
name: col.name,
355+
title: col.name,
356+
data_type: col.data_type || 'String',
357+
semantic_type: col.colume_type,
358+
}))
359+
360+
tableColumns.value = schemas
361+
tableData.value = rows.map((row, index) => {
362+
return toObj(row, schemas, index, null)
363+
})
321364
})
322365
}
323366
@@ -378,7 +421,6 @@ transform:
378421
}
379422
:deep(.arco-card-header) {
380423
flex-shrink: 0;
381-
margin-top: 12px;
382424
}
383425
}
384426
@@ -441,4 +483,109 @@ transform:
441483
overflow: hidden;
442484
}
443485
}
486+
487+
// ===================
488+
// SEMANTIC TYPE STYLES
489+
// ===================
490+
491+
// Define semantic type colors as CSS variables at component level
492+
.pipefile-view {
493+
--semantic-field-bg: #f6ffed;
494+
--semantic-field-text: #36b174;
495+
--semantic-field-legend: #36b174;
496+
497+
--semantic-tag-bg: #fff7e6;
498+
--semantic-tag-text: #e1b84d;
499+
--semantic-tag-legend: #e1b84d;
500+
501+
--semantic-timestamp-bg: #e6f4ff;
502+
--semantic-timestamp-text: #417aff;
503+
--semantic-timestamp-legend: #417aff;
504+
font-size: 13px;
505+
}
506+
507+
.semantic-legend {
508+
display: flex;
509+
align-items: center;
510+
gap: 16px;
511+
margin-bottom: 12px;
512+
justify-content: flex-end;
513+
514+
.legend-title {
515+
font-size: 12px;
516+
font-weight: 600;
517+
color: var(--color-text-2);
518+
}
519+
520+
.legend-items {
521+
display: flex;
522+
gap: 16px;
523+
}
524+
525+
.legend-item {
526+
display: flex;
527+
align-items: center;
528+
gap: 6px;
529+
530+
.legend-color {
531+
width: 12px;
532+
height: 12px;
533+
border-radius: 2px;
534+
border: 1px solid var(--color-border-3);
535+
536+
&.field {
537+
background-color: var(--semantic-field-legend);
538+
}
539+
540+
&.tag {
541+
background-color: var(--semantic-tag-legend);
542+
}
543+
544+
&.timestamp {
545+
background-color: var(--semantic-timestamp-legend);
546+
}
547+
}
548+
549+
.legend-label {
550+
font-size: 12px;
551+
color: var(--color-text-2);
552+
}
553+
}
554+
}
555+
556+
.output-table {
557+
:deep(.arco-table-th-title) {
558+
.timestamp {
559+
background-color: var(--semantic-timestamp-bg);
560+
color: var(--semantic-timestamp-text);
561+
padding: 2px 4px;
562+
}
563+
564+
.field {
565+
background-color: var(--semantic-field-bg);
566+
color: var(--semantic-field-text);
567+
padding: 2px 4px;
568+
}
569+
570+
.tag {
571+
background-color: var(--semantic-tag-bg);
572+
color: var(--semantic-tag-text);
573+
padding: 2px 4px;
574+
}
575+
}
576+
:deep(.arco-table-size-medium .arco-table-td) {
577+
font-size: 13px;
578+
}
579+
}
580+
.light-editor-card :deep(.arco-card-header) {
581+
border-bottom: 1px solid var(--color-border);
582+
height: 70px;
583+
}
584+
.section-divider {
585+
height: 6px;
586+
background: var(--color-neutral-3);
587+
border: none;
588+
margin: 10px 0 0;
589+
position: relative;
590+
}
444591
</style>

0 commit comments

Comments
 (0)