@olenbetong/appframe-cli 4.3.1 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/cli/af-apply.js +1 -1
  3. package/cli/af-deploy.js +1 -1
  4. package/cli/editor/TransactionsEditor.js +134 -158
  5. package/cli/editor/TransactionsPreviewDialog.js +175 -104
  6. package/cli/editor/tableFormatting.js +9 -80
  7. package/cli/editor/useCommand.js +148 -0
  8. package/cli/editor/useScrollableText.js +28 -0
  9. package/cli/editor/useTransactionEdits.js +142 -0
  10. package/cli/editor/useTransactionText.js +113 -0
  11. package/cli/editor/useTransactions.js +53 -0
  12. package/cli/editor/useTransactionsSelection.js +41 -0
  13. package/cli/editor/useTransactionsTableLayout.js +54 -0
  14. package/cli/editor/{useTransactionsTableViewport.js → useVirtualScrolling.js} +62 -24
  15. package/cli/editor/useVirtualText.js +18 -0
  16. package/package.json +2 -2
  17. package/src/af-apply.ts +1 -1
  18. package/src/af-deploy.ts +1 -1
  19. package/src/editor/TransactionsEditor.tsx +155 -180
  20. package/src/editor/TransactionsPreviewDialog.tsx +196 -146
  21. package/src/editor/tableFormatting.ts +8 -94
  22. package/src/editor/useCommand.ts +191 -0
  23. package/src/editor/useScrollableText.ts +48 -0
  24. package/src/editor/useTransactionEdits.ts +183 -0
  25. package/src/editor/useTransactionText.ts +153 -0
  26. package/src/editor/useTransactions.ts +75 -0
  27. package/src/editor/useTransactionsSelection.ts +54 -0
  28. package/src/editor/useTransactionsTableLayout.ts +84 -0
  29. package/src/editor/{useTransactionsTableViewport.ts → useVirtualScrolling.ts} +87 -38
  30. package/src/editor/useVirtualText.ts +32 -0
  31. package/tsconfig.build.tsbuildinfo +1 -1
  32. package/cli/editor/useTransactionsEditorData.js +0 -206
  33. package/cli/editor/useTransactionsEditorInput.js +0 -109
  34. package/src/editor/useTransactionsEditorData.ts +0 -245
  35. package/src/editor/useTransactionsEditorInput.ts +0 -147
@@ -1,163 +1,226 @@
1
- import type { TransactionsRecord } from "@olenbetong/appframe-updater";
2
- import { Box, Text, useInput } from "ink";
3
- import { useEffect, useMemo, useRef, useState } from "react";
1
+ import { type TransactionStatusCode, transactionStatusLabels } from "@olenbetong/appframe-updater";
2
+ import { Box, Text } from "ink";
3
+ import { type ReactNode, useMemo } from "react";
4
4
 
5
+ import type { Server } from "../lib/Server.js";
5
6
  import { FullScreenBox } from "./FullScreenBox.js";
7
+ import { STATUS_DIRTY_INDICATOR } from "./tableFormatting.js";
8
+ import { useCommand } from "./useCommand.js";
6
9
  import { useScreenSize } from "./useScreenSize.js";
10
+ import { useScrollableText } from "./useScrollableText.js";
11
+ import { useTransactionEdits } from "./useTransactionEdits.js";
12
+ import { useTransactions } from "./useTransactions.js";
13
+ import { useTransactionText } from "./useTransactionText.js";
14
+ import { useVirtualText } from "./useVirtualText.js";
7
15
 
