From 0478b87ce45e5c10c14337ee3731966e1461eecd Mon Sep 17 00:00:00 2001 From: Ainur Date: Mon, 24 Jun 2024 09:38:16 +0200 Subject: [PATCH 01/11] CB-5114 add gql api for bigquery trace info --- .../cloudbeaver/service/sql/WebSQLResultsInfo.java | 9 +++++++++ .../schema/service.sql.graphqls | 8 ++++++++ .../io/cloudbeaver/service/sql/DBWServiceSQL.java | 4 ++++ .../cloudbeaver/service/sql/WebSQLContextInfo.java | 7 ++++++- .../service/sql/WebSQLQueryDataReceiver.java | 9 ++++++++- .../service/sql/WebSQLQueryResultSet.java | 10 ++++++++++ .../service/sql/WebServiceBindingSQL.java | 6 ++++++ .../cloudbeaver/service/sql/impl/WebServiceSQL.java | 13 +++++++++++++ 8 files changed, 64 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java index 916efb4fc8..b4fee6f6e9 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java @@ -22,6 +22,7 @@ import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.data.DBDRowIdentifier; +import org.jkiss.dbeaver.model.exec.trace.DBCTrace; import org.jkiss.dbeaver.model.struct.*; import java.util.HashSet; @@ -38,6 +39,7 @@ public class WebSQLResultsInfo { @NotNull private final String id; private DBDAttributeBinding[] attributes; + private DBCTrace trace; private String queryText; public WebSQLResultsInfo(@NotNull DBSDataContainer dataContainer, @NotNull String id) { @@ -132,4 +134,11 @@ public boolean canRefreshResults() { (!(entity instanceof DBSDocumentContainer) && !entity.getDataSource().getInfo().isDynamicMetadata()); } + public DBCTrace getTrace() { + return trace; + } + + public void setTrace(@NotNull DBCTrace trace) { + this.trace = trace; + } } diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index d5ab8ee8e8..3b9629f9aa 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -402,6 +402,14 @@ extend type Mutation { asyncSqlRowDataCountResult(taskId: ID!): Int! + @since(version: "24.1.2") + sqlGetDynamicTrace( + projectId: ID, + connectionId: ID!, + contextId: ID!, + resultsId: ID! + ): Object! + @since(version: "24.0.1") asyncSqlSetAutoCommit( projectId: ID!, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java index 752357ba66..c449b47cd8 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java @@ -26,6 +26,7 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.exec.DBCLogicalOperator; +import org.jkiss.dbeaver.model.exec.trace.DBCTraceProperty; import org.jkiss.dbeaver.model.sql.registry.SQLGeneratorDescriptor; import java.util.List; @@ -106,6 +107,9 @@ WebAsyncTaskInfo asyncReadDataFromContainer( @Nullable WebSQLDataFilter filter, @Nullable WebDataFormat dataFormat) throws DBWebException; + @WebAction + List readDynamicTrace(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId) throws DBException; + @WebAction Boolean closeResult(@NotNull WebSQLContextInfo sqlContext, @NotNull String resultId) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java index 13862f2125..8b3906f373 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java @@ -29,6 +29,7 @@ import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.exec.*; +import org.jkiss.dbeaver.model.exec.trace.DBCTrace; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.qm.QMTransactionState; import org.jkiss.dbeaver.model.qm.QMUtils; @@ -143,12 +144,16 @@ public void setDefaults(String catalogName, String schemaName) throws DBWebExcep } @NotNull - public WebSQLResultsInfo saveResult(@NotNull DBSDataContainer dataContainer, @NotNull DBDAttributeBinding[] attributes) { + public WebSQLResultsInfo saveResult( + @NotNull DBSDataContainer dataContainer, + @NotNull DBCTrace trace, + @NotNull DBDAttributeBinding[] attributes) { WebSQLResultsInfo resultInfo = new WebSQLResultsInfo( dataContainer, String.valueOf(resultId.incrementAndGet()) ); resultInfo.setAttributes(attributes); + resultInfo.setTrace(trace); resultInfoMap.put(resultInfo.getId(), resultInfo); return resultInfo; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 957b322f7f..46f8d87307 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -25,6 +25,8 @@ import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.data.*; import org.jkiss.dbeaver.model.exec.*; +import org.jkiss.dbeaver.model.exec.trace.DBCTrace; +import org.jkiss.dbeaver.model.exec.trace.DBCTraceDynamic; import org.jkiss.dbeaver.model.impl.data.DBDValueError; import org.jkiss.dbeaver.model.meta.MetaData; import org.jkiss.dbeaver.model.sql.DBQuotaException; @@ -48,6 +50,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver { private final WebSQLQueryResultSet webResultSet = new WebSQLQueryResultSet(); private DBDAttributeBinding[] bindings; + private DBCTrace trace; private List rows = new ArrayList<>(); private final Number rowLimit; @@ -71,6 +74,9 @@ public void fetchStart(@NotNull DBCSession session, @NotNull DBCResultSet dbResu DBCAttributeMetaData attrMeta = attributes.get(i); bindings[i] = new DBDAttributeBindingMeta(dataContainer, dbResult.getSession(), attrMeta); } + if (dbResult instanceof DBCResultSetTrace resultSetTrace) { + this.trace = resultSetTrace.getExecutionTrace(); + } } @Override @@ -153,8 +159,9 @@ public void fetchEnd(@NotNull DBCSession session, @NotNull DBCResultSet resultSe webResultSet.setRows(List.of(rows.toArray(new WebSQLQueryResultSetRow[0]))); webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet); webResultSet.setSupportsDataFilter(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER)); + webResultSet.setHasDynamicTrace(resultSet instanceof DBCTraceDynamic); - WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, bindings); + WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, trace, bindings); webResultSet.setResultsInfo(resultsInfo); boolean isSingleEntity = DBExecUtils.detectSingleSourceTable(bindings) != null; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java index d7dba7e9cd..92882c4a7d 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java @@ -39,6 +39,7 @@ public class WebSQLQueryResultSet { private boolean hasChildrenCollection; private boolean isSupportsDataFilter; + private boolean hasDynamicTrace; public WebSQLQueryResultSet() { } @@ -132,4 +133,13 @@ public boolean isSupportsDataFilter() { public void setSupportsDataFilter(boolean supportsDataFilter) { isSupportsDataFilter = supportsDataFilter; } + + @Property + public boolean isHasDynamicTrace() { + return hasDynamicTrace; + } + + public void setHasDynamicTrace(boolean hasDynamicTrace) { + this.hasDynamicTrace = hasDynamicTrace; + } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java index 662fe6bd7e..7c5ddcd015 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java @@ -149,6 +149,12 @@ public void bindWiring(DBWBindingContext model) throws DBWebException { env.getArgument("resultsId"), env.getArgument("columnIndex"), new WebSQLResultsRow(env.getArgument("row")))) + .dataFetcher("sqlGetDynamicTrace", env -> + getService(env).readDynamicTrace( + getWebSession(env), + getSQLContext(env), + env.getArgument("resultsId") + )) .dataFetcher("updateResultsDataBatch", env -> getService(env).updateResultsDataBatch( getSQLContext(env), diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index 6658935c90..688620572d 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -36,6 +36,9 @@ import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.exec.DBCLogicalOperator; import org.jkiss.dbeaver.model.exec.DBExecUtils; +import org.jkiss.dbeaver.model.exec.trace.DBCTrace; +import org.jkiss.dbeaver.model.exec.trace.DBCTraceDynamic; +import org.jkiss.dbeaver.model.exec.trace.DBCTraceProperty; import org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect; import org.jkiss.dbeaver.model.navigator.DBNNode; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; @@ -455,6 +458,16 @@ public void run(DBRProgressMonitor monitor) throws InvocationTargetException, In return contextInfo.getProcessor().getWebSession().createAndRunAsyncTask("Read data from container " + nodePath, runnable); } + @Override + public List readDynamicTrace(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId) throws DBException { + WebSQLResultsInfo resultsInfo = contextInfo.getResults(resultsId); + DBCTrace trace = resultsInfo.getTrace(); + if (trace instanceof DBCTraceDynamic traceDynamic) { + return traceDynamic.getTraceProperties(webSession.getProgressMonitor()); + } + return null; + } + @Override public WebSQLExecuteInfo asyncGetQueryResults(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException { WebAsyncTaskInfo taskStatus = webSession.asyncTaskStatus(taskId, false); From b6e0ca10f665112aa06b633dd2d00055d57d55ae Mon Sep 17 00:00:00 2001 From: Ainur Date: Tue, 25 Jun 2024 17:35:08 +0200 Subject: [PATCH 02/11] CB-5114 add has dynamic trace to gql --- server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls | 1 + 1 file changed, 1 insertion(+) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 3b9629f9aa..b4fb96a70e 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -120,6 +120,7 @@ type SQLResultSet { # can't update data or load LOB file if hasRowIdentifier = false hasRowIdentifier: Boolean! hasChildrenCollection: Boolean! + hasDynamicTrace: Boolean! @since(version: "24.1.2") isSupportsDataFilter: Boolean! } From 819947be16a9e9ab24ac57364ba712c72f8d187f Mon Sep 17 00:00:00 2001 From: Ainur Date: Tue, 25 Jun 2024 18:30:28 +0200 Subject: [PATCH 03/11] CB-5114 has dynamic trace prop fix --- .../io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 46f8d87307..9ebd209c4a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -26,7 +26,6 @@ import org.jkiss.dbeaver.model.data.*; import org.jkiss.dbeaver.model.exec.*; import org.jkiss.dbeaver.model.exec.trace.DBCTrace; -import org.jkiss.dbeaver.model.exec.trace.DBCTraceDynamic; import org.jkiss.dbeaver.model.impl.data.DBDValueError; import org.jkiss.dbeaver.model.meta.MetaData; import org.jkiss.dbeaver.model.sql.DBQuotaException; @@ -159,7 +158,7 @@ public void fetchEnd(@NotNull DBCSession session, @NotNull DBCResultSet resultSe webResultSet.setRows(List.of(rows.toArray(new WebSQLQueryResultSetRow[0]))); webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet); webResultSet.setSupportsDataFilter(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER)); - webResultSet.setHasDynamicTrace(resultSet instanceof DBCTraceDynamic); + webResultSet.setHasDynamicTrace(trace != null); WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, trace, bindings); webResultSet.setResultsInfo(resultsInfo); From 5d580030357ed7f8c04b1737dadac5b54a1ab668 Mon Sep 17 00:00:00 2001 From: Ainur Date: Wed, 26 Jun 2024 14:52:47 +0200 Subject: [PATCH 04/11] CB-5114 fixes after review --- .../schema/service.sql.graphqls | 12 +++++++++++- .../io/cloudbeaver/service/sql/DBWServiceSQL.java | 10 +++++++++- .../cloudbeaver/service/sql/WebSQLContextInfo.java | 4 ++++ .../service/sql/WebSQLQueryDataReceiver.java | 3 ++- .../cloudbeaver/service/sql/impl/WebServiceSQL.java | 9 +++++++-- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index b4fb96a70e..db942decd4 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -212,6 +212,16 @@ type SQLScriptQuery { start: Int! end: Int! } + +#################################################### +# Dynamic trace info +#################################################### +type DynamicTraceProperty { + name: String! + value: String + description: String +} + #################################################### # Query and Mutation #################################################### @@ -409,7 +419,7 @@ extend type Mutation { connectionId: ID!, contextId: ID!, resultsId: ID! - ): Object! + ): [DynamicTraceProperty!]! @since(version: "24.0.1") asyncSqlSetAutoCommit( diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java index c449b47cd8..a7d5a95fc1 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java @@ -107,8 +107,16 @@ WebAsyncTaskInfo asyncReadDataFromContainer( @Nullable WebSQLDataFilter filter, @Nullable WebDataFormat dataFormat) throws DBWebException; + /** + * Reads dynamic trace from provided database results. + */ + @NotNull @WebAction - List readDynamicTrace(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId) throws DBException; + List readDynamicTrace( + @NotNull WebSession webSession, + @NotNull WebSQLContextInfo contextInfo, + @NotNull String resultsId + ) throws DBException; @WebAction Boolean closeResult(@NotNull WebSQLContextInfo sqlContext, @NotNull String resultId) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java index 8b3906f373..1dc81cbad9 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLContextInfo.java @@ -143,6 +143,10 @@ public void setDefaults(String catalogName, String schemaName) throws DBWebExcep } } + /** + * Saves results info into cache. + * Helps to find it with results id sent by front-end. + */ @NotNull public WebSQLResultsInfo saveResult( @NotNull DBSDataContainer dataContainer, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 9ebd209c4a..6a5800cb20 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -26,6 +26,7 @@ import org.jkiss.dbeaver.model.data.*; import org.jkiss.dbeaver.model.exec.*; import org.jkiss.dbeaver.model.exec.trace.DBCTrace; +import org.jkiss.dbeaver.model.exec.trace.DBCTraceDynamic; import org.jkiss.dbeaver.model.impl.data.DBDValueError; import org.jkiss.dbeaver.model.meta.MetaData; import org.jkiss.dbeaver.model.sql.DBQuotaException; @@ -158,7 +159,7 @@ public void fetchEnd(@NotNull DBCSession session, @NotNull DBCResultSet resultSe webResultSet.setRows(List.of(rows.toArray(new WebSQLQueryResultSetRow[0]))); webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet); webResultSet.setSupportsDataFilter(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER)); - webResultSet.setHasDynamicTrace(trace != null); + webResultSet.setHasDynamicTrace(trace instanceof DBCTraceDynamic); WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, trace, bindings); webResultSet.setResultsInfo(resultsInfo); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index 688620572d..cc52563e20 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -458,14 +458,19 @@ public void run(DBRProgressMonitor monitor) throws InvocationTargetException, In return contextInfo.getProcessor().getWebSession().createAndRunAsyncTask("Read data from container " + nodePath, runnable); } + @NotNull @Override - public List readDynamicTrace(@NotNull WebSession webSession, @NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId) throws DBException { + public List readDynamicTrace( + @NotNull WebSession webSession, + @NotNull WebSQLContextInfo contextInfo, + @NotNull String resultsId + ) throws DBException { WebSQLResultsInfo resultsInfo = contextInfo.getResults(resultsId); DBCTrace trace = resultsInfo.getTrace(); if (trace instanceof DBCTraceDynamic traceDynamic) { return traceDynamic.getTraceProperties(webSession.getProgressMonitor()); } - return null; + throw new DBWebException("Dynamic trace is not found in provided results info"); } @Override From 1bffea02b1bf8554d1519164f8b9ccd909048c34 Mon Sep 17 00:00:00 2001 From: naumov Date: Wed, 26 Jun 2024 18:53:20 +0200 Subject: [PATCH 05/11] CB-5113 add result trace details panel --- .../core-localization/src/locales/en.ts | 2 + .../core-localization/src/locales/fr.ts | 20 ++-- .../core-localization/src/locales/it.ts | 2 + .../core-localization/src/locales/ru.ts | 2 + .../core-localization/src/locales/zh.ts | 2 + .../src/queries/grid/getSqlDynamicTrace.gql | 7 ++ .../queries/grid/getSqlExecuteTaskResults.gql | 1 + .../queries/grid/updateResultsDataBatch.gql | 1 + .../.gitignore | 17 ++++ .../package.json | 40 ++++++++ .../public/icons/result_details.svg | 19 ++++ .../src/DVResultTraceDetailsBootstrap.ts | 37 ++++++++ .../src/DVResultTraceDetailsPresentation.tsx | 65 +++++++++++++ .../src/DVResultTraceDetailsService.ts | 25 +++++ .../src/LocaleService.ts | 37 ++++++++ .../ResultTraceDetailsTable/HeaderCell.tsx | 18 ++++ .../src/index.ts | 10 ++ .../src/locales/en.ts | 8 ++ .../src/locales/fr.ts | 8 ++ .../src/locales/it.ts | 8 ++ .../src/locales/ru.ts | 8 ++ .../src/locales/zh.ts | 8 ++ .../src/manifest.ts | 20 ++++ .../src/styles/styles.ts | 23 +++++ .../_base-result-trace-details-grid.scss | 55 +++++++++++ .../src/styles/themes/dark.module.scss | 18 ++++ .../src/styles/themes/light.module.scss | 18 ++++ .../src/useResultTraceDetails.tsx | 91 +++++++++++++++++++ .../tsconfig.json | 37 ++++++++ 29 files changed, 598 insertions(+), 9 deletions(-) create mode 100644 webapp/packages/core-sdk/src/queries/grid/getSqlDynamicTrace.gql create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/.gitignore create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/package.json create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsService.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/LocaleService.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/ResultTraceDetailsTable/HeaderCell.tsx create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/manifest.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/styles/styles.ts create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/_base-result-trace-details-grid.scss create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/dark.module.scss create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/light.module.scss create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json diff --git a/webapp/packages/core-localization/src/locales/en.ts b/webapp/packages/core-localization/src/locales/en.ts index d2cdff1589..65deee4ee2 100644 --- a/webapp/packages/core-localization/src/locales/en.ts +++ b/webapp/packages/core-localization/src/locales/en.ts @@ -83,6 +83,8 @@ export default [ ['ui_rename_processing', 'Renaming...'], ['ui_interval', 'Interval'], ['ui_name', 'Name'], + ['ui_value', 'Value'], + ['ui_description', 'Description'], ['ui_cant_delete_item', "This item can't be deleted"], ['ui_no_items_placeholder', 'There are no items yet.'], ['ui_search_no_result_placeholder', 'No results have been found.'], diff --git a/webapp/packages/core-localization/src/locales/fr.ts b/webapp/packages/core-localization/src/locales/fr.ts index 0ec6f36c78..53b9f61f9f 100644 --- a/webapp/packages/core-localization/src/locales/fr.ts +++ b/webapp/packages/core-localization/src/locales/fr.ts @@ -54,14 +54,14 @@ export default [ ['ui_data_saving_error', 'Erreur de sauvegarde'], ['ui_data_remove_confirmation', 'Confirmation de suppression'], ['ui_data_delete_confirmation', 'Confirmation de suppression'], - ['ui_no_matches_placeholder', 'Votre recherche n\'a retourné aucun résultat.'], + ['ui_no_matches_placeholder', "Votre recherche n'a retourné aucun résultat."], ['ui_information', 'Information'], ['ui_clipboard', 'Presse-papiers'], ['ui_copy_to_clipboard', 'Copier'], ['ui_copy_to_clipboard_copied', 'Copié'], ['ui_copy_to_clipboard_failed_to_copy', 'Échec de la copie'], ['ui_clipboard_access_denied_title', 'Accès au presse-papiers refusé'], - ['ui_clipboard_access_denied_message', 'Vous devez donner accès au presse-papiers pour utiliser certaines fonctionnalités de l\'application'], + ['ui_clipboard_access_denied_message', "Vous devez donner accès au presse-papiers pour utiliser certaines fonctionnalités de l'application"], ['ui_reveal_password', 'Afficher ou masquer le mot de passe'], ['ui_capslock_on', 'Verr Maj est activé'], ['ui_page_not_found', 'Page non trouvée'], @@ -77,8 +77,10 @@ export default [ ['ui_rename_processing', 'Renommage...'], ['ui_interval', 'Intervalle'], ['ui_name', 'Nom'], + ['ui_value', 'Value'], + ['ui_description', 'Description'], ['ui_cant_delete_item', 'Cet élément ne peut pas être supprimé'], - ['ui_no_items_placeholder', 'Il n\'y a pas encore d\'éléments.'], + ['ui_no_items_placeholder', "Il n'y a pas encore d'éléments."], ['ui_search_no_result_placeholder', 'Aucun résultat trouvé.'], ['ui_save_reminder', 'Vous avez des modifications non sauvegardées.'], ['ui_yes', 'Oui'], @@ -125,17 +127,17 @@ export default [ ['ui_export', 'Exporter'], ['ui_you', 'Vous'], - ['root_permission_denied', 'Vous n\'avez pas les permissions'], - ['root_permission_no_permission', 'Vous n\'avez pas la permission pour cette action'], - ['app_root_session_expire_warning_title', 'La session est sur le point d\'expirer'], + ['root_permission_denied', "Vous n'avez pas les permissions"], + ['root_permission_no_permission', "Vous n'avez pas la permission pour cette action"], + ['app_root_session_expire_warning_title', "La session est sur le point d'expirer"], ['app_root_session_expire_warning_message', 'Votre session expirera dans moins de 5 minutes. Pour continuer à travailler, fermez cette popup.'], ['app_root_session_expire_warning_button', 'Je suis ici'], ['app_root_session_expired_title', 'Session expirée'], ['app_root_session_expired_message', 'La session a expiré. Voulez-vous recharger ?'], ['app_root_session_expired_reload', 'Recharger'], - ['app_root_server_node_changed_title', 'L\'application a été relancée'], - ['app_root_server_node_changed_message', 'L\'application a été relancée. Veuillez recharger la page.'], + ['app_root_server_node_changed_title', "L'application a été relancée"], + ['app_root_server_node_changed_message', "L'application a été relancée. Veuillez recharger la page."], ['app_root_quota_exceeded', 'Quota dépassé'], ['app_root_event_permissions_changed_message', 'Vos permissions ont été modifiées'], - ['core_eventsLog_dbeaverErrorDetails', 'Détails de l\'erreur'], + ['core_eventsLog_dbeaverErrorDetails', "Détails de l'erreur"], ]; diff --git a/webapp/packages/core-localization/src/locales/it.ts b/webapp/packages/core-localization/src/locales/it.ts index 98c13ed403..aa67c32470 100644 --- a/webapp/packages/core-localization/src/locales/it.ts +++ b/webapp/packages/core-localization/src/locales/it.ts @@ -80,6 +80,8 @@ export default [ ['ui_rename_processing', 'Renaming...'], ['ui_interval', 'Interval'], ['ui_name', 'Name'], + ['ui_value', 'Value'], + ['ui_description', 'Description'], ['ui_cant_delete_item', "This item can't be deleted"], ['ui_no_items_placeholder', 'Non ci sono ancora elementi.'], ['ui_search_no_result_placeholder', 'Nessun risultato trovato.'], diff --git a/webapp/packages/core-localization/src/locales/ru.ts b/webapp/packages/core-localization/src/locales/ru.ts index f765a90b56..8a14f7ea36 100644 --- a/webapp/packages/core-localization/src/locales/ru.ts +++ b/webapp/packages/core-localization/src/locales/ru.ts @@ -78,6 +78,8 @@ export default [ ['ui_folder_new', 'Новая папка'], ['ui_rename_processing', 'Переименование...'], ['ui_name', 'Название'], + ['ui_value', 'Значение'], + ['ui_description', 'Описание'], ['ui_interval', 'Интервал'], ['ui_cant_delete_item', 'Этот элемент нельзя удалить'], ['ui_no_items_placeholder', 'Вы еще ничего не добавили.'], diff --git a/webapp/packages/core-localization/src/locales/zh.ts b/webapp/packages/core-localization/src/locales/zh.ts index c0c89bb2bc..8d497d42fc 100644 --- a/webapp/packages/core-localization/src/locales/zh.ts +++ b/webapp/packages/core-localization/src/locales/zh.ts @@ -79,6 +79,8 @@ export default [ ['ui_rename', '重命名'], ['ui_rename_processing', '重命名中...'], ['ui_name', '名称'], + ['ui_value', 'Value'], + ['ui_description', 'Description'], ['ui_interval', 'Interval'], ['ui_cant_delete_item', '此项目不能删除'], ['ui_no_items_placeholder', '还没有项目'], diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlDynamicTrace.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlDynamicTrace.gql new file mode 100644 index 0000000000..a7990fcaa5 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/grid/getSqlDynamicTrace.gql @@ -0,0 +1,7 @@ +mutation getSqlDynamicTrace($projectId: ID, $connectionId: ID!, $contextId: ID!, $resultsId: ID!) { + trace: sqlGetDynamicTrace(projectId: $projectId, connectionId: $connectionId, contextId: $contextId, resultsId: $resultsId) { + name + value + description + } +} diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql index 4b633ccfc1..9b1ef04431 100644 --- a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql +++ b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql @@ -41,6 +41,7 @@ mutation getSqlExecuteTaskResults($taskId: ID!) { hasRowIdentifier isSupportsDataFilter hasChildrenCollection + hasDynamicTrace } } } diff --git a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql index 306137c418..a45a1ffa71 100644 --- a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql +++ b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql @@ -32,6 +32,7 @@ mutation updateResultsDataBatch( hasRowIdentifier isSupportsDataFilter hasChildrenCollection + hasDynamicTrace } } } diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/.gitignore b/webapp/packages/plugin-data-viewer-result-trace-details/.gitignore new file mode 100644 index 0000000000..15bc16c7c3 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/.gitignore @@ -0,0 +1,17 @@ +# dependencies +/node_modules + +# testing +/coverage + +# production +/lib + +# misc +.DS_Store +.env* + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/package.json b/webapp/packages/plugin-data-viewer-result-trace-details/package.json new file mode 100644 index 0000000000..333f595dab --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/package.json @@ -0,0 +1,40 @@ +{ + "name": "@cloudbeaver/plugin-data-viewer-result-trace-details", + "sideEffects": [ + "src/**/*.css", + "src/**/*.scss", + "public/**/*" + ], + "version": "0.1.0", + "description": "", + "license": "Apache-2.0", + "main": "dist/index.js", + "scripts": { + "build": "tsc -b", + "clean": "rimraf --glob dist", + "lint": "eslint ./src/ --ext .ts,.tsx", + "lint-fix": "eslint ./src/ --ext .ts,.tsx --fix", + "validate-dependencies": "core-cli-validate-dependencies", + "update-ts-references": "yarn run clean && typescript-resolve-references" + }, + "dependencies": { + "@cloudbeaver/core-blocks": "^0", + "@cloudbeaver/core-di": "^0", + "@cloudbeaver/core-localization": "^0", + "@cloudbeaver/core-sdk": "^0", + "@cloudbeaver/core-theming": "^0", + "@cloudbeaver/core-utils": "^0", + "@cloudbeaver/plugin-data-viewer": "^0", + "@cloudbeaver/plugin-react-data-grid": "^0", + "mobx": "^6", + "mobx-react-lite": "^4", + "react": "^18" + }, + "peerDependencies": {}, + "devDependencies": { + "@cloudbeaver/core-theming": "^0", + "@types/react": "^18", + "typescript": "^5", + "typescript-plugin-css-modules": "^5" + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg new file mode 100644 index 0000000000..986c1a6014 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts new file mode 100644 index 0000000000..92e0642b08 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts @@ -0,0 +1,37 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { importLazyComponent } from '@cloudbeaver/core-blocks'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import { ResultDataFormat } from '@cloudbeaver/core-sdk'; +import { DataPresentationService, DataPresentationType } from '@cloudbeaver/plugin-data-viewer'; + +const DVResultTraceDetailsPresentation = importLazyComponent(() => + import('./DVResultTraceDetailsPresentation').then(module => module.DVResultTraceDetailsPresentation), +); + +@injectable() +export class DVResultTraceDetailsBootstrap extends Bootstrap { + constructor(private readonly dataPresentationService: DataPresentationService) { + super(); + } + + register() { + this.dataPresentationService.add({ + id: 'result-trace-details-presentation', + type: DataPresentationType.toolsPanel, + dataFormat: ResultDataFormat.Resultset, + icon: '/icons/result_details.svg', + title: 'plugin_data_viewer_result_trace_details', + hidden(dataFormat, model, resultIndex) { + const result = model.getResult(resultIndex); + return !result?.data?.hasDynamicTrace; + }, + getPresentationComponent: () => DVResultTraceDetailsPresentation, + }); + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx new file mode 100644 index 0000000000..4c40537a72 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx @@ -0,0 +1,65 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { observer } from 'mobx-react-lite'; + +import { Container, Loader, useAutoLoad, useS } from '@cloudbeaver/core-blocks'; +import { DynamicTraceProperty } from '@cloudbeaver/core-sdk'; +import { EMPTY_ARRAY } from '@cloudbeaver/core-utils'; +import type { DataPresentationComponent, IDatabaseResultSet } from '@cloudbeaver/plugin-data-viewer'; +import DataGrid, { Column } from '@cloudbeaver/plugin-react-data-grid'; + +import { HeaderCell } from './ResultTraceDetailsTable/HeaderCell'; +import { RESULT_TRACE_DETAILS_TABLE_THEME_BASE_STYLES } from './styles/styles'; +import { useResultTraceDetails } from './useResultTraceDetails'; + +const COLUMNS: Column[] = [ + { + key: 'name', + name: 'ui_name', + resizable: true, + renderCell: props =>
{props.row.name}
, + renderHeaderCell: props => , + }, + { + key: 'value', + name: 'ui_value', + resizable: true, + renderCell: props =>
{props.row.value ?? ''}
, + renderHeaderCell: props => , + }, + { + key: 'description', + name: 'ui_description', + resizable: true, + renderCell: props =>
{props.row.description ?? ''}
, + renderHeaderCell: props => , + }, +]; + +export const DVResultTraceDetailsPresentation: DataPresentationComponent = observer( + function DVResultTraceDetailsPresentation({ model, resultIndex }) { + const state = useResultTraceDetails(model, resultIndex); + + useS(RESULT_TRACE_DETAILS_TABLE_THEME_BASE_STYLES); + useAutoLoad(DVResultTraceDetailsPresentation, state); + + return ( + + + row.name} + columns={COLUMNS} + rowHeight={30} + /> + + + ); + }, +); diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsService.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsService.ts new file mode 100644 index 0000000000..f78ab4f7a5 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsService.ts @@ -0,0 +1,25 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { injectable } from '@cloudbeaver/core-di'; +import { GraphQLService } from '@cloudbeaver/core-sdk'; + +@injectable() +export class DVResultTraceDetailsService { + constructor(private readonly graphQLService: GraphQLService) {} + + async getTraceDetails(projectId: string, connectionId: string, contextId: string, resultsId: string) { + const trace = await this.graphQLService.sdk.getSqlDynamicTrace({ + projectId, + connectionId, + contextId, + resultsId, + }); + + return trace; + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/LocaleService.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/LocaleService.ts new file mode 100644 index 0000000000..f8618985f9 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/LocaleService.ts @@ -0,0 +1,37 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import { LocalizationService } from '@cloudbeaver/core-localization'; + +@injectable() +export class LocaleService extends Bootstrap { + constructor(private readonly localizationService: LocalizationService) { + super(); + } + + register(): void | Promise { + this.localizationService.addProvider(this.provider.bind(this)); + } + + load(): void | Promise {} + + private async provider(locale: string) { + switch (locale) { + case 'ru': + return (await import('./locales/ru')).default; + case 'it': + return (await import('./locales/it')).default; + case 'zh': + return (await import('./locales/zh')).default; + case 'fr': + return (await import('./locales/fr')).default; + default: + return (await import('./locales/en')).default; + } + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/ResultTraceDetailsTable/HeaderCell.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/ResultTraceDetailsTable/HeaderCell.tsx new file mode 100644 index 0000000000..c8efc1eb8e --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/ResultTraceDetailsTable/HeaderCell.tsx @@ -0,0 +1,18 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { observer } from 'mobx-react-lite'; + +import { useTranslate } from '@cloudbeaver/core-blocks'; +import { DynamicTraceProperty } from '@cloudbeaver/core-sdk'; +import type { RenderHeaderCellProps } from '@cloudbeaver/plugin-react-data-grid'; + +export const HeaderCell = observer>(function HeaderCell(props) { + const translate = useTranslate(); + + return
{typeof props.column.name === 'string' ? translate(props.column.name) : props.column.name}
; +}); diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts new file mode 100644 index 0000000000..fc3cefa395 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts @@ -0,0 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { dataViewerResultTraceDetailsPlugin } from './manifest'; + +export default dataViewerResultTraceDetailsPlugin; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts new file mode 100644 index 0000000000..112f87c8a1 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts @@ -0,0 +1,8 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +export default [['plugin_data_viewer_result_trace_details', 'Result details']]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts new file mode 100644 index 0000000000..112f87c8a1 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts @@ -0,0 +1,8 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +export default [['plugin_data_viewer_result_trace_details', 'Result details']]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts new file mode 100644 index 0000000000..112f87c8a1 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts @@ -0,0 +1,8 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +export default [['plugin_data_viewer_result_trace_details', 'Result details']]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts new file mode 100644 index 0000000000..79fcdcf53c --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts @@ -0,0 +1,8 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +export default [['plugin_data_viewer_result_trace_details', 'Детализация результата']]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts new file mode 100644 index 0000000000..112f87c8a1 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts @@ -0,0 +1,8 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +export default [['plugin_data_viewer_result_trace_details', 'Result details']]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/manifest.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/manifest.ts new file mode 100644 index 0000000000..8baf9b5970 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/manifest.ts @@ -0,0 +1,20 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import type { PluginManifest } from '@cloudbeaver/core-di'; + +export const dataViewerResultTraceDetailsPlugin: PluginManifest = { + info: { + name: 'Result trace details data viewer plugin', + }, + + providers: [ + () => import('./DVResultTraceDetailsBootstrap').then(m => m.DVResultTraceDetailsBootstrap), + () => import('./DVResultTraceDetailsService').then(m => m.DVResultTraceDetailsService), + () => import('./LocaleService').then(m => m.LocaleService), + ], +}; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/styles.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/styles.ts new file mode 100644 index 0000000000..5ac1acd7f4 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/styles.ts @@ -0,0 +1,23 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import type { ThemeSelector } from '@cloudbeaver/core-theming'; + +export const RESULT_TRACE_DETAILS_TABLE_THEME_BASE_STYLES: ThemeSelector = async theme => { + let styles: any; + + switch (theme) { + case 'dark': + styles = await import('./themes/dark.module.scss'); + break; + default: + styles = await import('./themes/light.module.scss'); + break; + } + + return [styles.default]; +}; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/_base-result-trace-details-grid.scss b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/_base-result-trace-details-grid.scss new file mode 100644 index 0000000000..61d19ba709 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/_base-result-trace-details-grid.scss @@ -0,0 +1,55 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +@import '@cloudbeaver/core-theming/src/styles/branding'; + +@mixin base-result-trace-details-grid() { + :global { + .result-trace-details-grid-container { + @include mdc-typography(caption); + + :global(input) { + @include mdc-typography(caption); + } + } + .result-trace-details-grid-container:focus-within { + .rdg-cell:global([aria-selected='true']) { + box-shadow: inset 0 0 0 1px #0091ea !important; + } + } + .result-trace-details-grid-theme { + @include mdc-typography(caption); + @include mdc-theme-prop(color, on-surface, true); + + .rdg-header-row { + @include mdc-theme-prop(background-color, surface, true); + } + + .rdg-row { + @include mdc-theme-prop(border-color, background, true); + } + + .rdg-row:hover { + @include stripes-background($mdc-theme-sub-secondary, true); + } + + .rdg-cell { + @include mdc-theme-prop(border-color, background, true); + + &:focus { + outline: 0 !important; + } + + &:global([aria-selected='true']) { + outline: 0 !important; + box-shadow: inset 0 0 0 1px #808080 !important; + } + } + } + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/dark.module.scss b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/dark.module.scss new file mode 100644 index 0000000000..0a5174edc0 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/dark.module.scss @@ -0,0 +1,18 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +@import '@cloudbeaver/core-theming/src/styles/theme-dark'; +@import './base-result-trace-details-grid'; + +:global .#{$theme-class} { + @include base-result-trace-details-grid; + + .result-trace-details-grid-theme { + --rdg-color-scheme: dark; + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/light.module.scss b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/light.module.scss new file mode 100644 index 0000000000..a5e6a645eb --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/styles/themes/light.module.scss @@ -0,0 +1,18 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +@import '@cloudbeaver/core-theming/src/styles/theme-light'; +@import './base-result-trace-details-grid'; + +:global .#{$theme-class} { + @include base-result-trace-details-grid; + + .result-trace-details-grid-theme { + --rdg-color-scheme: light; + } +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx new file mode 100644 index 0000000000..cd3fc248a0 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx @@ -0,0 +1,91 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { computed, observable } from 'mobx'; + +import { useObservableRef } from '@cloudbeaver/core-blocks'; +import { useService } from '@cloudbeaver/core-di'; +import { DynamicTraceProperty } from '@cloudbeaver/core-sdk'; +import { ILoadableState, isContainsException } from '@cloudbeaver/core-utils'; +import { IDatabaseDataModel, IDatabaseResultSet, IResultSetElementKey, ResultSetCacheAction } from '@cloudbeaver/plugin-data-viewer'; + +import { DVResultTraceDetailsService } from './DVResultTraceDetailsService'; + +interface State extends ILoadableState { + readonly trace: DynamicTraceProperty[] | undefined; + loading: boolean; + loaded: boolean; + exception: Error | null; + model: IDatabaseDataModel; + resultIndex: number; + cache: ResultSetCacheAction; +} + +const RESULT_TRACE_DETAILS_CACHE_KEY = Symbol('@cache/ResultTraceDetails'); +// @TODO Probably we want to implement a cache behavior that will only use Scope Key as sometimes we want +// a cache that only exists as long as result exists but dont want to specify row/column indexes +const FAKE_ELEMENT_KEY: IResultSetElementKey = { + column: { index: Number.MAX_SAFE_INTEGER }, + row: { index: Number.MAX_SAFE_INTEGER, subIndex: Number.MAX_SAFE_INTEGER }, +}; + +export function useResultTraceDetails(model: IDatabaseDataModel, resultIndex: number) { + const dvResultTraceDetailsService = useService(DVResultTraceDetailsService); + const cache = model.source.getAction(resultIndex, ResultSetCacheAction); + + const state = useObservableRef( + () => ({ + get trace(): DynamicTraceProperty[] | undefined { + return this.cache.get(FAKE_ELEMENT_KEY, RESULT_TRACE_DETAILS_CACHE_KEY); + }, + loading: false, + exception: null, + isLoading() { + return this.loading; + }, + isError() { + return isContainsException(this.exception); + }, + isLoaded() { + return this.trace !== undefined; + }, + async load() { + if (this.loading) { + return; + } + + const result = this.model.getResult(this.resultIndex); + + if (!result?.id) { + this.exception = new Error('Result is not found'); + return; + } + + this.loading = true; + this.exception = null; + + try { + const { trace } = await dvResultTraceDetailsService.getTraceDetails(result.projectId, result.connectionId, result.contextId, result.id); + + this.cache.set(FAKE_ELEMENT_KEY, RESULT_TRACE_DETAILS_CACHE_KEY, trace); + } catch (exception: any) { + this.exception = exception; + } finally { + this.loading = false; + } + }, + }), + { + loading: observable.ref, + exception: observable.ref, + trace: computed, + }, + { model, resultIndex, cache }, + ); + + return state; +} diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json b/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json new file mode 100644 index 0000000000..d9e5e21daa --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json @@ -0,0 +1,37 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" + }, + "references": [ + { + "path": "../core-blocks/tsconfig.json" + }, + { + "path": "../core-di/tsconfig.json" + }, + { + "path": "../core-localization/tsconfig.json" + }, + { + "path": "../core-sdk/tsconfig.json" + }, + { + "path": "../plugin-data-viewer/tsconfig.json" + } + ], + "include": [ + "__custom_mocks__/**/*", + "src/**/*", + "src/**/*.json", + "src/**/*.css", + "src/**/*.scss" + ], + "exclude": [ + "**/node_modules", + "lib/**/*", + "dist/**/*" + ] +} From b5f2ac40d74f1dbe806f4de1e4f96cb2cbf145bf Mon Sep 17 00:00:00 2001 From: naumov Date: Wed, 26 Jun 2024 18:58:04 +0200 Subject: [PATCH 06/11] CB-5113 connect plugin --- webapp/packages/product-default/package.json | 1 + webapp/packages/product-default/src/index.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/webapp/packages/product-default/package.json b/webapp/packages/product-default/package.json index 53b9c603c5..d127e18e3d 100644 --- a/webapp/packages/product-default/package.json +++ b/webapp/packages/product-default/package.json @@ -49,6 +49,7 @@ "@cloudbeaver/plugin-ddl-viewer": "^0", "@cloudbeaver/plugin-devtools": "^0", "@cloudbeaver/plugin-gis-viewer": "^0", + "@cloudbeaver/plugin-data-viewer-result-trace-details": "^0", "@cloudbeaver/plugin-help": "^0", "@cloudbeaver/plugin-localization": "^0", "@cloudbeaver/plugin-log-viewer": "^0", diff --git a/webapp/packages/product-default/src/index.ts b/webapp/packages/product-default/src/index.ts index b11cc39113..fb2d022650 100644 --- a/webapp/packages/product-default/src/index.ts +++ b/webapp/packages/product-default/src/index.ts @@ -23,6 +23,7 @@ import { dataImportPluginManifest } from '@cloudbeaver/plugin-data-import'; import { dataSpreadsheetNewManifest } from '@cloudbeaver/plugin-data-spreadsheet-new'; import { dataViewerManifest } from '@cloudbeaver/plugin-data-viewer'; import { dvResultSetGroupingPlugin } from '@cloudbeaver/plugin-data-viewer-result-set-grouping'; +import dataViewerResultTraceDetails from '@cloudbeaver/plugin-data-viewer-result-trace-details'; import { datasourceContextSwitchPluginManifest } from '@cloudbeaver/plugin-datasource-context-switch'; import { datasourceTransactionManagerPlugin } from '@cloudbeaver/plugin-datasource-transaction-manager'; import ddlViewer from '@cloudbeaver/plugin-ddl-viewer'; @@ -82,6 +83,7 @@ const PLUGINS: PluginManifest[] = [ dataExportManifest, dataImportPluginManifest, dataViewerManifest, + dataViewerResultTraceDetails, dvResultSetGroupingPlugin, gisViewer, ddlViewer, From 4a9b5be1ccc21f9fd4e578658955675adebd73a4 Mon Sep 17 00:00:00 2001 From: naumov Date: Thu, 27 Jun 2024 11:45:28 +0200 Subject: [PATCH 07/11] CB-4882 review fixes --- .../public/icons/result_details.svg | 20 +++++++++---------- .../public/icons/result_details_m.svg | 19 ++++++++++++++++++ .../public/icons/result_details_sm.svg | 19 ++++++++++++++++++ .../src/DVResultTraceDetailsBootstrap.ts | 2 +- .../src/index.ts | 1 + .../src/useResultTraceDetails.tsx | 13 ++++++------ webapp/packages/product-default/src/index.ts | 4 ++-- 7 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_m.svg create mode 100644 webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_sm.svg diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg index 986c1a6014..0c8019bbcb 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg +++ b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details.svg @@ -1,5 +1,5 @@ - + - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_m.svg b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_m.svg new file mode 100644 index 0000000000..43545d7e13 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_m.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_sm.svg b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_sm.svg new file mode 100644 index 0000000000..986c1a6014 --- /dev/null +++ b/webapp/packages/plugin-data-viewer-result-trace-details/public/icons/result_details_sm.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts index 92e0642b08..eaf8c607f6 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsBootstrap.ts @@ -25,7 +25,7 @@ export class DVResultTraceDetailsBootstrap extends Bootstrap { id: 'result-trace-details-presentation', type: DataPresentationType.toolsPanel, dataFormat: ResultDataFormat.Resultset, - icon: '/icons/result_details.svg', + icon: '/icons/result_details_sm.svg', title: 'plugin_data_viewer_result_trace_details', hidden(dataFormat, model, resultIndex) { const result = model.getResult(resultIndex); diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts index fc3cefa395..51b8e7f461 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/index.ts @@ -8,3 +8,4 @@ import { dataViewerResultTraceDetailsPlugin } from './manifest'; export default dataViewerResultTraceDetailsPlugin; +export { dataViewerResultTraceDetailsPlugin }; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx index cd3fc248a0..d0e6f402d1 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx @@ -60,15 +60,14 @@ export function useResultTraceDetails(model: IDatabaseDataModel Date: Thu, 27 Jun 2024 13:29:16 +0200 Subject: [PATCH 08/11] CB-4882 update references --- .../tsconfig.json | 12 ++++++++++++ webapp/packages/product-default/package.json | 2 +- webapp/packages/product-default/tsconfig.json | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json b/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json index d9e5e21daa..abf98fd422 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json +++ b/webapp/packages/plugin-data-viewer-result-trace-details/tsconfig.json @@ -18,8 +18,20 @@ { "path": "../core-sdk/tsconfig.json" }, + { + "path": "../core-theming/tsconfig.json" + }, + { + "path": "../core-theming/tsconfig.json" + }, + { + "path": "../core-utils/tsconfig.json" + }, { "path": "../plugin-data-viewer/tsconfig.json" + }, + { + "path": "../plugin-react-data-grid/tsconfig.json" } ], "include": [ diff --git a/webapp/packages/product-default/package.json b/webapp/packages/product-default/package.json index d127e18e3d..d9ac9077b1 100644 --- a/webapp/packages/product-default/package.json +++ b/webapp/packages/product-default/package.json @@ -44,12 +44,12 @@ "@cloudbeaver/plugin-data-spreadsheet-new": "^0", "@cloudbeaver/plugin-data-viewer": "^0", "@cloudbeaver/plugin-data-viewer-result-set-grouping": "^0", + "@cloudbeaver/plugin-data-viewer-result-trace-details": "^0", "@cloudbeaver/plugin-datasource-context-switch": "^0", "@cloudbeaver/plugin-datasource-transaction-manager": "^0", "@cloudbeaver/plugin-ddl-viewer": "^0", "@cloudbeaver/plugin-devtools": "^0", "@cloudbeaver/plugin-gis-viewer": "^0", - "@cloudbeaver/plugin-data-viewer-result-trace-details": "^0", "@cloudbeaver/plugin-help": "^0", "@cloudbeaver/plugin-localization": "^0", "@cloudbeaver/plugin-log-viewer": "^0", diff --git a/webapp/packages/product-default/tsconfig.json b/webapp/packages/product-default/tsconfig.json index 4b6043c654..cf1f6b15b9 100644 --- a/webapp/packages/product-default/tsconfig.json +++ b/webapp/packages/product-default/tsconfig.json @@ -60,6 +60,9 @@ { "path": "../plugin-data-viewer-result-set-grouping/tsconfig.json" }, + { + "path": "../plugin-data-viewer-result-trace-details/tsconfig.json" + }, { "path": "../plugin-data-viewer/tsconfig.json" }, From 2eb02c4307c8e856c2a95f2b1a48efda4496ac17 Mon Sep 17 00:00:00 2001 From: naumov Date: Thu, 27 Jun 2024 13:51:33 +0200 Subject: [PATCH 09/11] CB-4882 use suspense instead of loader --- .../src/DVResultTraceDetailsPresentation.tsx | 22 ++++++++----------- .../src/locales/en.ts | 5 ++++- .../src/locales/fr.ts | 5 ++++- .../src/locales/it.ts | 5 ++++- .../src/locales/ru.ts | 5 ++++- .../src/locales/zh.ts | 5 ++++- .../src/useResultTraceDetails.tsx | 22 ++++++++----------- 7 files changed, 38 insertions(+), 31 deletions(-) diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx index 4c40537a72..167a68f933 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx @@ -7,9 +7,8 @@ */ import { observer } from 'mobx-react-lite'; -import { Container, Loader, useAutoLoad, useS } from '@cloudbeaver/core-blocks'; +import { Container, TextPlaceholder, useAutoLoad, useS, useTranslate } from '@cloudbeaver/core-blocks'; import { DynamicTraceProperty } from '@cloudbeaver/core-sdk'; -import { EMPTY_ARRAY } from '@cloudbeaver/core-utils'; import type { DataPresentationComponent, IDatabaseResultSet } from '@cloudbeaver/plugin-data-viewer'; import DataGrid, { Column } from '@cloudbeaver/plugin-react-data-grid'; @@ -43,23 +42,20 @@ const COLUMNS: Column[] = [ export const DVResultTraceDetailsPresentation: DataPresentationComponent = observer( function DVResultTraceDetailsPresentation({ model, resultIndex }) { + const translate = useTranslate(); const state = useResultTraceDetails(model, resultIndex); useS(RESULT_TRACE_DETAILS_TABLE_THEME_BASE_STYLES); useAutoLoad(DVResultTraceDetailsPresentation, state); + if (!state.trace?.length) { + return {translate('plugin_data_viewer_result_trace_no_data_placeholder')}; + } + return ( - - - row.name} - columns={COLUMNS} - rowHeight={30} - /> - - + + row.name} columns={COLUMNS} rowHeight={30} /> + ); }, ); diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts index 112f87c8a1..fa1dbc8fe5 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/en.ts @@ -5,4 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [['plugin_data_viewer_result_trace_details', 'Result details']]; +export default [ + ['plugin_data_viewer_result_trace_details', 'Result details'], + ['plugin_data_viewer_result_trace_no_data_placeholder', 'No trace details were found'], +]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts index 112f87c8a1..fa1dbc8fe5 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/fr.ts @@ -5,4 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [['plugin_data_viewer_result_trace_details', 'Result details']]; +export default [ + ['plugin_data_viewer_result_trace_details', 'Result details'], + ['plugin_data_viewer_result_trace_no_data_placeholder', 'No trace details were found'], +]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts index 112f87c8a1..fa1dbc8fe5 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/it.ts @@ -5,4 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [['plugin_data_viewer_result_trace_details', 'Result details']]; +export default [ + ['plugin_data_viewer_result_trace_details', 'Result details'], + ['plugin_data_viewer_result_trace_no_data_placeholder', 'No trace details were found'], +]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts index 79fcdcf53c..060c0ea8b7 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/ru.ts @@ -5,4 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [['plugin_data_viewer_result_trace_details', 'Детализация результата']]; +export default [ + ['plugin_data_viewer_result_trace_details', 'Детализация результата'], + ['plugin_data_viewer_result_trace_no_data_placeholder', 'Детали результата не найдены'], +]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts index 112f87c8a1..fa1dbc8fe5 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/locales/zh.ts @@ -5,4 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [['plugin_data_viewer_result_trace_details', 'Result details']]; +export default [ + ['plugin_data_viewer_result_trace_details', 'Result details'], + ['plugin_data_viewer_result_trace_no_data_placeholder', 'No trace details were found'], +]; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx index d0e6f402d1..4d5835b5c8 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx @@ -17,7 +17,6 @@ import { DVResultTraceDetailsService } from './DVResultTraceDetailsService'; interface State extends ILoadableState { readonly trace: DynamicTraceProperty[] | undefined; - loading: boolean; loaded: boolean; exception: Error | null; model: IDatabaseDataModel; @@ -42,11 +41,8 @@ export function useResultTraceDetails(model: IDatabaseDataModel Date: Thu, 27 Jun 2024 17:15:55 +0200 Subject: [PATCH 10/11] CB-4882 use metadata to keep promise --- .../packages/core-utils/src/ILoadableState.ts | 4 +- .../src/DVResultTraceDetailsPresentation.tsx | 2 +- .../src/useResultTraceDetails.tsx | 60 ++++++++++++++----- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/webapp/packages/core-utils/src/ILoadableState.ts b/webapp/packages/core-utils/src/ILoadableState.ts index 455f5ce063..003610d1a7 100644 --- a/webapp/packages/core-utils/src/ILoadableState.ts +++ b/webapp/packages/core-utils/src/ILoadableState.ts @@ -7,15 +7,15 @@ */ export interface ILoadableState { + readonly promise?: Promise | null; + readonly exception?: (Error | null)[] | Error | null; lazy?: boolean; isLoading: () => boolean; isLoaded: () => boolean; isError: () => boolean; - readonly exception?: (Error | null)[] | Error | null; load: () => void | Promise; reload?: () => void | Promise; - promise?: Promise | null; isOutdated?: () => boolean; isCancelled?: () => boolean; cancel?: () => void; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx index 167a68f933..cc8ebe0c26 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx @@ -46,7 +46,7 @@ export const DVResultTraceDetailsPresentation: DataPresentationComponent{translate('plugin_data_viewer_result_trace_no_data_placeholder')}; diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx index 4d5835b5c8..2ea90909fa 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/useResultTraceDetails.tsx @@ -9,22 +9,34 @@ import { computed, observable } from 'mobx'; import { useObservableRef } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; -import { DynamicTraceProperty } from '@cloudbeaver/core-sdk'; +import type { DynamicTraceProperty, GetSqlDynamicTraceMutation } from '@cloudbeaver/core-sdk'; import { ILoadableState, isContainsException } from '@cloudbeaver/core-utils'; -import { IDatabaseDataModel, IDatabaseResultSet, IResultSetElementKey, ResultSetCacheAction } from '@cloudbeaver/plugin-data-viewer'; +import { + DatabaseMetadataAction, + IDatabaseDataModel, + IDatabaseResultSet, + IResultSetElementKey, + ResultSetCacheAction, +} from '@cloudbeaver/plugin-data-viewer'; import { DVResultTraceDetailsService } from './DVResultTraceDetailsService'; +type ResultTraceDetailsPromise = Promise; + +interface MetadataState { + promise: ResultTraceDetailsPromise | null; + exception: Error | null; +} interface State extends ILoadableState { readonly trace: DynamicTraceProperty[] | undefined; - loaded: boolean; - exception: Error | null; model: IDatabaseDataModel; resultIndex: number; cache: ResultSetCacheAction; + metadataState: MetadataState; } const RESULT_TRACE_DETAILS_CACHE_KEY = Symbol('@cache/ResultTraceDetails'); +const RESULT_TRACE_DETAILS_METADATA_KEY = 'result-trace-details-panel'; // @TODO Probably we want to implement a cache behavior that will only use Scope Key as sometimes we want // a cache that only exists as long as result exists but dont want to specify row/column indexes const FAKE_ELEMENT_KEY: IResultSetElementKey = { @@ -35,14 +47,26 @@ const FAKE_ELEMENT_KEY: IResultSetElementKey = { export function useResultTraceDetails(model: IDatabaseDataModel, resultIndex: number) { const dvResultTraceDetailsService = useService(DVResultTraceDetailsService); const cache = model.source.getAction(resultIndex, ResultSetCacheAction); + const metadataAction = model.source.getAction(resultIndex, DatabaseMetadataAction); + + const metadataState = metadataAction.get(RESULT_TRACE_DETAILS_METADATA_KEY, () => + observable({ + promise: null, + exception: null, + }), + ); const state = useObservableRef( () => ({ get trace(): DynamicTraceProperty[] | undefined { return this.cache.get(FAKE_ELEMENT_KEY, RESULT_TRACE_DETAILS_CACHE_KEY); }, - promise: null, - exception: null, + get promise(): ResultTraceDetailsPromise | null { + return this.metadataState.promise; + }, + get exception(): Error | null { + return this.metadataState.exception; + }, isError() { return isContainsException(this.exception); }, @@ -57,29 +81,35 @@ export function useResultTraceDetails(model: IDatabaseDataModel Date: Fri, 28 Jun 2024 18:30:49 +0200 Subject: [PATCH 11/11] CB-4882 add overflow to container --- .../src/DVResultTraceDetailsPresentation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx index cc8ebe0c26..7d6aec6703 100644 --- a/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx +++ b/webapp/packages/plugin-data-viewer-result-trace-details/src/DVResultTraceDetailsPresentation.tsx @@ -53,7 +53,7 @@ export const DVResultTraceDetailsPresentation: DataPresentationComponent + row.name} columns={COLUMNS} rowHeight={30} /> );