sqlite-wasm-viewer 0.1.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,266 +0,0 @@
1
- import { ViewerState } from '../../viewerState';
2
- import { ListVirtualizer } from '../../ListVirtualizer';
3
- import { QueryRunner } from '../../QueryRunner';
4
- import './styles.css';
5
-
6
- export class TableView {
7
- private container: HTMLDivElement;
8
-
9
- private viewHeader: HTMLDivElement;
10
-
11
- private viewHeaderTitle: HTMLSpanElement;
12
-
13
- private headerRow: HTMLTableRowElement;
14
-
15
- private bodyRoot: HTMLTableSectionElement;
16
-
17
- private virtualizer: ListVirtualizer;
18
-
19
- private rows;
20
-
21
- private tableName: string;
22
-
23
- private columnNames: string[] = [];
24
-
25
- private fitlers: { [column: string]: string } = {};
26
-
27
- private updateTimer: number | null = null;
28
-
29
- private selectedCell: HTMLTableCellElement | null = null;
30
-
31
- constructor(
32
- private viewerElem: HTMLElement,
33
- private rootElement: HTMLDivElement,
34
- private queryRunner: QueryRunner
35
- ) {
36
- this.buildDomTemplate();
37
-
38
- this.viewerElem.addEventListener('tableSelected', (event) => {
39
- const { detail: tableName } = event;
40
- this.setTable(tableName);
41
- });
42
-
43
- this.virtualizer = new ListVirtualizer({
44
- width: 500,
45
- height: 930,
46
- totalRows: 0,
47
- itemHeight: 40,
48
- contentRoot: this.bodyRoot,
49
- container: this.container,
50
- generatorFn: (i: number) => {
51
- const row = this.rows[i];
52
-
53
- if (!row) {
54
- return null;
55
- }
56
-
57
- const tr = document.createElement('tr');
58
-
59
- const rowId = row.rowid;
60
-
61
- Object.keys(row).forEach((columnKey) => {
62
- if (columnKey === 'rowid') {
63
- return;
64
- }
65
-
66
- const value = row[columnKey];
67
- const td = document.createElement('td');
68
- const contentEl = document.createElement('div');
69
- if (value !== null) {
70
- contentEl.innerHTML = value;
71
- } else {
72
- contentEl.innerHTML = 'NULL';
73
- contentEl.className = 'nullValue';
74
- }
75
-
76
- td.onclick = () => {
77
- ViewerState.instance.setSelectedCell({
78
- value,
79
- cellRowId: rowId,
80
- columnName: columnKey,
81
- tableName: ViewerState.instance.selectedTable,
82
- });
83
-
84
- if (this.selectedCell) {
85
- this.selectedCell.classList.remove('selected');
86
- }
87
-
88
- td.classList.add('selected');
89
- this.selectedCell = td;
90
- };
91
-
92
- td.appendChild(contentEl);
93
- tr.appendChild(td);
94
- });
95
- this.bodyRoot.appendChild(tr);
96
-
97
- return tr;
98
- },
99
- });
100
- }
101
-
102
- setTableResults(rows: any[]) {
103
- this.rows = rows;
104
-
105
- this.viewHeaderTitle.innerHTML = this.tableName;
106
-
107
- this.buildHeader(rows);
108
-
109
- this.virtualizer.setRowCount(rows.length);
110
- }
111
-
112
- buildDomTemplate() {
113
- this.viewHeader = document.createElement('div');
114
- this.viewHeader.className = 'viewHeader';
115
-
116
- this.viewHeaderTitle = document.createElement('span');
117
- this.viewHeaderTitle.id = 'table_view_header_title';
118
- this.viewHeader.appendChild(this.viewHeaderTitle);
119
-
120
- const updateBtn = document.createElement('button');
121
- updateBtn.innerText = 'Update';
122
- updateBtn.onclick = () => {
123
- this.requestRows();
124
- };
125
- this.viewHeader.appendChild(updateBtn);
126
-
127
- const saveBtn = document.createElement('button');
128
- saveBtn.innerText = 'Save changes';
129
- saveBtn.onclick = () => {
130
- this.saveChanges();
131
- };
132
- saveBtn.setAttribute('disabled', '');
133
- this.viewHeader.appendChild(saveBtn);
134
-
135
- const revertBtn = document.createElement('button');
136
- revertBtn.innerText = 'Revert changes';
137
- revertBtn.onclick = () => {
138
- this.revertChanges();
139
- };
140
- revertBtn.setAttribute('disabled', '');
141
- this.viewHeader.appendChild(revertBtn);
142
-
143
- this.rootElement.appendChild(this.viewHeader);
144
-
145
- this.container = document.createElement('div');
146
- this.container.id = 'table_container';
147
-
148
- const table = document.createElement('table');
149
-
150
- const tableHeader = table.createTHead();
151
- this.headerRow = document.createElement('tr');
152
- tableHeader.appendChild(this.headerRow);
153
-
154
- this.bodyRoot = table.createTBody();
155
- this.container.appendChild(table);
156
-
157
- this.rootElement.appendChild(this.container);
158
-
159
- this.viewerElem.addEventListener('hasChanges', (event) => {
160
- const { detail: hasChanges } = event;
161
-
162
- if (hasChanges) {
163
- saveBtn.removeAttribute('disabled');
164
- revertBtn.removeAttribute('disabled');
165
- } else {
166
- saveBtn.setAttribute('disabled', '');
167
- revertBtn.setAttribute('disabled', '');
168
- }
169
- });
170
- }
171
-
172
- private buildHeader(rows: any[]) {
173
- if (this.columnNames.length !== 0) {
174
- return;
175
- }
176
-
177
- const schema =
178
- rows.length > 0
179
- ? Object.keys(rows[0]).filter((column) => column !== 'rowid')
180
- : [];
181
-
182
- if (schema.length > 0) {
183
- this.columnNames = schema;
184
- }
185
-
186
- this.headerRow.innerHTML = '';
187
- this.columnNames.forEach((column) => {
188
- const columnHeader = document.createElement('th');
189
- columnHeader.className = 'columnHeaderCell';
190
-
191
- columnHeader.innerHTML = column;
192
-
193
- const filterFieldCell = document.createElement('th');
194
- filterFieldCell.className = 'columnFilterCell';
195
- const filterField = document.createElement('input');
196
- filterField.oninput = () => {
197
- this.fitlers[column] = filterField.value;
198
- this.scheduleUpdate();
199
- };
200
- filterField.placeholder = 'Filter';
201
-
202
- filterFieldCell.appendChild(filterField);
203
-
204
- this.headerRow.appendChild(columnHeader);
205
-
206
- columnHeader.appendChild(filterFieldCell);
207
- });
208
- }
209
-
210
- private setTable(name: string) {
211
- if (this.tableName === name) {
212
- return;
213
- }
214
-
215
- this.tableName = name;
216
- this.columnNames = [];
217
- this.fitlers = {};
218
-
219
- this.requestRows();
220
- }
221
-
222
- private requestRows(): void {
223
- let sql = `SELECT "_rowid_",* FROM ${this.tableName}`;
224
-
225
- const filterSql: string[] = [];
226
- Object.entries(this.fitlers).forEach((filterEntry) => {
227
- const column = filterEntry[0];
228
- const filter = filterEntry[1];
229
-
230
- if (filter) {
231
- filterSql.push(`"${column}" LIKE '%${filter}%'`);
232
- }
233
- });
234
-
235
- if (filterSql.length > 0) {
236
- sql += ` WHERE ${filterSql.join(' AND ')} ESCAPE '\\'`;
237
- }
238
-
239
- this.queryRunner.runQuery({ sql, parameters: [] }, 'tableView');
240
- }
241
-
242
- private saveChanges(): void {
243
- const sql = 'RELEASE "RESTOREPOINT";';
244
- this.queryRunner.runQuery({ sql, parameters: [] });
245
- ViewerState.instance.setHasChanges(false);
246
- }
247
-
248
- private revertChanges(): void {
249
- const sql = 'ROLLBACK TO SAVEPOINT "RESTOREPOINT";';
250
- this.queryRunner.runQuery({ sql, parameters: [] });
251
-
252
- this.requestRows();
253
-
254
- ViewerState.instance.setHasChanges(false);
255
- }
256
-
257
- private scheduleUpdate() {
258
- if (this.updateTimer !== null) {
259
- window.clearTimeout(this.updateTimer);
260
- }
261
- this.updateTimer = window.setTimeout(() => {
262
- this.requestRows();
263
- this.updateTimer = null;
264
- }, 300);
265
- }
266
- }
@@ -1,79 +0,0 @@
1
- #table_view {
2
- padding: 5px;
3
- flex: 1;
4
- position: relative;
5
- overflow: hidden;
6
- display: flex;
7
- flex-direction: column;
8
- }
9
-
10
- #table_view_header {
11
- max-height: 20px;
12
- flex-basis: 20px;
13
- left: 0;
14
- right: 0;
15
- position: sticky;
16
- line-height: 1.1rem;
17
- padding: 8px;
18
- background-color: lightgray;
19
- }
20
-
21
- #table_view_header_title {
22
- padding: 8px;
23
- }
24
-
25
- #table_container {
26
- overflow-y: scroll;
27
- display: flex;
28
- }
29
-
30
- #table_container table {
31
- background-color: whitesmoke;
32
- border-collapse: collapse;
33
- border-spacing: 0;
34
- flex: 1;
35
- flex-direction: column;
36
- }
37
-
38
- #table_container tbody {
39
- flex: 1;
40
- overflow-y: scroll;
41
- position: relative;
42
- }
43
-
44
- #table_container .columnHeaderCell {
45
- height: 60px;
46
- position: sticky;
47
- top: 0;
48
- background-color: darkgray;
49
- z-index: 2;
50
- }
51
-
52
- #table_container .columnFilterCell {
53
- padding-top: 5px;
54
- }
55
-
56
- #table_container td, #table_container .columnHeaderCell {
57
- border: 1px solid lightgray;
58
- }
59
-
60
- #table_container td.selected {
61
- background-color: lightslategray;
62
- color: white;
63
- }
64
-
65
- #table_container td div {
66
- height: 40px;
67
- box-sizing: border-box;
68
- display: -webkit-box;
69
- padding: 4px;
70
- text-overflow: ellipsis;
71
- overflow: hidden;
72
- -webkit-line-clamp: 2;
73
- -webkit-box-orient: vertical;
74
- }
75
-
76
- #table_container .nullValue {
77
- font-style: italic;
78
- color: gray;
79
- }
package/tsconfig.json DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "composite": true,
4
- "module": "ES2020",
5
- "target": "ES5",
6
- "esModuleInterop": true,
7
- "strictNullChecks": true,
8
- "outDir": "dist",
9
- "declaration": true,
10
- "emitDeclarationOnly": true,
11
- "declarationMap": true,
12
- "lib": [
13
- "esnext",
14
- "dom",
15
- "Webworker"
16
- ],
17
- "baseUrl": ".",
18
- },
19
- "include": [
20
- "src/**/*.tsx",
21
- "src/**/*.ts",
22
- "src/**/*d.ts"
23
- ],
24
- "exclude": [
25
- "node_modules",
26
- "**/build",
27
- ]
28
- }