This commit is contained in:
@@ -11,12 +11,7 @@
|
||||
<p-button icon="pi pi-save" class="mr-2" text severity="secondary" />
|
||||
</ng-template>
|
||||
</p-toolbar>
|
||||
<p-splitter
|
||||
[panelSizes]="[15, 70, 15]"
|
||||
class="h-full"
|
||||
[style]="{ height: '100%' }"
|
||||
styleClass="mb-8"
|
||||
>
|
||||
<p-splitter [panelSizes]="[15, 70, 15]" class="h-full" styleClass="mb-8 h-full">
|
||||
<ng-template #panel>
|
||||
<div class="h-full w-full">
|
||||
<app-file-tree (selectFile)="selectedFile.set($event)"></app-file-tree>
|
||||
@@ -25,18 +20,31 @@
|
||||
<ng-template #panel>
|
||||
<p-splitter layout="vertical" [panelSizes]="[70, 30]">
|
||||
<ng-template #panel>
|
||||
<p-tabs value="0" class="w-full"
|
||||
><p-tablist>
|
||||
<p-tab value="0">Tab 1</p-tab>
|
||||
<p-tab value="1">Tab 2</p-tab>
|
||||
<div class="flex flex-col w-full">
|
||||
@if (tabs().length > 0) {
|
||||
<p-tabs [(value)]="selectedTab" class="w-full" scrollable>
|
||||
<p-tablist>
|
||||
@for (tab of tabs(); track $index) {
|
||||
<p-tab [value]="$index">
|
||||
<span>{{ tab.name }}</span>
|
||||
<span
|
||||
(click)="removeTab($index)"
|
||||
class="material-symbols-outlined"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</p-tab>
|
||||
}
|
||||
</p-tablist>
|
||||
<p-tabpanels class="h-full">
|
||||
<p-tabpanel value="0">
|
||||
<app-file-viewer [file]="selectedFile()"></app-file-viewer>
|
||||
</p-tabpanel>
|
||||
</p-tabpanels>
|
||||
</p-tabs>
|
||||
<!-- <div class="col flex items-center justify-center">Panel 2</div> -->
|
||||
}
|
||||
@if (selectedFile()) {
|
||||
<app-file-viewer
|
||||
class="flex w-full flex-1"
|
||||
[file]="selectedFile()"
|
||||
></app-file-viewer>
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template #panel>
|
||||
<div class="col flex items-center justify-center">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, signal, viewChild } from '@angular/core';
|
||||
import { Component, effect, signal, viewChild } from '@angular/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { SplitterModule } from 'primeng/splitter';
|
||||
import { TabsModule } from 'primeng/tabs';
|
||||
@@ -28,7 +28,68 @@ import { FileViewerComponent } from './file-viewer/file-viewer.component';
|
||||
styleUrl: './app.component.scss',
|
||||
})
|
||||
export class AppComponent {
|
||||
// TODO: When a file is selected, we add a new sheet with that file as the current file?
|
||||
// For now we'll just store the current file only
|
||||
selectedFile = signal<File | undefined>(undefined);
|
||||
protected selectedFile = signal<File | undefined>(undefined);
|
||||
protected tabs = signal<File[]>([]);
|
||||
protected selectedTab = signal(0);
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
const selectedFile = this.selectedFile();
|
||||
if (selectedFile) {
|
||||
if (
|
||||
this.tabs().find(
|
||||
(tab) => tab.webkitRelativePath === selectedFile.webkitRelativePath,
|
||||
)
|
||||
) {
|
||||
this.selectedTab.set(
|
||||
this.tabs().findIndex(
|
||||
(tab) =>
|
||||
tab.webkitRelativePath === selectedFile.webkitRelativePath,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
this.tabs.update((tabs) => [...tabs, selectedFile]);
|
||||
this.selectedTab.set(this.tabs().length - 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
if (this.selectedFile() !== this.tabs()[this.selectedTab()]) {
|
||||
if (this.tabs().length > 0) {
|
||||
this.selectedFile.set(this.tabs()[Number(this.selectedTab())]);
|
||||
} else {
|
||||
this.selectedFile.set(undefined);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected removeTab(index: number) {
|
||||
this.tabs.update((tabs) => {
|
||||
const copy = tabs.slice();
|
||||
copy.splice(index);
|
||||
return copy;
|
||||
});
|
||||
if (this.selectedTab() === index) {
|
||||
if (this.selectedTab() > 0) {
|
||||
this.selectedTab.update((tab) => tab - 1);
|
||||
this.selectedFile.set(this.tabs()[this.selectedTab()]);
|
||||
} else if (this.tabs().length > 1) {
|
||||
this.selectedTab.update((tab) => tab + 1);
|
||||
this.selectedFile.set(this.tabs()[this.selectedTab()]);
|
||||
} else {
|
||||
this.selectedFile.set(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Drop files over viewport
|
||||
protected fileDropped(event: DragEvent) {
|
||||
if (event.dataTransfer?.items.length ?? 0 > 1) {
|
||||
// Open in the tabs
|
||||
} else if (event.dataTransfer?.items.length ?? 0 > 0) {
|
||||
// Open in current tab
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {
|
||||
ApplicationConfig,
|
||||
inject,
|
||||
provideAppInitializer,
|
||||
provideZonelessChangeDetection,
|
||||
} from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
@@ -8,6 +10,7 @@ import { providePrimeNG } from 'primeng/config';
|
||||
import Aura from '@primeng/themes/aura';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import { DuckdbService } from './duckdb.service';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
@@ -19,5 +22,9 @@ export const appConfig: ApplicationConfig = {
|
||||
preset: Aura,
|
||||
},
|
||||
}),
|
||||
provideAppInitializer(async () => {
|
||||
const duckDbService = inject(DuckdbService);
|
||||
await duckDbService.init();
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -102,9 +102,6 @@ const suffix = (operator: FilterOperator) => {
|
||||
export class DuckdbService {
|
||||
private db!: duckdb.AsyncDuckDB;
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
async init() {
|
||||
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
inject,
|
||||
input,
|
||||
@@ -123,6 +124,7 @@ import { PaginatorModule, PaginatorState } from 'primeng/paginator';
|
||||
}
|
||||
</tr>
|
||||
</ng-template>
|
||||
@if (hasAggregates()) {
|
||||
<ng-template #footer>
|
||||
<tr>
|
||||
@for (col of columns(); track $index) {
|
||||
@@ -151,6 +153,7 @@ import { PaginatorModule, PaginatorState } from 'primeng/paginator';
|
||||
}
|
||||
</tr>
|
||||
</ng-template>
|
||||
}
|
||||
</p-table>
|
||||
</div>
|
||||
@if (currentRowCount() > PAGE_SIZE) {
|
||||
@@ -191,6 +194,10 @@ export class FileViewerComponent {
|
||||
|
||||
private table = viewChild(Table);
|
||||
|
||||
protected hasAggregates = computed(
|
||||
() => !!this.columns().find((col) => this.isAggregateColumn(col)),
|
||||
);
|
||||
|
||||
protected aggregateItems: MenuItem[] = aggregateTypes.map((type) => ({
|
||||
label: type,
|
||||
command: () => this.updateAggregateValue(type),
|
||||
@@ -198,7 +205,7 @@ export class FileViewerComponent {
|
||||
|
||||
constructor() {
|
||||
effect(async () => {
|
||||
this.loadEmpty();
|
||||
await this.loadEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -268,7 +275,7 @@ export class FileViewerComponent {
|
||||
}
|
||||
|
||||
// Can't update the current value, otherwise we get an infinite loop due to primeng change detection rerunning (plus it's faster to mutate)
|
||||
for (let i = 0; i < event.rows!; i++) {
|
||||
for (let i = 0; i < rows.rows!.length; i++) {
|
||||
this.currentValue()[event.first! + i] = rows.rows![i];
|
||||
}
|
||||
event.forceUpdate!();
|
||||
@@ -340,4 +347,8 @@ export class FileViewerComponent {
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
protected isAggregateColumn(col: Column) {
|
||||
return col.type === 'DOUBLE' || col.type === 'BIGINT';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=mediation"
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=close,mediation"
|
||||
/>
|
||||
<style>
|
||||
.material-symbols-outlined {
|
||||
|
||||
Reference in New Issue
Block a user