Skip to content

Commit 645bf8f

Browse files
authored
Merge pull request #56 from beekeeper-studio/fix/style-preview-table
native looking table
2 parents bc4835b + 7c59207 commit 645bf8f

File tree

7 files changed

+167
-41
lines changed

7 files changed

+167
-41
lines changed

src/assets/styles/components/_message.scss

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,69 @@
11
.message {
2+
.markdown {
3+
p {
4+
margin: 0.75em 0;
5+
}
6+
7+
code:not([data-lang]) {
8+
background-color: color-mix(in srgb,
9+
var(--theme-base) 3%,
10+
var(--query-editor-bg));
11+
padding: 0.05em 0.2em;
12+
border-radius: 8px;
13+
}
14+
15+
h1,
16+
h2,
17+
h3,
18+
h4 {
19+
margin: 2.5rem 0 1.5rem 0;
20+
line-height: 1.25;
21+
}
22+
23+
ol,
24+
ul {
25+
margin: 1em;
26+
}
27+
28+
ol li ol,
29+
ol li ul,
30+
ul li ol,
31+
ul li ul {
32+
margin: 0 2em;
33+
}
34+
35+
ol li p,
36+
ul li p {
37+
margin: 0;
38+
}
39+
40+
&:first-child {
41+
42+
p:first-child,
43+
h1:first-child,
44+
h2:first-child,
45+
h3:first-child,
46+
h4:first-child,
47+
ol:first-child,
48+
ul:first-child {
49+
margin-top: 0;
50+
}
51+
}
52+
53+
&:last-child {
54+
55+
p:last-child,
56+
h1:last-child,
57+
h2:last-child,
58+
h3:last-child,
59+
h4:last-child,
60+
ol:last-child,
61+
ul:last-child {
62+
margin-bottom: 0;
63+
}
64+
}
65+
}
66+
267
.message-actions {
368
display: flex;
469
margin-top: 0.5rem;
@@ -18,6 +83,7 @@
1883
}
1984

2085
.copy-btn {
86+
2187
&.copied .copy-label,
2288
&.copied .copy-icon,
2389
&:not(.copied) .copied-label,
@@ -27,8 +93,62 @@
2793
}
2894
}
2995