8
- function formatPreviewValue(value: unknown) {
9
- if (typeof value === "string") {
10
- let lines = value.split(/\r?\n/);
11
- return lines.length > 0 ? lines : [""];
12
- }
16
+ const PREVIEW_SAVE_SHORTCUTS = ["ctrl+s", "meta+s"];
17
+ const NO_TRANSACTION_FILTER = "1 = 0";
13
18
 
14
- if (value && typeof value === "object") {
15
- try {
16
- let serialized = JSON.stringify(value, null, 2);
17
- if (serialized) {
18
- return serialized.split("\n");
19
- }
20
- } catch {}
21
- }
19
+ function escapePrimKey(primKey: string) {
20
+ return primKey.replace(/'/g, "''");
21
+ }
22
22
 
23
- if (value === null) {
24
- return ["null"];
23
+ function createPrimKeyFilter(primKey: string | null) {
24
+ if (!primKey) {
25
+ return NO_TRANSACTION_FILTER;
25
26
  }
26
27
 
27
- return [String(value)];
28
+ return `PrimKey = '${escapePrimKey(primKey)}'`;
28
29
  }
29
30
 
30
31
  export type TransactionsPreviewDialogProps = {
31
- record: TransactionsRecord;
32
+ server: Server;
33
+ namespace: string | number;
32
34
  frameWidth: number;
35
+ focusedPrimKey: string | null;
36
+ focusNext: () => void;
37
+ focusPrevious: () => void;
33
38
  };
34
39
 
35
- type PreviewLine = {
36
- type: "line";
37
- key: string;
38
- entryKey: string;
39
- line: string;
40
- lineIndex: number;
41
- };
40
+ function Shortcut({ keyboard, command }: { keyboard: string; command: string }) {
41
+ return (
42
+ <Text>
43
+ [{keyboard}] {command}
44
+ </Text>
45
+ );
46
+ }
42
47
 
43
- type PreviewSpacer = {
44
- type: "spacer";
45
- key: string;
46
- };
48
+ export function TransactionsPreviewDialog({
49
+ server,
50
+ namespace,
51
+ frameWidth,
52
+ focusedPrimKey,
53
+ focusNext,
54
+ focusPrevious,
55
+ }: TransactionsPreviewDialogProps) {
56
+ let transactionFilter = useMemo(() => createPrimKeyFilter(focusedPrimKey), [focusedPrimKey]);
57
+ let { loading, error, refresh, normalizedTransactions, transactionMap } = useTransactions({
58
+ server,
59
+ namespace,
60
+ filter: transactionFilter,
61
+ });
62
+
63
+ let selectedPrimKeys = useMemo(
64
+ () => (focusedPrimKey ? new Set([focusedPrimKey]) : new Set<string>()),
65
+ [focusedPrimKey],
66
+ );
47
67
 
48
- type PreviewItem = PreviewLine | PreviewSpacer;
68
+ let { pendingStatuses, cycleStatus, save } = useTransactionEdits({
69
+ normalizedTransactions,
70
+ transactionRecordMap: transactionMap,
71
+ selectedPrimKeys,
72
+ server,
73
+ refresh,
74
+ });
49
75
 
50
- export function TransactionsPreviewDialog({ record, frameWidth }: TransactionsPreviewDialogProps) {
51
- let previewEntries = useMemo(
52
- () =>
53
- Object.entries(record)
54
- .filter(([key]) => key !== "PrimKey")
55
- .map(([key, value]) => ({ key, lines: formatPreviewValue(value) })),
56
- [record],
57
- );
76
+ let record = focusedPrimKey ? transactionMap.get(focusedPrimKey) : undefined;
77
+ let pendingStatus = focusedPrimKey ? pendingStatuses[focusedPrimKey] : undefined;
58
78
 
59
- let maxKeyLength = useMemo(
60
- () => previewEntries.reduce((max, entry) => Math.max(max, entry.key.length), 0),
61
- [previewEntries],
62
- );
79
+ let statusPreviewValue = useMemo(() => {
80
+ if (!record) {
81
+ return "";
82
+ }
83
+
84
+ let originalStatus = record.Status;
85
+ let numericOriginal =
86
+ typeof originalStatus === "number"
87
+ ? originalStatus
88
+ : typeof originalStatus === "string"
89
+ ? Number(originalStatus)
90
+ : null;
91
+
92
+ let baseText: string;
93
+ if (pendingStatus !== undefined) {
94
+ baseText = String(pendingStatus);
95
+ } else if (originalStatus === null) {
96
+ baseText = "null";
97
+ } else if (originalStatus === undefined) {
98
+ baseText = "";
99
+ } else {
100
+ baseText = String(originalStatus);
101
+ }
63
102
 
64
- let previewItems = useMemo<PreviewItem[]>(() => {
65
- if (previewEntries.length === 0) {
66
- return [];
103
+ let labelSource: number | null = null;
104
+ if (pendingStatus !== undefined) {
105
+ labelSource = pendingStatus;
106
+ } else if (numericOriginal !== null && Number.isFinite(numericOriginal)) {
107
+ labelSource = numericOriginal;
67
108
  }
68
109
 
69
- let items: PreviewItem[] = [];
70
- previewEntries.forEach((entry, entryIndex) => {
71
- entry.lines.forEach((line, lineIndex) => {
72
- items.push({
73
- type: "line",
74
- key: `${entry.key}-${lineIndex}`,
75
- entryKey: entry.key,
76
- line,
77
- lineIndex,
78
- });
79
- });
80
-
81
- if (entryIndex < previewEntries.length - 1) {
82
- items.push({ type: "spacer", key: `${entry.key}-spacer` });
110
+ if (labelSource !== null) {
111
+ let label = transactionStatusLabels[labelSource as TransactionStatusCode];
112
+ if (label) {
113
+ baseText = baseText.length > 0 ? `${baseText} (${label})` : `(${label})`;
83
114
  }
84
- });
115
+ }
116
+
117
+ let isDirty = false;
118
+ if (pendingStatus !== undefined) {
119
+ isDirty = numericOriginal === null || !Number.isFinite(numericOriginal) || pendingStatus !== numericOriginal;
120
+ }
121
+
122
+ if (isDirty) {
123
+ baseText = `${baseText}${STATUS_DIRTY_INDICATOR}`;
124
+ }
85
125
 
86
- return items;
87
- }, [previewEntries]);
126
+ return baseText;
127
+ }, [pendingStatus, record]);
88
128
 
89
- let rawKeyColumnWidth = Math.max(maxKeyLength, 1);
90
- let availableDialogWidth = Math.max(frameWidth - 4, 1);
91
- let dialogWidth = Math.min(Math.max(rawKeyColumnWidth + 80, 10), availableDialogWidth);
92
- let keyColumnWidth = Math.min(rawKeyColumnWidth, Math.max(dialogWidth - 4, 1));
129
+ let { text: transactionText, dialogWidth } = useTransactionText({
130
+ transaction: record,
131
+ statusPreviewValue,
132
+ frameWidth,
133
+ });
93
134
 
94
135
  let { height: screenHeight } = useScreenSize();
95
136
 
96
- let headerLineCount = 3 + (record.Name ? 1 : 0);
137
+ let headerLineCount = 3 + (record?.Name ? 1 : 0);
97
138
  let marginLines = 1; // Box marginTop between header and content
98
- let nonContentLines = headerLineCount + marginLines;
99
- let contentLineCount = previewItems.length > 0 ? previewItems.length : 1;
100
- let naturalDialogHeight = nonContentLines + contentLineCount;
101
- let maxDialogHeight = Math.max(screenHeight - 4, nonContentLines + 1);
102
- maxDialogHeight = Math.min(maxDialogHeight, Math.max(screenHeight - 2, 1));
103
- let dialogHeight = Math.min(naturalDialogHeight, maxDialogHeight);
104
- let contentHeight = Math.max(dialogHeight - nonContentLines, 1);
105
-
106
- let [scrollOffset, setScrollOffset] = useState(0);
139
+ let baseNonContentLines = headerLineCount + marginLines;
140
+ let contentLineCount = transactionText.length > 0 ? transactionText.length : 1;
141
+
142
+ let computeLayout = (extraNonContentLines: number) => {
143
+ let nonContentLines = baseNonContentLines + extraNonContentLines;
144
+ let naturalDialogHeight = nonContentLines + contentLineCount;
145
+ let maxDialogHeight = Math.max(screenHeight - 4, nonContentLines + 1);
146
+ maxDialogHeight = Math.min(maxDialogHeight, Math.max(screenHeight - 2, 1));
147
+ let dialogHeightValue = Math.min(naturalDialogHeight, maxDialogHeight);
148
+ let contentHeightValue = Math.max(dialogHeightValue - nonContentLines, 1);
149
+ return { dialogHeight: dialogHeightValue, contentHeight: contentHeightValue, nonContentLines };
150
+ };
151
+
152
+ let { dialogHeight, contentHeight } = computeLayout(0);
153
+ let showScrollSummary = record && transactionText.length > contentHeight;
154
+ if (showScrollSummary) {
155
+ ({ dialogHeight, contentHeight } = computeLayout(2));
156
+ }
107
157
 
108
158
  let previewSignature = useMemo(
109
- () => previewItems.map((item) => (item.type === "spacer" ? item.key : `${item.key}:${item.line}`)).join("|"),
110
- [previewItems],
159
+ () => `${focusedPrimKey ?? ""}|${transactionText.join("|")}`,
160
+ [focusedPrimKey, transactionText],
111
161
  );
112
162
 
113
- let lastPreviewSignatureRef = useRef(previewSignature);
114
-
115
- useEffect(() => {
116
- if (lastPreviewSignatureRef.current !== previewSignature) {
117
- lastPreviewSignatureRef.current = previewSignature;
118
- setScrollOffset(0);
119
- }
120
- }, [previewSignature]);
121
-
122
- let totalItems = previewItems.length;
123
- let maxScrollOffset = Math.max((totalItems || 1) - contentHeight, 0);
124
-
125
- useEffect(() => {
126
- setScrollOffset((offset) => Math.min(offset, maxScrollOffset));
127
- }, [maxScrollOffset]);
128
-
129
- useInput(
130
- (_, key) => {
131
- if (key.upArrow) {
132
- setScrollOffset((offset) => Math.max(offset - 1, 0));
133
- return;
134
- }
135
-
136
- if (key.downArrow) {
137
- setScrollOffset((offset) => Math.min(offset + 1, maxScrollOffset));
138
- return;
163
+ let { scrollOffset } = useScrollableText({
164
+ textLength: transactionText.length,
165
+ viewportHeight: contentHeight,
166
+ signature: previewSignature,
167
+ });
168
+
169
+ let { visibleText, totalLines, offset } = useVirtualText({
170
+ text: transactionText,
171
+ viewportHeight: contentHeight,
172
+ scrollOffset,
173
+ });
174
+
175
+ useCommand("left", focusPrevious, true);
176
+ useCommand("right", focusNext, true);
177
+ useCommand(
178
+ PREVIEW_SAVE_SHORTCUTS,
179
+ () => {
180
+ if (focusedPrimKey) {
181
+ save({ primKey: focusedPrimKey });
139
182
  }
140
-
141
- if (key.pageUp) {
142
- setScrollOffset((offset) => Math.max(offset - Math.max(contentHeight - 1, 1), 0));
143
- return;
144
- }
145
-
146
- if (key.pageDown) {
147
- setScrollOffset((offset) => Math.min(offset + Math.max(contentHeight - 1, 1), maxScrollOffset));
148
- return;
183
+ },
184
+ focusedPrimKey !== null,
185
+ );
186
+ useCommand(
187
+ "s",
188
+ () => {
189
+ if (focusedPrimKey) {
190
+ cycleStatus(focusedPrimKey, { exclusive: true });
149
191
  }
150
192
  },
151
- { isActive: previewItems.length > contentHeight },
193
+ focusedPrimKey !== null,
152
194
  );
153
195
 
154
- let visibleItems = previewItems.slice(scrollOffset, scrollOffset + contentHeight);
155
-
156
196
  let summaryText = useMemo(() => {
157
- let start = scrollOffset + 1;
158
- let end = Math.min(scrollOffset + contentHeight, previewItems.length);
159
- return `Showing ${start}–${end} of ${previewItems.length}`;
160
- }, [contentHeight, previewItems.length, scrollOffset]);
197
+ if (totalLines === 0) {
198
+ return "";
199
+ }
200
+
201
+ let start = offset + 1;
202
+ let end = Math.min(offset + contentHeight, totalLines);
203
+ return `Showing ${start}–${end} of ${totalLines}`;
204
+ }, [contentHeight, offset, totalLines]);
205
+
206
+ let bodyContent: ReactNode;
207
+ if (!focusedPrimKey) {
208
+ bodyContent = <Text color="gray">No transaction selected.</Text>;
209
+ } else if (error) {
210
+ bodyContent = <Text color="red">{error.message}</Text>;
211
+ } else if (!record) {
212
+ bodyContent = loading ? (
213
+ <Text color="gray">Loading transaction…</Text>
214
+ ) : (
215
+ <Text color="yellow">Transaction not found.</Text>
216
+ );
217
+ } else if (transactionText.length === 0) {
218
+ bodyContent = <Text color="gray">No data available.</Text>;
219
+ } else {
220
+ bodyContent = visibleText.map((line, index) => (
221
+ <Text key={`${offset + index}`}>{line.length > 0 ? line : " "}</Text>
222
+ ));
223
+ }
161
224
 
162
225
  return (
163
226
  <FullScreenBox position="absolute" justifyContent="center" alignItems="center">
@@ -171,32 +234,19 @@ export function TransactionsPreviewDialog({ record, frameWidth }: TransactionsPr
171
234
  backgroundColor="black"
172
235
  >
173
236
  <Text bold>Transaction preview</Text>
174
- {record.Name ? <Text>{record.Name}</Text> : null}
175
- <Text color="gray">Press Escape to close. Use ↑/↓ or PgUp/PgDn to scroll.</Text>
237
+ {record?.Name ? <Text>{record.Name}</Text> : null}
238
+ <Text color="gray">
239
+ <Shortcut keyboard="esc" command="Close preview" /> · <Shortcut keyboard="←/→" command="Change focus" /> ·{" "}
240
+ <Shortcut keyboard="↑/↓" command="Scroll" /> · <Shortcut keyboard="PgUp/PgDn" command="Scroll faster" /> ·{" "}
241
+ <Shortcut keyboard="s" command="Cycle status" /> · <Shortcut keyboard="Ctrl+S" command="Save" />
242
+ </Text>
176
243
  <Box marginTop={1} flexDirection="column" height={contentHeight}>
177
- {previewEntries.length === 0 ? (
178
- <Text color="gray">No data available.</Text>
179
- ) : (
180
- visibleItems.map((item) =>
181
- item.type === "spacer" ? (
182
- <Text key={item.key}> </Text>
183
- ) : (
184
- <Box key={item.key} flexDirection="row" alignItems="flex-start">
185
- <Box width={keyColumnWidth} marginRight={1} flexShrink={0}>
186
- <Text bold={item.lineIndex === 0} wrap="truncate-end">
187
- {item.lineIndex === 0 ? item.entryKey.padEnd(keyColumnWidth) : ""}
188
- </Text>
189
- </Box>
190
- <Box flexGrow={1} flexShrink={1}>
191
- <Text wrap="wrap">{item.line}</Text>
192
- </Box>
193
- </Box>
194
- ),
195
- )
196
- )}
244
+ {bodyContent}
197
245
  </Box>
198
- {previewEntries.length > 0 && previewItems.length > contentHeight ? (
199
- <Text color="gray">{summaryText}</Text>
246
+ {showScrollSummary ? (
247
+ <Box marginTop={1} flexDirection="column">
248
+ <Text color="gray">{summaryText}</Text>
249
+ </Box>
200
250
  ) : null}
201
251
  </Box>
202
252
  </FullScreenBox>
@@ -14,8 +14,6 @@ const STATUS_COLUMN_MIN_WIDTH = (() => {
14
14
  return Math.max("Status".length, longest + STATUS_DIRTY_INDICATOR.length);
15
15
  })();
16
16
 
17
- export const ERROR_COLUMN_MAX_LINES = 5;
18
-
19
17
  export interface TableColumn<Row> {
20
18
  key: keyof Row;
21
19
  header: string;
@@ -23,8 +21,6 @@ export interface TableColumn<Row> {
23
21
  max: number;
24
22
  weight: number;
25
23
  shrinkPriority?: number;
26
- wrap?: boolean;
27
- maxWrapLines?: number;
28
24
  }
29
25
 
30
26
  export interface EditorTransactionRow {
@@ -56,65 +52,6 @@ export function truncateCellValue(value: string, width: number) {
56
52
  return `${value.slice(0, width - 1)}…`;
57
53
  }
58
54
 
59
- export function wrapCellValue(value: string, width: number, maxLines: number) {
60
- if (width <= 0 || maxLines <= 0) {
61
- return [];
62
- }
63
-
64
- let sanitized = sanitizeCellValue(value);
65
- if (sanitized.length === 0) {
66
- return ["".padEnd(width, " ")];
67
- }
68
-
69
- let remaining = sanitized;
70
- let lines: string[] = [];
71
-
72
- while (remaining.length > 0 && lines.length < maxLines) {
73
- if (remaining.length <= width) {
74
- lines.push(remaining.padEnd(width, " "));
75
- remaining = "";
76
- break;
77
- }
78
-
79
- let sliceEnd = Math.min(width, remaining.length);
80
- let breakIndex = remaining.lastIndexOf(" ", sliceEnd);
81
- if (breakIndex <= 0) {
82
- breakIndex = sliceEnd;
83
- }
84
-
85
- let chunk = remaining.slice(0, breakIndex).trimEnd();
86
- if (chunk.length === 0) {
87
- chunk = remaining.slice(0, width);
88
- breakIndex = chunk.length;
89
- }
90
-
91
- lines.push(chunk.padEnd(width, " "));
92
- remaining = remaining.slice(breakIndex).trimStart();
93
- }
94
-
95
- if (remaining.length > 0) {
96
- let ellipsisLine: string;
97
- if (lines.length === 0) {
98
- let truncated = remaining.slice(0, Math.max(width - 1, 0));
99
- ellipsisLine = `${truncated}${width > 0 ? "…" : ""}`;
100
- } else {
101
- let last = lines.pop() ?? "";
102
- let trimmed = last.trimEnd();
103
- if (trimmed.length >= width) {
104
- trimmed = trimmed.slice(0, Math.max(width - 1, 0));
105
- }
106
- ellipsisLine = `${trimmed}${width > 0 ? "…" : ""}`;
107
- }
108
- lines.push(ellipsisLine.padEnd(width, " "));
109
- }
110
-
111
- if (lines.length === 0) {
112
- lines.push("".padEnd(width, " "));
113
- }
114
-
115
- return lines;
116
- }
117
-
118
55
  export function calculateColumnWidths<Row extends Record<string, unknown>>({
119
56
  columns,
120
57
  rows,
@@ -218,39 +155,18 @@ export function formatRowLines<Row extends Record<string, unknown>>({
218
155
  widths: number[];
219
156
  separator?: string;
220
157
  }) {
221
- let columnLines = columns.map((column, index) => {
158
+ let parts = columns.map((column, index) => {
222
159
  let width = widths[index];
223
- if (column.wrap) {
224
- let maxLines = column.maxWrapLines ?? 1;
225
- return wrapCellValue(String(row[column.key] ?? ""), width, maxLines);
226
- }
227
160
  let value = sanitizeCellValue(row[column.key]);
228
- return [truncateCellValue(value, width)];
161
+ return truncateCellValue(value, width);
229
162
  });
230
163
 
231
- let height = columnLines.reduce((max, lines) => Math.max(max, lines.length), 0);
232
- let lines: string[] = [];
233
-
234
- for (let lineIndex = 0; lineIndex < height; lineIndex++) {
235
- let parts = columnLines.map((column, index) => {
236
- let width = widths[index];
237
- let value = column[lineIndex] ?? "";
238
- if (value.length < width) {
239
- return value.padEnd(width, " ");
240
- }
241
- if (value.length > width) {
242
- return truncateCellValue(value, width);
243
- }
244
- return value;
245
- });
246
- lines.push(parts.join(separator));
247
- }
248
-
249
- if (lines.length === 0) {
250
- lines.push(columns.map((_, index) => "".padEnd(widths[index], " ")).join(separator));
164
+ let line = parts.join(separator);
165
+ if (line.length === 0) {
166
+ return [columns.map((_, index) => "".padEnd(widths[index], " ")).join(separator)];
251
167
  }
252
168
 
253
- return lines;
169
+ return [line];
254
170
  }
255
171
 
256
172
  export function addViewportEllipsis(line: string) {
@@ -308,8 +224,8 @@ export function createStatusLine(message: string, stats: string, lineWidth: numb
308
224
  export function createTransactionColumns(showError: boolean): TableColumn<EditorTransactionRow>[] {
309
225
  let columns: TableColumn<EditorTransactionRow>[] = [
310
226
  { key: "Namespace", header: "Namespace", min: 10, max: 24, weight: 0, shrinkPriority: 3 },
311
- { key: "Name", header: "Name", min: 4, max: 40, weight: 1, shrinkPriority: 1 },
312
- { key: "CreatedBy", header: "CreatedBy", min: 8, max: 20, weight: 0, shrinkPriority: 4 },
227
+ { key: "Name", header: "Name", min: 32, max: 40, weight: 1, shrinkPriority: 1 },
228
+ { key: "CreatedBy", header: "CreatedBy", min: 13, max: 20, weight: 0, shrinkPriority: 4 },
313
229
  {
314
230
  key: "Status",
315
231
  header: "Status",
@@ -328,8 +244,6 @@ export function createTransactionColumns(showError: boolean): TableColumn<Editor
328
244
  max: 120,
329
245
  weight: 2,
330
246
  shrinkPriority: 0,
331
- wrap: true,
332
- maxWrapLines: ERROR_COLUMN_MAX_LINES,
333
247
  });
334
248
  }
335
249