diff --git a/CHANGELOG.md b/CHANGELOG.md index ea37d35f..436f9c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Column totals for Grouped rows will now be shown inside the groups instead of on a seperate row ([#583][#583]). +- Table actions: Copy to clipboard and Export to CSV directly from the button above the Analysis and Database table ([#589]). ### Changed @@ -384,6 +385,7 @@ Skipped due to adopting odd numbering for pre releases and even number for relea [#582]: https://github.com/certinia/debug-log-analyzer/issues/582 [#588]: https://github.com/certinia/debug-log-analyzer/issues/588 [#583]: https://github.com/certinia/debug-log-analyzer/issues/583 +[#589]: https://github.com/certinia/debug-log-analyzer/issues/589 diff --git a/README.md b/README.md index ab53ab08..515f27b6 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Apex Log Analyzer makes performance analysis of Salesforce debug logs much easier and quicker. Visualize code execution via a Flame chart and Call Tree, identify and resolve performance and SOQL/DML problems via Method and Database Analysis. +Visualize code execution via a Flame chart and identify performance and SOQL/DML problems via Method and Database analysis + ![preview](https://raw.githubusercontent.com/certinia/debug-log-analyzer/main/lana/dist/images/lana-preview.gif) ## WARNING @@ -163,8 +165,8 @@ The rows can be grouped by Type or Namespace #### Export to CSV + copy to clipboard -Click the header menu,`⋮`, and use `Export to CSV` to save the table content to a file. -Focus the Analysis table and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. +Use `Export to CSV` above the table to save the table content to a file or `Copy to Clipboard`. +You can also focus the Analysis table and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. ### Database @@ -202,8 +204,8 @@ For SOQL rows, to the right of the Call Stack is SOQL Analysis which shows infor #### Export to CSV + copy to clipboard -Click the header menu,`⋮`, and use `Export to CSV` to save the table content to a file. -Focus the Analysis table and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. +Use `Export to CSV` above the table to save the table content to a file or `Copy to Clipboard`. +You can also focus the DML/ SOQL tables and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. ### Find diff --git a/lana-docs-site/docs/docs/features.md b/lana-docs-site/docs/docs/features.md index 4383fdd5..3c886ed2 100644 --- a/lana-docs-site/docs/docs/features.md +++ b/lana-docs-site/docs/docs/features.md @@ -91,8 +91,8 @@ The rows can be grouped by Type or Namespace ### Export to CSV + copy to clipboard -Click the header menu,`⋮`, and use `Export to CSV` to save the table content to a file. -Focus the Analysis table and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. +Use `Export to CSV` above the table to save the table content to a file or `Copy to Clipboard`. +You can also focus the Analysis tables and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. ## 💾 Database @@ -130,8 +130,8 @@ For SOQL rows, to the right of the Call Stack is SOQL Analysis which shows infor ### Export to CSV + copy to clipboard -Click the header menu,`⋮`, and use `Export to CSV` to save the table content to a file. -Focus the Analysis table and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. +Use `Export to CSV` above the table to save the table content to a file or `Copy to Clipboard`. +You can also focus the DML/ SOQL tables and use `CMD / CTRL + c` to copy the table content to clipboard. This can then be pasted into a spreadsheet or other file. ## 🔍 Find diff --git a/log-viewer/modules/components/analysis-view/AnalysisView.ts b/log-viewer/modules/components/analysis-view/AnalysisView.ts index 019fa6ea..343cb693 100644 --- a/log-viewer/modules/components/analysis-view/AnalysisView.ts +++ b/log-viewer/modules/components/analysis-view/AnalysisView.ts @@ -3,39 +3,47 @@ */ import { provideVSCodeDesignSystem, + vsCodeButton, vsCodeCheckbox, vsCodeDropdown, vsCodeOption, } from '@vscode/webview-ui-toolkit'; import { LitElement, css, html, unsafeCSS, type PropertyValues } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { Tabulator, type ColumnComponent, type RowComponent } from 'tabulator-tables'; -import * as CommonModules from '../../datagrid/module/CommonModules.js'; - -import NumberAccessor from '../../datagrid/dataaccessor/Number.js'; -import { progressFormatter } from '../../datagrid/format/Progress.js'; -import { RowKeyboardNavigation } from '../../datagrid/module/RowKeyboardNavigation.js'; -import dataGridStyles from '../../datagrid/style/DataGrid.scss'; import { ApexLog, LogLine } from '../../parsers/ApexLogParser.js'; import { vscodeMessenger } from '../../services/VSCodeExtensionMessenger.js'; import { globalStyles } from '../../styles/global.styles.js'; -import { isVisible } from '../../Util.js'; +// Tabulator custom modules, imports + styles +import { Tabulator, type RowComponent } from 'tabulator-tables'; +import { isVisible } from '../../Util.js'; +import NumberAccessor from '../../datagrid/dataaccessor/Number.js'; +import { progressFormatter } from '../../datagrid/format/Progress.js'; +import { GroupCalcs } from '../../datagrid/group-calcs/GroupCalcs.js'; +import * as CommonModules from '../../datagrid/module/CommonModules.js'; +import { RowKeyboardNavigation } from '../../datagrid/module/RowKeyboardNavigation.js'; import { RowNavigation } from '../../datagrid/module/RowNavigation.js'; +import dataGridStyles from '../../datagrid/style/DataGrid.scss'; +import codiconStyles from '../../styles/codicon.css'; import { Find, formatter } from '../calltree-view/module/Find.js'; import { callStackSum } from './column-calcs/CallStackSum.js'; -import { GroupCalcs } from '../../datagrid/group-calcs/GroupCalcs.js'; - // Components +import '../datagrid/datagrid-filter-bar.js'; import '../skeleton/GridSkeleton.js'; -provideVSCodeDesignSystem().register(vsCodeCheckbox(), vsCodeDropdown(), vsCodeOption()); +provideVSCodeDesignSystem().register( + vsCodeButton(), + vsCodeCheckbox(), + vsCodeDropdown(), + vsCodeOption(), +); @customElement('analysis-view') export class AnalysisView extends LitElement { static styles = [ unsafeCSS(dataGridStyles), + unsafeCSS(codiconStyles), globalStyles, css` :host { @@ -58,15 +66,15 @@ export class AnalysisView extends LitElement { flex-flow: column nowrap; align-items: flex-start; justify-content: flex-start; - } - .dropdown-container label { - display: block; - color: var(--vscode-foreground); - cursor: pointer; - font-size: var(--vscode-font-size); - line-height: normal; - margin-bottom: 2px; + label { + display: block; + color: var(--vscode-foreground); + cursor: pointer; + font-size: var(--vscode-font-size); + line-height: normal; + margin-bottom: 2px; + } } `, ]; @@ -106,16 +114,36 @@ export class AnalysisView extends LitElement { const skeleton = !this.timelineRoot ? html`` : ''; return html` -
- + +
+ + + + + + +
+ +
${skeleton}
@@ -123,6 +151,14 @@ export class AnalysisView extends LitElement { `; } + _copyToClipboard() { + this.analysisTable?.copyToClipboard('all'); + } + + _exportToCSV() { + this.analysisTable?.download('csv', 'analysis.csv', { bom: true, delimiter: ',' }); + } + get _tableWrapper(): HTMLDivElement | null | undefined { return (this.tableContainer ??= this.renderRoot?.querySelector('#analysis-table')); } @@ -197,15 +233,6 @@ export class AnalysisView extends LitElement { } const metricList = groupMetrics(rootMethod); - const headerMenu = [ - { - label: 'Export to CSV', - action: function (_e: PointerEvent, column: ColumnComponent) { - column.getTable().download('csv', 'analysis.csv', { bom: true, delimiter: ',' }); - }, - }, - ]; - Tabulator.registerModule(Object.values(CommonModules)); Tabulator.registerModule([RowKeyboardNavigation, RowNavigation, Find, GroupCalcs]); this.analysisTable = new Tabulator(this._tableWrapper, { @@ -254,7 +281,6 @@ export class AnalysisView extends LitElement { resizable: true, headerSortStartingDir: 'desc', headerTooltip: true, - headerMenu: headerMenu, headerWordWrap: true, }, initialSort: [{ column: 'selfTime', dir: 'desc' }], diff --git a/log-viewer/modules/components/database-view/DMLView.ts b/log-viewer/modules/components/database-view/DMLView.ts index dc875d88..fc18a495 100644 --- a/log-viewer/modules/components/database-view/DMLView.ts +++ b/log-viewer/modules/components/database-view/DMLView.ts @@ -1,15 +1,14 @@ /* * Copyright (c) 2022 Certinia Inc. All rights reserved. */ -import { provideVSCodeDesignSystem, vsCodeCheckbox } from '@vscode/webview-ui-toolkit'; +import { + provideVSCodeDesignSystem, + vsCodeButton, + vsCodeCheckbox, +} from '@vscode/webview-ui-toolkit'; import { LitElement, css, html, render, unsafeCSS, type PropertyValues } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { - Tabulator, - type ColumnComponent, - type GroupComponent, - type RowComponent, -} from 'tabulator-tables'; +import { Tabulator, type GroupComponent, type RowComponent } from 'tabulator-tables'; // tabulator custom modules import * as CommonModules from '../../datagrid/module/CommonModules.js'; @@ -27,6 +26,7 @@ import dataGridStyles from '../../datagrid/style/DataGrid.scss'; import { DatabaseAccess } from '../../Database.js'; import { ApexLog, DMLBeginLine } from '../../parsers/ApexLogParser.js'; import { vscodeMessenger } from '../../services/VSCodeExtensionMessenger.js'; +import codiconStyles from '../../styles/codicon.css'; import { globalStyles } from '../../styles/global.styles.js'; import { isVisible } from '../../Util.js'; import databaseViewStyles from './DatabaseView.scss'; @@ -35,7 +35,7 @@ import databaseViewStyles from './DatabaseView.scss'; import '../CallStack.js'; import './DatabaseSection.js'; -provideVSCodeDesignSystem().register(vsCodeCheckbox()); +provideVSCodeDesignSystem().register(vsCodeButton(), vsCodeCheckbox()); @customElement('dml-view') export class DMLView extends LitElement { @@ -86,6 +86,7 @@ export class DMLView extends LitElement { static styles = [ unsafeCSS(dataGridStyles), unsafeCSS(databaseViewStyles), + unsafeCSS(codiconStyles), globalStyles, css` :host { @@ -112,12 +113,35 @@ export class DMLView extends LitElement { return html` -
- Group by -
- DML + + +
+ Group by +
+ DML +
-
+ +
+ + + + + + +
+ +
${dmlSkeleton}
@@ -125,6 +149,14 @@ export class DMLView extends LitElement { `; } + _copyToClipboard() { + this.dmlTable?.copyToClipboard('all'); + } + + _exportToCSV() { + this.dmlTable?.download('csv', 'dml.csv', { bom: true, delimiter: ',' }); + } + _findEvt = ((event: FindEvt) => this._find(event)) as EventListener; _dmlGroupBy(event: Event) { @@ -261,7 +293,6 @@ export class DMLView extends LitElement { resizable: true, headerSortStartingDir: 'desc', headerTooltip: true, - headerMenu: this.csvheaderMenu('dml.csv'), headerWordWrap: true, }, initialSort: [{ column: 'rowCount', dir: 'desc' }], @@ -436,17 +467,6 @@ export class DMLView extends LitElement { return [...newMap.keys()]; } - csvheaderMenu(csvFileName: string) { - return [ - { - label: 'Export to CSV', - action: function (_e: PointerEvent, column: ColumnComponent) { - column.getTable().download('csv', csvFileName, { bom: true, delimiter: ',' }); - }, - }, - ]; - } - downlodEncoder(defaultFileName: string) { return function (fileContents: string, mimeType: string) { const vscode = vscodeMessenger.getVsCodeAPI(); diff --git a/log-viewer/modules/components/database-view/SOQLView.ts b/log-viewer/modules/components/database-view/SOQLView.ts index 2bf295ec..e9d3882e 100644 --- a/log-viewer/modules/components/database-view/SOQLView.ts +++ b/log-viewer/modules/components/database-view/SOQLView.ts @@ -3,6 +3,7 @@ */ import { provideVSCodeDesignSystem, + vsCodeButton, vsCodeDropdown, vsCodeOption, } from '@vscode/webview-ui-toolkit'; @@ -36,6 +37,7 @@ import { SOQLExecuteExplainLine, } from '../../parsers/ApexLogParser.js'; import { vscodeMessenger } from '../../services/VSCodeExtensionMessenger.js'; +import codiconStyles from '../../styles/codicon.css'; import { globalStyles } from '../../styles/global.styles.js'; import databaseViewStyles from './DatabaseView.scss'; @@ -44,7 +46,7 @@ import '../CallStack.js'; import './DatabaseSOQLDetailPanel.js'; import './DatabaseSection.js'; -provideVSCodeDesignSystem().register(vsCodeDropdown(), vsCodeOption()); +provideVSCodeDesignSystem().register(vsCodeButton(), vsCodeDropdown(), vsCodeOption()); @customElement('soql-view') export class SOQLView extends LitElement { @@ -99,6 +101,7 @@ export class SOQLView extends LitElement { static styles = [ unsafeCSS(dataGridStyles), unsafeCSS(databaseViewStyles), + unsafeCSS(codiconStyles), globalStyles, css` :host { @@ -117,25 +120,21 @@ export class SOQLView extends LitElement { margin-bottom: 1rem; } - .filter-container { - margin-bottom: 1rem; - } - .dropdown-container { box-sizing: border-box; display: flex; flex-flow: column nowrap; align-items: flex-start; justify-content: flex-start; - } - .dropdown-container label { - display: block; - color: var(--vscode-foreground); - cursor: pointer; - font-size: var(--vscode-font-size); - line-height: normal; - margin-bottom: 2px; + label { + display: block; + color: var(--vscode-foreground); + cursor: pointer; + font-size: var(--vscode-font-size); + line-height: normal; + margin-bottom: 2px; + } } `, ]; @@ -144,16 +143,37 @@ export class SOQLView extends LitElement { const soqlSkeleton = !this.timelineRoot ? html`` : ``; return html` -
- + +
+ + + + + + +
+ +
${soqlSkeleton}
@@ -161,6 +181,14 @@ export class SOQLView extends LitElement { `; } + _copyToClipboard() { + this.soqlTable?.copyToClipboard('all'); + } + + _exportToCSV() { + this.soqlTable?.download('csv', 'soql.csv', { bom: true, delimiter: ',' }); + } + _findEvt = ((event: FindEvt) => this._find(event)) as EventListener; _soqlGroupBy(event: Event) { @@ -313,7 +341,6 @@ export class SOQLView extends LitElement { resizable: true, headerSortStartingDir: 'desc', headerTooltip: true, - headerMenu: this.csvheaderMenu('soql.csv'), headerWordWrap: true, }, initialSort: [{ column: 'rowCount', dir: 'desc' }], @@ -583,17 +610,6 @@ export class SOQLView extends LitElement { return [...newMap.keys()]; } - csvheaderMenu(csvFileName: string) { - return [ - { - label: 'Export to CSV', - action: function (_e: PointerEvent, column: ColumnComponent) { - column.getTable().download('csv', csvFileName, { bom: true, delimiter: ',' }); - }, - }, - ]; - } - downlodEncoder(defaultFileName: string) { return function (fileContents: string, mimeType: string) { const vscode = vscodeMessenger.getVsCodeAPI(); diff --git a/log-viewer/modules/components/datagrid/datagrid-filter-bar.ts b/log-viewer/modules/components/datagrid/datagrid-filter-bar.ts new file mode 100644 index 00000000..c4524006 --- /dev/null +++ b/log-viewer/modules/components/datagrid/datagrid-filter-bar.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Certinia Inc. All rights reserved. + */ +import { provideVSCodeDesignSystem } from '@vscode/webview-ui-toolkit'; +import { LitElement, css, html } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +import { globalStyles } from '../../styles/global.styles.js'; + +provideVSCodeDesignSystem().register(); + +@customElement('datagrid-filter-bar') +export class DatagridFilterBar extends LitElement { + static styles = [ + globalStyles, + css` + :host { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + flex: 1; + } + + .filter-bar { + display: flex; + } + + .filter-bar .filter-bar__actions--right { + align-items: center; + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + } + `, + ]; + + render() { + return html`
+
+ + +
+ +
+ +
+
`; + } +}