30-
&.assistant .message-actions {
31-
padding-left: 0.4rem;
96+
&.assistant {
97+
.table-container table {
98+
width: 100%;
99+
}
100+
101+
table tbody tr:nth-child(odd) {
102+
background-color: color-mix(in srgb,
103+
var(--theme-base) 3%,
104+
var(--query-editor-bg));
105+
}
106+
107+
.message-actions {
108+
padding-left: 0.4rem;
109+
}
110+
111+
.tool {
112+
.tool-name {
113+
margin-bottom: 0.25rem;
114+
}
115+
116+
.tool-error {
117+
margin-top: 0.5rem;
118+
}
119+
120+
&[data-tool-name="run_query"] {
121+
gap: 0;
122+
123+
.no-rows {
124+
margin-top: 0.5rem;
125+
}
126+
127+
&[data-tool-empty-result="false"] .code-block {
128+
border-bottom: none;
129+
border-bottom-right-radius: 0;
130+
border-bottom-left-radius: 0;
131+
}
132+
133+
.table-container {
134+
margin: 0;
135+
border: 1px solid var(--border-color);
136+
border-bottom: none;
137+
}
138+
139+
.view-more-btn {
140+
width: 100%;
141+
border-top-left-radius: 0;
142+
border-top-right-radius: 0;
143+
height: 2rem;
144+
font-weight: normal;
145+
146+
.open-icon {
147+
font-size: 1.2rem;
148+
}
149+
}
150+
}
151+
}
32152
}
33153

34154
&.user .message-actions {

src/assets/styles/components/_run-query-result.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
.run-query-result {
22
display: flex;
33
flex-direction: column;
4-
gap: 0.5rem;
5-
.view-more-btn {
6-
width: max-content;
7-
}
84

95
.null-cell, .empty-cell {
106
opacity: 0.65;

src/assets/styles/pages/_chat-interface.scss

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@
144144
.message-content {
145145
display: flex;
146146
flex-direction: column;
147-
gap: 1.2rem;
148147
padding: 0.55rem 0.9rem;
149148
line-height: 1.4rem;
150149
white-space: pre-wrap;
@@ -178,7 +177,6 @@
178177
white-space: normal;
179178
display: flex;
180179
flex-direction: column;
181-
gap: 1.2rem;
182180

183181
ol,
184182
ul {
@@ -325,6 +323,7 @@
325323
border-left: 2px solid var(--border-color);
326324
gap: 0.35rem;
327325
width: 100%;
326+
margin: 0.75em 0;
328327

329328
.accept-icon,
330329
.reject-icon {
@@ -517,40 +516,42 @@
517516
}
518517
}
519518

520-
.preview-table-container {
519+
.table-container {
521520
overflow-x: auto;
521+
margin: 0.5rem 0;
522522
}
523523

524-
.preview-table {
524+
.message.assistant table {
525525
width: auto;
526526
border-collapse: collapse;
527-
margin: 0.5rem 0;
528527
table-layout: auto;
529528

529+
&.preview-table {
530+
th, td {
531+
max-width: 200px;
532+
overflow: hidden;
533+
text-overflow: ellipsis;
534+
}
535+
}
536+
530537
th,
531538
td {
532-
border: 1px solid var(--border-color);
533539
padding: 0 0.7rem;
534540
text-align: left;
535541
white-space: nowrap;
536-
max-width: 200px;
537-
overflow: hidden;
538-
text-overflow: ellipsis;
539542
}
540543

541544
th {
542545
width: auto;
543546
}
544547

545548
th {
546-
background-color: color-mix(in srgb, var(--theme-base) 5%, var(--query-editor-bg));
547549
font-weight: 600;
548550
font-size: 0.68rem;
549551
line-height: 1.7rem;
550552
}
551553

552554
td {
553-
background-color: var(--query-editor-bg);
554555
font-size: 0.75rem;
555556
line-height: 1.875rem;
556557
}

src/components/messages/Message.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export default {
8383
return text.trim();
8484
},
8585
isEmpty() {
86-
return isEmptyUIMessage(this.message);
86+
return this.status === 'ready' && isEmptyUIMessage(this.message);
8787
},
8888
},
8989

src/components/messages/ToolMessage.vue

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<template>
2-
<div class="tool">
3-
<div>{{ displayName }}</div>
4-
<markdown
5-
v-if="toolCall.toolName === 'run_query'"
6-
:content="'```sql\n' + toolCall.args.query + '\n```'"
7-
/>
2+
<div class="tool" :data-tool-name="toolCall.toolName" :data-tool-state="toolCall.state"
3+
:data-tool-empty-result="isEmptyResult">
4+
<div class="tool-name">{{ displayName }}</div>
5+
<markdown v-if="toolCall.toolName === 'run_query'" :content="'```sql\n' + toolCall.args.query + '\n```'" />
86
<div v-if="askingPermission">
97
{{
108
toolCall.toolName === "run_query"
@@ -22,7 +20,7 @@
2220
</button>
2321
</div>
2422
</div>
25-
<div :class="{ error }">
23+
<div :class="{ 'error tool-error': error }">
2624
<template v-if="error">{{ error }}</template>
2725
<template v-else-if="data">
2826
<template v-if="toolCall.toolName === 'get_connection_info'">
@@ -36,23 +34,17 @@
3634
<template v-if="toolCall.toolName === 'get_columns'">
3735
{{ data.length }}
3836
{{ $pluralize("column", data.length) }}
39-
(<code
40-
v-if="data.length < 5"
41-
v-text="data.map((c) => c.name).join(', ')"
42-
/>)
37+
(<code v-if="data.length < 5" v-text="data.map((c) => c.name).join(', ')" />)
4338
</template>
44-
<run-query-result
45-
v-else-if="toolCall.toolName === 'run_query' && data"
46-
:data="data"
47-
/>
39+
<run-query-result v-else-if="toolCall.toolName === 'run_query' && data" :data="data" />
4840
</template>
4941
</div>
5042
</div>
5143
</template>
5244

5345
<script lang="ts">
5446
import Markdown from "@/components/messages/Markdown.vue";
55-
import { ToolCall } from "ai";
47+
import { ToolInvocation } from "ai";
5648
import { PropType } from "vue";
5749
import { safeJSONStringify } from "@/utils";
5850
import RunQueryResult from "@/components/messages/tool/RunQueryResult.vue";
@@ -64,12 +56,22 @@ export default {
6456
props: {
6557
askingPermission: Boolean,
6658
toolCall: {
67-
type: Object as PropType<ToolCall<string, any>>,
59+
type: Object as PropType<ToolInvocation>,
6860
required: true,
6961
},
7062
},
7163
emits: ["accept", "reject"],
7264
computed: {
65+
isEmptyResult() {
66+
if (this.toolCall.state === "result") {
67+
return _.isEmpty(
68+
this.toolCall.toolName === "run_query"
69+
? this.data.results?.[0]?.rows
70+
: this.data,
71+
);
72+
}
73+
return true;
74+
},
7375
content() {
7476
if (this.data) {
7577
let str = "";

src/components/messages/tool/RunQueryResult.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
<template>
22
<div class="run-query-result">
3-
<span>
4-
Query returned {{ rows.length }} {{ $pluralize('row', rows.length) }}
5-
</span>
63
<template v-if="rows.length > 0">
7-
<div class="preview-table-container">
4+
<div class="preview-table-container table-container">
85
<table class="preview-table">
96
<thead>
107
<tr>
@@ -37,7 +34,7 @@
3734
</table>
3835
</div>
3936
<button
40-
class="btn btn-primary view-more-btn"
37+
class="btn view-more-btn"
4138
@click.prevent="handleViewMoreClick"
4239
>
4340
<div class="label">View more</div>
@@ -46,6 +43,9 @@
4643
</span>
4744
</button>
4845
</template>
46+
<span class="no-rows" v-else>
47+
Query returned 0 rows
48+
</span>
4949
</div>
5050
</template>
5151

src/markdownParser.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Marked } from "marked";
1+
import { Marked, Renderer } from "marked";
22
import { markedHighlight } from "marked-highlight";
33
import hljs from "highlight.js";
44
import { getAppVersion } from "@beekeeperstudio/plugin";
@@ -14,12 +14,19 @@ const marked = new Marked(
1414
}),
1515
);
1616

17+
const renderer = new Renderer();
18+
1719
let copyCounter = 0;
1820

1921
async function useExtensions() {
2022
const appVersion = await getAppVersion();
2123
const supportOpenInQueryEditor = appVersion !== "5.3";
2224
marked.use({
25+
renderer: {
26+
table(...args) {
27+
return `<div class="table-container">${renderer.table.apply(this, args)}</div>`;
28+
},
29+
},
2330
extensions: [
2431
{
2532
name: "code",

0 commit comments

Comments
 (0)