Frontend improvements for Databases plugin
Summary: Specs here: https://fb.quip.com/aPPOAWMraRMT Screenshots: https://pxl.cl/Gngf https://pxl.cl/Gngg https://pxl.cl/Gngd https://pxl.cl/GxQr https://pxl.cl/Gngh https://pxl.cl/Gngk https://pxl.cl/Gngl https://pxl.cl/Gngm Reviewed By: quanturium Differential Revision: D16266093 fbshipit-source-id: a5408b974875dcabcbd6055ccbb2818d0c1b25f6
This commit is contained in:
committed by
Facebook Github Bot
parent
dbf0e3db43
commit
fe56c8471c
@@ -1,7 +1,6 @@
|
|||||||
[ignore]
|
[ignore]
|
||||||
.*/scripts/.*
|
.*/scripts/.*
|
||||||
.*/coverage/.*
|
.*/coverage/.*
|
||||||
.*/node_modules/.*
|
|
||||||
.*/build/.*
|
.*/build/.*
|
||||||
.*/dist/.*
|
.*/dist/.*
|
||||||
.*/static/.*
|
.*/static/.*
|
||||||
@@ -9,6 +8,7 @@
|
|||||||
.*/website/.*
|
.*/website/.*
|
||||||
<PROJECT_ROOT>/src/plugins/sections/d3/d3.js$
|
<PROJECT_ROOT>/src/plugins/sections/d3/d3.js$
|
||||||
.*\.tsx
|
.*\.tsx
|
||||||
|
.*flow-typed/.*
|
||||||
|
|
||||||
[libs]
|
[libs]
|
||||||
flow-typed
|
flow-typed
|
||||||
|
|||||||
@@ -173,11 +173,14 @@ public class ObjectMapper {
|
|||||||
DatabaseExecuteSqlResponse databaseExecuteSqlResponse) {
|
DatabaseExecuteSqlResponse databaseExecuteSqlResponse) {
|
||||||
|
|
||||||
FlipperArray.Builder columnBuilder = new FlipperArray.Builder();
|
FlipperArray.Builder columnBuilder = new FlipperArray.Builder();
|
||||||
|
if (databaseExecuteSqlResponse.columns != null) {
|
||||||
for (String columnName : databaseExecuteSqlResponse.columns) {
|
for (String columnName : databaseExecuteSqlResponse.columns) {
|
||||||
columnBuilder.put(columnName);
|
columnBuilder.put(columnName);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FlipperArray.Builder rowBuilder = new FlipperArray.Builder();
|
FlipperArray.Builder rowBuilder = new FlipperArray.Builder();
|
||||||
|
if (databaseExecuteSqlResponse.values != null) {
|
||||||
for (List<Object> row : databaseExecuteSqlResponse.values) {
|
for (List<Object> row : databaseExecuteSqlResponse.values) {
|
||||||
FlipperArray.Builder valueBuilder = new FlipperArray.Builder();
|
FlipperArray.Builder valueBuilder = new FlipperArray.Builder();
|
||||||
for (Object item : row) {
|
for (Object item : row) {
|
||||||
@@ -185,6 +188,7 @@ public class ObjectMapper {
|
|||||||
}
|
}
|
||||||
rowBuilder.put(valueBuilder.build());
|
rowBuilder.put(valueBuilder.build());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new FlipperObject.Builder()
|
return new FlipperObject.Builder()
|
||||||
.put("type", databaseExecuteSqlResponse.type)
|
.put("type", databaseExecuteSqlResponse.type)
|
||||||
|
|||||||
193
flow-typed/npm/sql-formatter_vx.x.x.js
vendored
Normal file
193
flow-typed/npm/sql-formatter_vx.x.x.js
vendored
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
// flow-typed signature: 21bf70a7f73a77579f4cc048adda0919
|
||||||
|
// flow-typed version: <<STUB>>/sql-formatter_v2.3.3/flow_v0.102.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an autogenerated libdef stub for:
|
||||||
|
*
|
||||||
|
* 'sql-formatter'
|
||||||
|
*
|
||||||
|
* Fill this stub out by replacing all the `any` types.
|
||||||
|
*
|
||||||
|
* Once filled out, we encourage you to share your work with the
|
||||||
|
* community by sending a pull request to:
|
||||||
|
* https://github.com/flowtype/flow-typed
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare module 'sql-formatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We include stubs for each file inside this npm package in case you need to
|
||||||
|
* require those files directly. Feel free to delete any files that aren't
|
||||||
|
* needed.
|
||||||
|
*/
|
||||||
|
declare module 'sql-formatter/dist/sql-formatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/dist/sql-formatter.min' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/core/Formatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/core/Indentation' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/core/InlineBlock' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/core/Params' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/core/Tokenizer' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/core/tokenTypes' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/languages/Db2Formatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/languages/N1qlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/languages/PlSqlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/languages/StandardSqlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/lib/sqlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/core/Formatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/core/Indentation' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/core/InlineBlock' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/core/Params' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/core/Tokenizer' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/core/tokenTypes' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/languages/Db2Formatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/languages/N1qlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/languages/PlSqlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/languages/StandardSqlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'sql-formatter/src/sqlFormatter' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filename aliases
|
||||||
|
declare module 'sql-formatter/dist/sql-formatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/dist/sql-formatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/dist/sql-formatter.min.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/dist/sql-formatter.min'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/core/Formatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/core/Formatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/core/Indentation.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/core/Indentation'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/core/InlineBlock.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/core/InlineBlock'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/core/Params.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/core/Params'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/core/Tokenizer.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/core/Tokenizer'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/core/tokenTypes.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/core/tokenTypes'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/languages/Db2Formatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/languages/Db2Formatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/languages/N1qlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/languages/N1qlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/languages/PlSqlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/languages/PlSqlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/languages/StandardSqlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/languages/StandardSqlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/lib/sqlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/lib/sqlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/core/Formatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/core/Formatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/core/Indentation.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/core/Indentation'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/core/InlineBlock.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/core/InlineBlock'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/core/Params.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/core/Params'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/core/Tokenizer.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/core/Tokenizer'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/core/tokenTypes.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/core/tokenTypes'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/languages/Db2Formatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/languages/Db2Formatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/languages/N1qlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/languages/N1qlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/languages/PlSqlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/languages/PlSqlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/languages/StandardSqlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/languages/StandardSqlFormatter'>;
|
||||||
|
}
|
||||||
|
declare module 'sql-formatter/src/sqlFormatter.js' {
|
||||||
|
declare module.exports: $Exports<'sql-formatter/src/sqlFormatter'>;
|
||||||
|
}
|
||||||
@@ -48,6 +48,28 @@ type GetTableStructureResponse = {
|
|||||||
definition: string,
|
definition: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ExecuteSqlRequest = {
|
||||||
|
databaseId: number,
|
||||||
|
value: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExecuteSqlResponse = {
|
||||||
|
type: string,
|
||||||
|
columns: Array<string>,
|
||||||
|
values: Array<Array<Value>>,
|
||||||
|
insertedId: number,
|
||||||
|
affectedCount: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
type GetTableInfoRequest = {
|
||||||
|
databaseId: number,
|
||||||
|
table: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type GetTableInfoResponse = {
|
||||||
|
definition: string,
|
||||||
|
};
|
||||||
|
|
||||||
export class DatabaseClient {
|
export class DatabaseClient {
|
||||||
client: PluginClient;
|
client: PluginClient;
|
||||||
|
|
||||||
@@ -67,4 +89,12 @@ export class DatabaseClient {
|
|||||||
GetTableStructureRequest,
|
GetTableStructureRequest,
|
||||||
GetTableStructureResponse,
|
GetTableStructureResponse,
|
||||||
> = params => this.client.call('getTableStructure', params);
|
> = params => this.client.call('getTableStructure', params);
|
||||||
|
|
||||||
|
getExecution: ClientCall<ExecuteSqlRequest, ExecuteSqlResponse> = params =>
|
||||||
|
this.client.call('execute', params);
|
||||||
|
|
||||||
|
getTableInfo: ClientCall<
|
||||||
|
GetTableInfoRequest,
|
||||||
|
GetTableInfoResponse,
|
||||||
|
> = params => this.client.call('getTableInfo', params);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
colors,
|
colors,
|
||||||
getStringFromErrorLike,
|
getStringFromErrorLike,
|
||||||
|
Spacer,
|
||||||
|
Textarea,
|
||||||
|
DetailSidebar,
|
||||||
|
Panel,
|
||||||
|
ManagedDataInspector,
|
||||||
} from 'flipper';
|
} from 'flipper';
|
||||||
import {Component} from 'react';
|
import {Component} from 'react';
|
||||||
import type {
|
import type {
|
||||||
@@ -29,6 +34,8 @@ import {DatabaseClient} from './ClientProtocol';
|
|||||||
import {renderValue} from 'flipper';
|
import {renderValue} from 'flipper';
|
||||||
import type {Value} from 'flipper';
|
import type {Value} from 'flipper';
|
||||||
import ButtonNavigation from './ButtonNavigation';
|
import ButtonNavigation from './ButtonNavigation';
|
||||||
|
import sqlFormatter from 'sql-formatter';
|
||||||
|
import dateFormat from 'dateformat';
|
||||||
|
|
||||||
const PAGE_SIZE = 50;
|
const PAGE_SIZE = 50;
|
||||||
|
|
||||||
@@ -51,11 +58,17 @@ type DatabasesPluginState = {|
|
|||||||
pageRowNumber: number,
|
pageRowNumber: number,
|
||||||
databases: Array<DatabaseEntry>,
|
databases: Array<DatabaseEntry>,
|
||||||
outdatedDatabaseList: boolean,
|
outdatedDatabaseList: boolean,
|
||||||
viewMode: 'data' | 'structure',
|
viewMode: 'data' | 'structure' | 'SQL' | 'tableInfo' | 'queryHistory',
|
||||||
error: ?null,
|
error: ?null,
|
||||||
currentPage: ?Page,
|
currentPage: ?Page,
|
||||||
currentStructure: ?Structure,
|
currentStructure: ?Structure,
|
||||||
currentSort: ?TableRowSortOrder,
|
currentSort: ?TableRowSortOrder,
|
||||||
|
query: ?Query,
|
||||||
|
queryResult: ?QueryResult,
|
||||||
|
favorites: Array<string>,
|
||||||
|
executionTime: number,
|
||||||
|
tableInfo: string,
|
||||||
|
queryHistory: Array<Query>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
type Page = {
|
type Page = {
|
||||||
@@ -77,6 +90,18 @@ type Structure = {|
|
|||||||
indexesValues: Array<TableBodyRow>,
|
indexesValues: Array<TableBodyRow>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
type QueryResult = {
|
||||||
|
table: ?QueriedTable,
|
||||||
|
id: ?number,
|
||||||
|
count: ?number,
|
||||||
|
};
|
||||||
|
|
||||||
|
type QueriedTable = {
|
||||||
|
columns: Array<string>,
|
||||||
|
rows: Array<TableBodyRow>,
|
||||||
|
highlightedRows: Array<number>,
|
||||||
|
};
|
||||||
|
|
||||||
type Actions =
|
type Actions =
|
||||||
| SelectDatabaseEvent
|
| SelectDatabaseEvent
|
||||||
| SelectDatabaseTableEvent
|
| SelectDatabaseTableEvent
|
||||||
@@ -84,11 +109,18 @@ type Actions =
|
|||||||
| UpdateViewModeEvent
|
| UpdateViewModeEvent
|
||||||
| UpdatePageEvent
|
| UpdatePageEvent
|
||||||
| UpdateStructureEvent
|
| UpdateStructureEvent
|
||||||
|
| DisplaySelectEvent
|
||||||
|
| DisplayInsertEvent
|
||||||
|
| DisplayUpdateDeleteEvent
|
||||||
|
| UpdateTableInfoEvent
|
||||||
| NextPageEvent
|
| NextPageEvent
|
||||||
| PreviousPageEvent
|
| PreviousPageEvent
|
||||||
|
| ExecuteEvent
|
||||||
| RefreshEvent
|
| RefreshEvent
|
||||||
|
| UpdateFavoritesEvent
|
||||||
| SortByChangedEvent
|
| SortByChangedEvent
|
||||||
| GoToRowEvent;
|
| GoToRowEvent
|
||||||
|
| UpdateQueryEvent;
|
||||||
|
|
||||||
type DatabaseEntry = {
|
type DatabaseEntry = {
|
||||||
id: number,
|
id: number,
|
||||||
@@ -96,6 +128,11 @@ type DatabaseEntry = {
|
|||||||
tables: Array<string>,
|
tables: Array<string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Query = {|
|
||||||
|
value: string,
|
||||||
|
time: string,
|
||||||
|
|};
|
||||||
|
|
||||||
type UpdateDatabasesEvent = {|
|
type UpdateDatabasesEvent = {|
|
||||||
databases: Array<{name: string, id: number, tables: Array<string>}>,
|
databases: Array<{name: string, id: number, tables: Array<string>}>,
|
||||||
type: 'UpdateDatabases',
|
type: 'UpdateDatabases',
|
||||||
@@ -113,7 +150,7 @@ type SelectDatabaseTableEvent = {|
|
|||||||
|
|
||||||
type UpdateViewModeEvent = {|
|
type UpdateViewModeEvent = {|
|
||||||
type: 'UpdateViewMode',
|
type: 'UpdateViewMode',
|
||||||
viewMode: 'data' | 'structure',
|
viewMode: 'data' | 'structure' | 'SQL' | 'tableInfo' | 'queryHistory',
|
||||||
|};
|
|};
|
||||||
|
|
||||||
type UpdatePageEvent = {|
|
type UpdatePageEvent = {|
|
||||||
@@ -137,6 +174,27 @@ type UpdateStructureEvent = {|
|
|||||||
indexesValues: Array<Array<any>>,
|
indexesValues: Array<Array<any>>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
type DisplaySelectEvent = {|
|
||||||
|
type: 'DisplaySelect',
|
||||||
|
columns: Array<string>,
|
||||||
|
values: Array<Array<any>>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
type DisplayInsertEvent = {|
|
||||||
|
type: 'DisplayInsert',
|
||||||
|
id: number,
|
||||||
|
|};
|
||||||
|
|
||||||
|
type DisplayUpdateDeleteEvent = {|
|
||||||
|
type: 'DisplayUpdateDelete',
|
||||||
|
count: number,
|
||||||
|
|};
|
||||||
|
|
||||||
|
type UpdateTableInfoEvent = {|
|
||||||
|
type: 'UpdateTableInfo',
|
||||||
|
tableInfo: string,
|
||||||
|
|};
|
||||||
|
|
||||||
type NextPageEvent = {
|
type NextPageEvent = {
|
||||||
type: 'NextPage',
|
type: 'NextPage',
|
||||||
};
|
};
|
||||||
@@ -145,10 +203,18 @@ type PreviousPageEvent = {
|
|||||||
type: 'PreviousPage',
|
type: 'PreviousPage',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ExecuteEvent = {
|
||||||
|
type: 'Execute',
|
||||||
|
};
|
||||||
|
|
||||||
type RefreshEvent = {
|
type RefreshEvent = {
|
||||||
type: 'Refresh',
|
type: 'Refresh',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type UpdateFavoritesEvent = {
|
||||||
|
type: 'UpdateFavorites',
|
||||||
|
};
|
||||||
|
|
||||||
type SortByChangedEvent = {
|
type SortByChangedEvent = {
|
||||||
type: 'SortByChanged',
|
type: 'SortByChanged',
|
||||||
sortOrder: TableRowSortOrder,
|
sortOrder: TableRowSortOrder,
|
||||||
@@ -159,6 +225,11 @@ type GoToRowEvent = {
|
|||||||
row: number,
|
row: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type UpdateQueryEvent = {
|
||||||
|
type: 'UpdateQuery',
|
||||||
|
value: string,
|
||||||
|
};
|
||||||
|
|
||||||
function transformRow(
|
function transformRow(
|
||||||
columns: Array<string>,
|
columns: Array<string>,
|
||||||
row: Array<Value>,
|
row: Array<Value>,
|
||||||
@@ -250,6 +321,47 @@ function renderDatabaseIndexes(structure: ?Structure) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderQueryHistory(history: Array<Query>) {
|
||||||
|
if (!history || typeof history === 'undefined') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const columns = {
|
||||||
|
time: {
|
||||||
|
value: 'Time',
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
value: 'Query',
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const rows = [];
|
||||||
|
if (history.length > 0) {
|
||||||
|
for (const query of history) {
|
||||||
|
const time = query.time;
|
||||||
|
const value = query.value;
|
||||||
|
rows.push({
|
||||||
|
key: query,
|
||||||
|
columns: {time: {value: time}, query: {value: value}},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlexRow grow={true}>
|
||||||
|
<ManagedTable
|
||||||
|
style={{paddingLeft: 16}}
|
||||||
|
floating={false}
|
||||||
|
columns={columns}
|
||||||
|
columnSizes={{time: 75}}
|
||||||
|
zebra={true}
|
||||||
|
rows={rows}
|
||||||
|
horizontallyScrollable={true}
|
||||||
|
/>
|
||||||
|
</FlexRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
type PageInfoProps = {
|
type PageInfoProps = {
|
||||||
currentRow: number,
|
currentRow: number,
|
||||||
count: number,
|
count: number,
|
||||||
@@ -277,7 +389,6 @@ class PageInfo extends Component<
|
|||||||
onSubmit(e: SyntheticKeyboardEvent<>) {
|
onSubmit(e: SyntheticKeyboardEvent<>) {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
const rowNumber = parseInt(this.state.inputValue, 10);
|
const rowNumber = parseInt(this.state.inputValue, 10);
|
||||||
console.log(rowNumber);
|
|
||||||
this.props.onChange(rowNumber - 1, this.props.count);
|
this.props.onChange(rowNumber - 1, this.props.count);
|
||||||
this.setState({isOpen: false});
|
this.setState({isOpen: false});
|
||||||
}
|
}
|
||||||
@@ -331,6 +442,12 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
currentPage: null,
|
currentPage: null,
|
||||||
currentStructure: null,
|
currentStructure: null,
|
||||||
currentSort: null,
|
currentSort: null,
|
||||||
|
query: null,
|
||||||
|
queryResult: null,
|
||||||
|
favorites: [],
|
||||||
|
executionTime: 0,
|
||||||
|
tableInfo: '',
|
||||||
|
queryHistory: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers = [
|
reducers = [
|
||||||
@@ -414,6 +531,7 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
viewMode: event.viewMode,
|
viewMode: event.viewMode,
|
||||||
|
error: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -458,6 +576,73 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'DisplaySelect',
|
||||||
|
(
|
||||||
|
state: DatabasesPluginState,
|
||||||
|
event: DisplaySelectEvent,
|
||||||
|
): DatabasesPluginState => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
queryResult: {
|
||||||
|
table: {
|
||||||
|
columns: event.columns,
|
||||||
|
rows: event.values.map((row: Array<Value>, index: number) =>
|
||||||
|
transformRow(event.columns, row, index),
|
||||||
|
),
|
||||||
|
highlightedRows: [],
|
||||||
|
},
|
||||||
|
id: null,
|
||||||
|
count: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'DisplayInsert',
|
||||||
|
(
|
||||||
|
state: DatabasesPluginState,
|
||||||
|
event: DisplayInsertEvent,
|
||||||
|
): DatabasesPluginState => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
queryResult: {
|
||||||
|
table: null,
|
||||||
|
id: event.id,
|
||||||
|
count: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
'DisplayUpdateDelete',
|
||||||
|
(
|
||||||
|
state: DatabasesPluginState,
|
||||||
|
event: DisplayUpdateDeleteEvent,
|
||||||
|
): DatabasesPluginState => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
queryResult: {
|
||||||
|
table: null,
|
||||||
|
id: null,
|
||||||
|
count: event.count,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'UpdateTableInfo',
|
||||||
|
(
|
||||||
|
state: DatabasesPluginState,
|
||||||
|
event: UpdateTableInfoEvent,
|
||||||
|
): DatabasesPluginState => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
tableInfo: event.tableInfo,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'NextPage',
|
'NextPage',
|
||||||
(
|
(
|
||||||
@@ -484,6 +669,66 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'Execute',
|
||||||
|
(
|
||||||
|
state: DatabasesPluginState,
|
||||||
|
results: ExecuteEvent,
|
||||||
|
): DatabasesPluginState => {
|
||||||
|
const timeBefore = Date.now();
|
||||||
|
if (
|
||||||
|
this.state.query !== null &&
|
||||||
|
typeof this.state.query !== 'undefined'
|
||||||
|
) {
|
||||||
|
this.databaseClient
|
||||||
|
.getExecution({
|
||||||
|
databaseId: state.selectedDatabase,
|
||||||
|
value: this.state.query.value,
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.setState({
|
||||||
|
error: null,
|
||||||
|
executionTime: Date.now() - timeBefore,
|
||||||
|
});
|
||||||
|
if (data.type === 'select') {
|
||||||
|
this.dispatchAction({
|
||||||
|
type: 'DisplaySelect',
|
||||||
|
columns: data.columns,
|
||||||
|
values: data.values,
|
||||||
|
});
|
||||||
|
} else if (data.type === 'insert') {
|
||||||
|
this.dispatchAction({
|
||||||
|
type: 'DisplayInsert',
|
||||||
|
id: data.insertedId,
|
||||||
|
});
|
||||||
|
} else if (data.type === 'update_delete') {
|
||||||
|
this.dispatchAction({
|
||||||
|
type: 'DisplayUpdateDelete',
|
||||||
|
count: data.affectedCount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.setState({error: e});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let newHistory = this.state.queryHistory;
|
||||||
|
const newQuery = this.state.query;
|
||||||
|
if (
|
||||||
|
newQuery !== null &&
|
||||||
|
typeof newQuery !== 'undefined' &&
|
||||||
|
newHistory !== null &&
|
||||||
|
typeof newHistory !== 'undefined'
|
||||||
|
) {
|
||||||
|
newQuery.time = dateFormat(new Date(), 'hh:MM:ss');
|
||||||
|
newHistory = newHistory.concat(newQuery);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
queryHistory: newHistory,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'GoToRow',
|
'GoToRow',
|
||||||
(
|
(
|
||||||
@@ -519,6 +764,32 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'UpdateFavorites',
|
||||||
|
(
|
||||||
|
state: DatabasesPluginState,
|
||||||
|
event: UpdateFavoritesEvent,
|
||||||
|
): DatabasesPluginState => {
|
||||||
|
let newFavorites = state.favorites;
|
||||||
|
if (
|
||||||
|
state.query &&
|
||||||
|
state.query !== null &&
|
||||||
|
typeof state.query !== 'undefined'
|
||||||
|
) {
|
||||||
|
const value = state.query.value;
|
||||||
|
if (newFavorites.includes(value)) {
|
||||||
|
const index = newFavorites.indexOf(value);
|
||||||
|
newFavorites.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
newFavorites = state.favorites.concat(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
favorites: newFavorites,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'UpdateViewMode',
|
'UpdateViewMode',
|
||||||
(
|
(
|
||||||
@@ -528,6 +799,7 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
viewMode: event.viewMode,
|
viewMode: event.viewMode,
|
||||||
|
error: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -542,6 +814,18 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'UpdateQuery',
|
||||||
|
(state: DatabasesPluginState, event: UpdateQueryEvent) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
query: {
|
||||||
|
value: event.value,
|
||||||
|
time: dateFormat(new Date(), 'hh:MM:ss'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
].reduce((acc, val) => {
|
].reduce((acc, val) => {
|
||||||
const name = val[0];
|
const name = val[0];
|
||||||
const f = val[1];
|
const f = val[1];
|
||||||
@@ -576,7 +860,6 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
start: newState.pageRowNumber,
|
start: newState.pageRowNumber,
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log(data);
|
|
||||||
this.dispatchAction({
|
this.dispatchAction({
|
||||||
type: 'UpdatePage',
|
type: 'UpdatePage',
|
||||||
databaseId: databaseId,
|
databaseId: databaseId,
|
||||||
@@ -604,7 +887,6 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
table: table,
|
table: table,
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log(data);
|
|
||||||
this.dispatchAction({
|
this.dispatchAction({
|
||||||
type: 'UpdateStructure',
|
type: 'UpdateStructure',
|
||||||
databaseId: databaseId,
|
databaseId: databaseId,
|
||||||
@@ -619,6 +901,28 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
this.setState({error: e});
|
this.setState({error: e});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
newState.viewMode === 'tableInfo' &&
|
||||||
|
newState.currentStructure === null &&
|
||||||
|
databaseId &&
|
||||||
|
table
|
||||||
|
) {
|
||||||
|
this.databaseClient
|
||||||
|
.getTableInfo({
|
||||||
|
databaseId: databaseId,
|
||||||
|
table: table,
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.dispatchAction({
|
||||||
|
type: 'UpdateTableInfo',
|
||||||
|
tableInfo: data.definition,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.setState({error: e});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!previousState.outdatedDatabaseList && newState.outdatedDatabaseList) {
|
if (!previousState.outdatedDatabaseList && newState.outdatedDatabaseList) {
|
||||||
this.databaseClient.getDatabases({}).then(databases => {
|
this.databaseClient.getDatabases({}).then(databases => {
|
||||||
this.dispatchAction({
|
this.dispatchAction({
|
||||||
@@ -647,10 +951,29 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
this.dispatchAction({type: 'UpdateViewMode', viewMode: 'structure'});
|
this.dispatchAction({type: 'UpdateViewMode', viewMode: 'structure'});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onSQLClicked = () => {
|
||||||
|
this.dispatchAction({type: 'UpdateViewMode', viewMode: 'SQL'});
|
||||||
|
};
|
||||||
|
|
||||||
|
onTableInfoClicked = () => {
|
||||||
|
this.dispatchAction({type: 'UpdateViewMode', viewMode: 'tableInfo'});
|
||||||
|
};
|
||||||
|
|
||||||
|
onQueryHistoryClicked = () => {
|
||||||
|
this.dispatchAction({type: 'UpdateViewMode', viewMode: 'queryHistory'});
|
||||||
|
};
|
||||||
|
|
||||||
onRefreshClicked = () => {
|
onRefreshClicked = () => {
|
||||||
|
this.setState({error: null});
|
||||||
this.dispatchAction({type: 'Refresh'});
|
this.dispatchAction({type: 'Refresh'});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onFavoritesClicked = () => {
|
||||||
|
this.dispatchAction({
|
||||||
|
type: 'UpdateFavorites',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onDatabaseSelected = (selected: string) => {
|
onDatabaseSelected = (selected: string) => {
|
||||||
const dbId = this.state.databases.find(x => x.name === selected)?.id || 0;
|
const dbId = this.state.databases.find(x => x.name === selected)?.id || 0;
|
||||||
this.dispatchAction({
|
this.dispatchAction({
|
||||||
@@ -674,10 +997,25 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
this.dispatchAction({type: 'PreviousPage'});
|
this.dispatchAction({type: 'PreviousPage'});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onExecuteClicked = () => {
|
||||||
|
this.dispatchAction({type: 'Execute'});
|
||||||
|
};
|
||||||
|
|
||||||
|
onFavoriteClicked = (selected: any) => {
|
||||||
|
this.setState({query: selected.target.value});
|
||||||
|
};
|
||||||
|
|
||||||
onGoToRow = (row: number, count: number) => {
|
onGoToRow = (row: number, count: number) => {
|
||||||
this.dispatchAction({type: 'GoToRow', row: row});
|
this.dispatchAction({type: 'GoToRow', row: row});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onQueryChanged = (selected: any) => {
|
||||||
|
this.dispatchAction({
|
||||||
|
type: 'UpdateQuery',
|
||||||
|
value: selected.target.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
renderStructure() {
|
renderStructure() {
|
||||||
return [
|
return [
|
||||||
renderDatabaseColumns(this.state.currentStructure),
|
renderDatabaseColumns(this.state.currentStructure),
|
||||||
@@ -685,6 +1023,153 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderSidebar = (table: QueriedTable) => {
|
||||||
|
if (
|
||||||
|
table.highlightedRows === null ||
|
||||||
|
typeof table.highlightedRows === 'undefined' ||
|
||||||
|
table.highlightedRows.length !== 1
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const id = table.highlightedRows[0];
|
||||||
|
const cols = {
|
||||||
|
col: {
|
||||||
|
value: 'Column',
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
val: {
|
||||||
|
value: 'Value',
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const colSizes = {
|
||||||
|
col: '35%',
|
||||||
|
val: 'flex',
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<DetailSidebar width={500}>
|
||||||
|
<Panel
|
||||||
|
padded={true}
|
||||||
|
heading="Row details"
|
||||||
|
floating={false}
|
||||||
|
collapsable={true}
|
||||||
|
grow={true}>
|
||||||
|
<ManagedTable
|
||||||
|
highlightableRows={false}
|
||||||
|
columnSizes={colSizes}
|
||||||
|
multiline={true}
|
||||||
|
columns={cols}
|
||||||
|
autoHeight={true}
|
||||||
|
floating={false}
|
||||||
|
zebra={true}
|
||||||
|
rows={this.sidebarRows(id, table)}
|
||||||
|
/>
|
||||||
|
</Panel>
|
||||||
|
</DetailSidebar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
sidebarRows = (id: number, table: QueriedTable) => {
|
||||||
|
const columns = table.columns;
|
||||||
|
const row = table.rows[id];
|
||||||
|
const sidebarArray = [];
|
||||||
|
for (let i = 0; i < columns.length; i++) {
|
||||||
|
sidebarArray.push(
|
||||||
|
this.buildSidebarRow(columns[i], row.columns[columns[i]].value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return sidebarArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
buildSidebarRow = (key: string, val: any) => {
|
||||||
|
let output = '';
|
||||||
|
try {
|
||||||
|
output = (
|
||||||
|
<ManagedDataInspector
|
||||||
|
data={JSON.parse(val.props.children)}
|
||||||
|
expandRoot={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
output = val;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
columns: {
|
||||||
|
col: {value: <Text>{key}</Text>},
|
||||||
|
val: {
|
||||||
|
value: output,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
key: key,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
renderQuery(query: ?QueryResult) {
|
||||||
|
if (!query || query === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
query.table &&
|
||||||
|
typeof query.table !== 'undefined' &&
|
||||||
|
query.table !== null
|
||||||
|
) {
|
||||||
|
const table = query.table;
|
||||||
|
const columns = table.columns;
|
||||||
|
const rows = table.rows;
|
||||||
|
return (
|
||||||
|
<FlexRow grow={true} style={{paddingTop: 18}}>
|
||||||
|
<ManagedTable
|
||||||
|
floating={false}
|
||||||
|
multiline={true}
|
||||||
|
columnOrder={columns.map(name => ({
|
||||||
|
key: name,
|
||||||
|
visible: true,
|
||||||
|
}))}
|
||||||
|
columns={columns.reduce((acc, val) => {
|
||||||
|
acc[val] = {value: val, resizable: true};
|
||||||
|
return acc;
|
||||||
|
}, {})}
|
||||||
|
zebra={true}
|
||||||
|
rows={rows}
|
||||||
|
horizontallyScrollable={true}
|
||||||
|
onRowHighlighted={highlightedRows => {
|
||||||
|
this.setState({
|
||||||
|
queryResult: {
|
||||||
|
table: {
|
||||||
|
columns: columns,
|
||||||
|
rows: rows,
|
||||||
|
highlightedRows: highlightedRows,
|
||||||
|
},
|
||||||
|
id: null,
|
||||||
|
count: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{this.renderSidebar(table)}
|
||||||
|
</FlexRow>
|
||||||
|
);
|
||||||
|
} else if (query.id && query.id !== null) {
|
||||||
|
return (
|
||||||
|
<FlexRow grow={true} style={{paddingTop: 18}}>
|
||||||
|
<Text style={{paddingTop: 8, paddingLeft: 8}}>
|
||||||
|
Row id: {query.id}
|
||||||
|
</Text>
|
||||||
|
</FlexRow>
|
||||||
|
);
|
||||||
|
} else if (query.count && query.count !== null) {
|
||||||
|
return (
|
||||||
|
<FlexRow grow={true} style={{paddingTop: 18}}>
|
||||||
|
<Text style={{paddingTop: 8, paddingLeft: 8}}>
|
||||||
|
Rows affected: {query.count}
|
||||||
|
</Text>
|
||||||
|
</FlexRow>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const tableOptions =
|
const tableOptions =
|
||||||
(this.state.selectedDatabase &&
|
(this.state.selectedDatabase &&
|
||||||
@@ -697,7 +1182,45 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FlexColumn style={{flex: 1}}>
|
<FlexColumn style={{flex: 1}}>
|
||||||
<Toolbar position="top" style={{paddingLeft: 8}}>
|
<Toolbar position="top" style={{paddingLeft: 16}}>
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button
|
||||||
|
icon={'data-table'}
|
||||||
|
onClick={this.onDataClicked}
|
||||||
|
selected={this.state.viewMode === 'data'}>
|
||||||
|
Data
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={'gears-two'}
|
||||||
|
onClick={this.onStructureClicked}
|
||||||
|
selected={this.state.viewMode === 'structure'}>
|
||||||
|
Structure
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={'magnifying-glass'}
|
||||||
|
onClick={this.onSQLClicked}
|
||||||
|
selected={this.state.viewMode === 'SQL'}>
|
||||||
|
SQL
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={'info-cursive'}
|
||||||
|
onClick={this.onTableInfoClicked}
|
||||||
|
selected={this.state.viewMode === 'tableInfo'}>
|
||||||
|
Table Info
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={'on-this-day'}
|
||||||
|
iconSize={12}
|
||||||
|
onClick={this.onQueryHistoryClicked}
|
||||||
|
selected={this.state.viewMode === 'queryHistory'}>
|
||||||
|
Query History
|
||||||
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</Toolbar>
|
||||||
|
{this.state.viewMode === 'data' ||
|
||||||
|
this.state.viewMode === 'structure' ||
|
||||||
|
this.state.viewMode === 'tableInfo' ? (
|
||||||
|
<Toolbar position="top" style={{paddingLeft: 16}}>
|
||||||
<BoldSpan style={{marginRight: 16}}>Database</BoldSpan>
|
<BoldSpan style={{marginRight: 16}}>Database</BoldSpan>
|
||||||
<Select
|
<Select
|
||||||
options={this.state.databases
|
options={this.state.databases
|
||||||
@@ -719,31 +1242,117 @@ export default class DatabasesPlugin extends FlipperPlugin<
|
|||||||
/>
|
/>
|
||||||
<div />
|
<div />
|
||||||
<Button onClick={this.onRefreshClicked}>Refresh</Button>
|
<Button onClick={this.onRefreshClicked}>Refresh</Button>
|
||||||
<Button style={{marginLeft: 'auto', display: 'none'}}>
|
|
||||||
Execute SQL
|
|
||||||
</Button>
|
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
) : null}
|
||||||
|
{this.state.viewMode === 'SQL' ? (
|
||||||
|
<div>
|
||||||
|
<Toolbar position="top" style={{paddingLeft: 16}}>
|
||||||
|
<BoldSpan style={{marginRight: 16}}>Database</BoldSpan>
|
||||||
|
<Select
|
||||||
|
options={this.state.databases
|
||||||
|
.map(x => x.name)
|
||||||
|
.reduce((obj, item) => {
|
||||||
|
obj[item] = item;
|
||||||
|
return obj;
|
||||||
|
}, {})}
|
||||||
|
selected={
|
||||||
|
this.state.databases[this.state.selectedDatabase - 1]?.name
|
||||||
|
}
|
||||||
|
onChange={this.onDatabaseSelected}
|
||||||
|
/>
|
||||||
|
</Toolbar>
|
||||||
|
{
|
||||||
|
<Textarea
|
||||||
|
style={{
|
||||||
|
width: '98%',
|
||||||
|
height: '40%',
|
||||||
|
marginLeft: 16,
|
||||||
|
marginTop: '1%',
|
||||||
|
marginBottom: '1%',
|
||||||
|
}}
|
||||||
|
onChange={this.onQueryChanged.bind(this)}
|
||||||
|
placeholder="Type query here.."
|
||||||
|
value={
|
||||||
|
this.state.query !== null &&
|
||||||
|
typeof this.state.query !== 'undefined'
|
||||||
|
? this.state.query.value
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
<Toolbar
|
||||||
|
position="top"
|
||||||
|
style={{paddingLeft: 16, paddingTop: 24, paddingBottom: 24}}>
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button
|
||||||
|
icon={'star'}
|
||||||
|
iconSize={14}
|
||||||
|
iconVariant={
|
||||||
|
this.state.query !== null &&
|
||||||
|
typeof this.state.query !== 'undefined' &&
|
||||||
|
this.state.favorites.includes(this.state.query.value)
|
||||||
|
? 'filled'
|
||||||
|
: 'outline'
|
||||||
|
}
|
||||||
|
onClick={this.onFavoritesClicked}
|
||||||
|
/>
|
||||||
|
{this.state.favorites !== null ? (
|
||||||
|
<Button
|
||||||
|
dropdown={this.state.favorites.map(option => {
|
||||||
|
return {
|
||||||
|
click: () => {
|
||||||
|
this.setState({
|
||||||
|
query: {
|
||||||
|
value: option,
|
||||||
|
time: dateFormat(new Date(), 'hh:MM:ss'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.onQueryChanged.bind(this);
|
||||||
|
},
|
||||||
|
label: option,
|
||||||
|
};
|
||||||
|
})}>
|
||||||
|
Choose from previous queries
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</ButtonGroup>
|
||||||
|
<Spacer />
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button onClick={this.onExecuteClicked}>Execute</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</Toolbar>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<FlexColumn grow={true}>
|
<FlexColumn grow={true}>
|
||||||
{this.state.viewMode === 'data'
|
{this.state.viewMode === 'data'
|
||||||
? renderTable(this.state.currentPage, this)
|
? renderTable(this.state.currentPage, this)
|
||||||
: this.renderStructure()}
|
: null}
|
||||||
|
{this.state.viewMode === 'structure' ? this.renderStructure() : null}
|
||||||
|
{this.state.viewMode === 'SQL'
|
||||||
|
? this.renderQuery(this.state.queryResult)
|
||||||
|
: null}
|
||||||
|
{this.state.viewMode === 'tableInfo' ? (
|
||||||
|
<Textarea
|
||||||
|
style={{
|
||||||
|
width: '98%',
|
||||||
|
height: '100%',
|
||||||
|
marginLeft: '1%',
|
||||||
|
marginTop: '1%',
|
||||||
|
marginBottom: '1%',
|
||||||
|
readOnly: true,
|
||||||
|
}}
|
||||||
|
value={sqlFormatter.format(this.state.tableInfo)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{this.state.viewMode === 'queryHistory'
|
||||||
|
? renderQueryHistory(this.state.queryHistory)
|
||||||
|
: null}
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
<Toolbar position="bottom" style={{paddingLeft: 8}}>
|
<Toolbar position="bottom" style={{paddingLeft: 8}}>
|
||||||
<FlexRow grow={true}>
|
<FlexRow grow={true}>
|
||||||
<ButtonGroup>
|
{this.state.viewMode === 'SQL' && this.state.executionTime !== 0 ? (
|
||||||
<Button
|
<Text> {this.state.executionTime} ms </Text>
|
||||||
icon={'data-table'}
|
) : null}
|
||||||
onClick={this.onDataClicked}
|
|
||||||
selected={this.state.viewMode === 'data'}>
|
|
||||||
Data
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
icon={'gears-two'}
|
|
||||||
onClick={this.onStructureClicked}
|
|
||||||
selected={this.state.viewMode === 'structure'}>
|
|
||||||
Structure
|
|
||||||
</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
{this.state.viewMode === 'data' && this.state.currentPage ? (
|
{this.state.viewMode === 'data' && this.state.currentPage ? (
|
||||||
<PageInfo
|
<PageInfo
|
||||||
currentRow={this.state.currentPage.start}
|
currentRow={this.state.currentPage.start}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"sql-formatter": "^2.3.3",
|
||||||
|
"dateformat": "^3.0.3"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"email": "oncall+flipper@xmail.facebook.com",
|
"email": "oncall+flipper@xmail.facebook.com",
|
||||||
|
|||||||
@@ -2,3 +2,19 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
dateformat@^3.0.3:
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||||
|
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||||
|
|
||||||
|
lodash@^4.16.0:
|
||||||
|
version "4.17.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
|
||||||
|
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
|
||||||
|
|
||||||
|
sql-formatter@^2.3.3:
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/sql-formatter/-/sql-formatter-2.3.3.tgz#910ef484fbb988a5e510bea4161157e3b80b2f62"
|
||||||
|
integrity sha512-m6pqVXwsm9GkCHC/+gdPvNowI7PNoVTT6OZMWKwXJoP2MvfntfhcfyliIf4/QX6t+DirSJ6XDSiSS70YvZ87Lw==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.16.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user