Add basic column selection
All checks were successful
build / build (push) Successful in 1m31s

This commit is contained in:
2025-07-08 19:10:31 +09:30
parent a53c01ab8e
commit 4def7b8daf
5 changed files with 77 additions and 5 deletions

View File

@@ -49,6 +49,7 @@
<app-file-viewer <app-file-viewer
class="flex w-full flex-1" class="flex w-full flex-1"
[file]="selectedFile()" [file]="selectedFile()"
[(columns)]="selectedFileColumns"
></app-file-viewer> ></app-file-viewer>
} @else { } @else {
<p-button <p-button
@@ -69,7 +70,12 @@
</p-splitter> </p-splitter>
</ng-template> </ng-template>
<ng-template #panel> <ng-template #panel>
<div class="flex items-center justify-center h-full">Panel 4</div> @if (selectedFile()) {
<app-column-editor
class="w-full"
[(columns)]="selectedFileColumns"
></app-column-editor>
}
</ng-template> </ng-template>
</p-splitter> </p-splitter>
<input <input

View File

@@ -15,6 +15,8 @@ import { SplitButtonModule } from 'primeng/splitbutton';
import { InputTextModule } from 'primeng/inputtext'; import { InputTextModule } from 'primeng/inputtext';
import { FileTreeComponent } from './file-tree/file-tree.component'; import { FileTreeComponent } from './file-tree/file-tree.component';
import { FileViewerComponent } from './file-viewer/file-viewer.component'; import { FileViewerComponent } from './file-viewer/file-viewer.component';
import { ColumnEditorComponent } from './column-editor/column-editor.component';
import { Column } from './duckdb.service';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@@ -29,12 +31,14 @@ import { FileViewerComponent } from './file-viewer/file-viewer.component';
SplitButtonModule, SplitButtonModule,
FileTreeComponent, FileTreeComponent,
FileViewerComponent, FileViewerComponent,
ColumnEditorComponent,
], ],
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrl: './app.component.scss', styleUrl: './app.component.scss',
}) })
export class AppComponent { export class AppComponent {
protected selectedFile = signal<File | undefined>(undefined); protected selectedFile = signal<File | undefined>(undefined);
protected selectedFileColumns = signal<Column[]>([]);
protected tabs = signal<File[]>([]); protected tabs = signal<File[]>([]);
protected selectedTab = signal(0); protected selectedTab = signal(0);
protected dragging = signal(false); protected dragging = signal(false);

View File

@@ -0,0 +1,55 @@
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { AccordionModule } from 'primeng/accordion';
import { Column } from '../duckdb.service';
import { Checkbox, CheckboxChangeEvent } from 'primeng/checkbox';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-column-editor',
standalone: true,
imports: [AccordionModule, Checkbox, FormsModule],
template: `
<p-accordion [value]="0">
<p-accordion-panel [value]="0">
<p-accordion-header>Columns</p-accordion-header>
<p-accordion-content>
<ul>
@for (column of columns(); track $index) {
<li>
<p-checkbox
(ngModelChange)="checkboxChanged($index)"
[binary]="true"
[inputId]="column.name"
name="group"
[ngModel]="column.enabled"
/>
<label [for]="column.name" class="ml-2">
{{ column.name }}
</label>
{{ column.name }}
</li>
}
</ul>
</p-accordion-content>
</p-accordion-panel>
</p-accordion>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ColumnEditorComponent {
columns = model<Column[]>();
protected checkboxChanged(index: number) {
this.columns.update((columns) => {
if (columns) {
let enabledColumns = columns?.slice();
enabledColumns[index] = {
...enabledColumns[index],
enabled: !enabledColumns[index].enabled,
};
return enabledColumns;
}
return columns;
});
}
}

View File

@@ -5,6 +5,7 @@ import { z } from 'zod';
export const Column = z.object({ export const Column = z.object({
name: z.string(), name: z.string(),
type: z.string(), type: z.string(),
enabled: z.boolean().default(true),
}); });
export const SortColumn = z.object({ export const SortColumn = z.object({
@@ -142,6 +143,7 @@ export class DuckdbService {
cols.push({ cols.push({
name: jsonData['column_name'], name: jsonData['column_name'],
type: jsonData['column_type'], type: jsonData['column_type'],
enabled: true,
}); });
} }
return cols; return cols;

View File

@@ -5,6 +5,7 @@ import {
effect, effect,
inject, inject,
input, input,
model,
signal, signal,
viewChild, viewChild,
} from '@angular/core'; } from '@angular/core';
@@ -43,14 +44,14 @@ import { PaginatorModule, PaginatorState } from 'primeng/paginator';
PaginatorModule, PaginatorModule,
], ],
template: ` template: `
@if (file() && columns().length > 0) { @if (file() && enabledColumns().length > 0) {
<div class="h-full"> <div class="h-full">
<p-table <p-table
#table #table
sortMode="multiple" sortMode="multiple"
[resizableColumns]="true" [resizableColumns]="true"
columnResizeMode="expand" columnResizeMode="expand"
[columns]="columns()" [columns]="enabledColumns()"
[value]="currentValue()" [value]="currentValue()"
showGridlines showGridlines
[scrollable]="true" [scrollable]="true"
@@ -124,7 +125,7 @@ import { PaginatorModule, PaginatorState } from 'primeng/paginator';
@if (hasAggregates()) { @if (hasAggregates()) {
<ng-template #footer> <ng-template #footer>
<tr> <tr>
@for (col of columns(); track $index) { @for (col of enabledColumns(); track $index) {
<td #attachment> <td #attachment>
@if (col.type === 'DOUBLE' || col.type === 'BIGINT') { @if (col.type === 'DOUBLE' || col.type === 'BIGINT') {
<div class="flex items-baseline"> <div class="flex items-baseline">
@@ -174,7 +175,7 @@ export class FileViewerComponent {
private duckdbService = inject(DuckdbService); private duckdbService = inject(DuckdbService);
// Can't be computed since effect has to run first so file exists in duckdb // Can't be computed since effect has to run first so file exists in duckdb
protected columns = signal<Column[]>([]); columns = model<Column[]>([]);
protected aggregates = signal<(Aggregate | undefined)[]>([]); protected aggregates = signal<(Aggregate | undefined)[]>([]);
protected currentAggregateColumn = signal<number | undefined>(undefined); protected currentAggregateColumn = signal<number | undefined>(undefined);
protected aggregateValues = signal<(number | undefined)[]>([]); protected aggregateValues = signal<(number | undefined)[]>([]);
@@ -195,6 +196,10 @@ export class FileViewerComponent {
() => !!this.columns().find((col) => this.isAggregateColumn(col)), () => !!this.columns().find((col) => this.isAggregateColumn(col)),
); );
protected enabledColumns = computed(() =>
this.columns().filter((col) => col.enabled),
);
protected aggregateItems: MenuItem[] = aggregateTypes.map((type) => ({ protected aggregateItems: MenuItem[] = aggregateTypes.map((type) => ({
label: type, label: type,
command: () => this.updateAggregateValue(type), command: () => this.updateAggregateValue(type),