Skip to content

Commit

Permalink
Add support for copying query results in Markdown format
Browse files Browse the repository at this point in the history
This CL replaces the existing "Copy query" and "Copy results (.tsv)"
buttons with a single "Copy" pop-up menu with options to copy the query,
copy the result as TSV and copy the result as Markdown (new).

Change-Id: I18e9d728c831abaef4520f4a33ef89193b8b1a8c
  • Loading branch information
petrcermak committed Jan 20, 2025
1 parent 789532f commit 5e1f7b2
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8b7d70ad4f8739e1da2c08a01e986300e8a54802605242fac43e256cd077a637
4b25c85d37c04af0f123ed63eab1c5227bae0786edee6111a09e22088375183d
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b9a96bb2efd20db364d16d7e7fe1e060248f5bf27557badcd123c3c330195d61
3a0423ca165ba88d7635c53932c7bb5d66fbebb7247833c0bb32ce465d3bfefd
Original file line number Diff line number Diff line change
@@ -1 +1 @@
00ab906efd78e5e2ec0465f9ac25cc792af71643d77112df36e68e85fb323c49
32fb8853ad2e317ce9d37a318167ca68d2826e37ddbc28b5f35ba22520f57b03
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ce20e472156ea2c2ecb7aab6c76d3242e73eea039bf0624e1f2e194057dcb842
e39cccdbc390289b3c10d2743c597d7e360f6b8c1b40647d51e86ea4b483be49
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c636755a7c74805ac5c8dbafd31110fbb666070df179ffddda7d9f2fe3404fa9
019681faa293a20dd826bb58abf2e21a468887dccdc3e16ce60c73eb3838fb33
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7a37afddcfef9a096999af8c6dcfc7b89df088519e9359c1050ca2a937229290
62084cb38d8bc53e27ed85ed028c0291e763436da4116d3b6bb664bc1e1bb0b7
Original file line number Diff line number Diff line change
@@ -1 +1 @@
177c2c44763d97dc161c133c3ec3c8ac9af76ae54e7e6bb660902ec0233512ab
6d2f7e20729c73b152a9d13890eed7ff882e20a37fb87cc828cc863ba39ae2ad
85 changes: 71 additions & 14 deletions ui/src/components/query_table/query_table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {downloadData} from '../../base/download_utils';
import {Router} from '../../core/router';
import {AppImpl} from '../../core/app_impl';
import {Trace} from '../../public/trace';
import {MenuItem, PopupMenu} from '../../widgets/menu';
import {Icons} from '../../base/semantic_icons';

interface QueryTableRowAttrs {
trace: Trace;
Expand Down Expand Up @@ -228,20 +230,30 @@ export class QueryTable implements m.ClassComponent<QueryTableAttrs> {
) {
return [
contextButtons,
m(Button, {
label: 'Copy query',
onclick: () => {
copyToClipboard(query);
m(
PopupMenu,
{
trigger: m(Button, {
label: 'Copy',
rightIcon: Icons.ContextMenu,
}),
},
}),
resp &&
resp.error === undefined &&
m(Button, {
label: 'Copy result (.tsv)',
onclick: () => {
queryResponseToClipboard(resp);
},
m(MenuItem, {
label: 'Query',
onclick: () => copyToClipboard(query),
}),
resp &&
resp.error === undefined && [
m(MenuItem, {
label: 'Result (.tsv)',
onclick: () => queryResponseAsTsvToClipboard(resp),
}),
m(MenuItem, {
label: 'Result (.md)',
onclick: () => queryResponseAsMarkdownToClipboard(resp),
}),
],
),
];
}

Expand All @@ -264,7 +276,9 @@ export class QueryTable implements m.ClassComponent<QueryTableAttrs> {
}
}

async function queryResponseToClipboard(resp: QueryResponse): Promise<void> {
async function queryResponseAsTsvToClipboard(
resp: QueryResponse,
): Promise<void> {
const lines: string[][] = [];
lines.push(resp.columns);
for (const row of resp.rows) {
Expand All @@ -275,5 +289,48 @@ async function queryResponseToClipboard(resp: QueryResponse): Promise<void> {
}
lines.push(line);
}
copyToClipboard(lines.map((line) => line.join('\t')).join('\n'));
await copyToClipboard(lines.map((line) => line.join('\t')).join('\n'));
}

async function queryResponseAsMarkdownToClipboard(
resp: QueryResponse,
): Promise<void> {
// Convert all values to strings.
// rows = [header, separators, ...body]
const rows: string[][] = [];
rows.push(resp.columns);
rows.push(resp.columns.map((_) => '---'));
for (const responseRow of resp.rows) {
rows.push(
resp.columns.map((responseCol) => {
const value = responseRow[responseCol];
return value === null ? 'NULL' : `${value}`;
}),
);
}

// Find the maximum width of each column.
const maxWidths: number[] = Array(resp.columns.length).fill(0);
for (const row of rows) {
for (let i = 0; i < resp.columns.length; i++) {
if (row[i].length > maxWidths[i]) {
maxWidths[i] = row[i].length;
}
}
}

const text = rows
.map((row, rowIndex) => {
// Pad each column to the maximum width with hyphens (separator row) or
// spaces (all other rows).
const expansionChar = rowIndex === 1 ? '-' : ' ';
const line: string[] = row.map(
(str, colIndex) =>
str + expansionChar.repeat(maxWidths[colIndex] - str.length),
);
return `| ${line.join(' | ')} |`;
})
.join('\n');

await copyToClipboard(text);
}

0 comments on commit 5e1f7b2

Please sign in to comment.