A few tweaks
This commit is contained in:
31
app.go
31
app.go
@@ -2,8 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.cems.dev/cdricms/bdooc/proto"
|
"git.cems.dev/cdricms/bdooc/proto"
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
@@ -52,13 +50,6 @@ func (a *App) GetEmployees(path string, limit, page uint, column, query *string)
|
|||||||
return a.employees.Employees[page*limit : page*limit+limit], nil
|
return a.employees.Employees[page*limit : page*limit+limit], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) SaveData(data []uint8, filename string) {
|
|
||||||
err := proto.SaveToFile(data, filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GetProtoPath() string {
|
func (a *App) GetProtoPath() string {
|
||||||
return a.OpenPath([]runtime.FileFilter{{
|
return a.OpenPath([]runtime.FileFilter{{
|
||||||
DisplayName: "Proto binary file",
|
DisplayName: "Proto binary file",
|
||||||
@@ -78,8 +69,22 @@ func (a *App) OpenPath(filters []runtime.FileFilter) string {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) IsPathValid(path string) bool {
|
type FunctionAgg string
|
||||||
_, err := os.Stat(path)
|
|
||||||
fmt.Println(path)
|
const (
|
||||||
return !os.IsNotExist(err)
|
AVG = FunctionAgg("AVG")
|
||||||
|
SUM = FunctionAgg("SUM")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *App) AggregateByColumn(groupBy proto.EmployeeField, on proto.EmployeeField, function FunctionAgg) map[string]float64 {
|
||||||
|
return proto.AggregateByColumn(a.employees, proto.EmployeeField(proto.SnakeCaseToPascalCase(string(groupBy))), func(ep proto.EmployeePList) float64 {
|
||||||
|
switch function {
|
||||||
|
case AVG:
|
||||||
|
return proto.Average(ep, proto.EmployeeField(proto.SnakeCaseToPascalCase(string(on))))
|
||||||
|
case SUM:
|
||||||
|
return proto.Sum(ep, proto.EmployeeField(proto.SnakeCaseToPascalCase(string(on))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
109
frontend/src/Aggregation.svelte
Normal file
109
frontend/src/Aggregation.svelte
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Modal from "./Modal.svelte";
|
||||||
|
import { AggregateByColumn } from "../wailsjs/go/main/App.js";
|
||||||
|
export let isOpen: boolean;
|
||||||
|
export let keys: string[];
|
||||||
|
|
||||||
|
let group: string | null = null;
|
||||||
|
let onColumn: string | null = null;
|
||||||
|
let func: string | null = null;
|
||||||
|
|
||||||
|
let promise: ReturnType<typeof AggregateByColumn>;
|
||||||
|
|
||||||
|
async function Aggregate() {
|
||||||
|
if (!group || !onColumn || !func) return;
|
||||||
|
try {
|
||||||
|
const res = await AggregateByColumn(group, onColumn, func);
|
||||||
|
return res;
|
||||||
|
} catch (error) {
|
||||||
|
throw error.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
{isOpen}
|
||||||
|
onClose={() => {
|
||||||
|
isOpen = false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<section>
|
||||||
|
<p>Aggregation</p>
|
||||||
|
<div>
|
||||||
|
<label for="group">Group by: </label>
|
||||||
|
<select bind:value={group} name="group" id="">
|
||||||
|
{#each keys as key}
|
||||||
|
<option value={key}>{key}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="on-column">On: </label>
|
||||||
|
<select bind:value={onColumn} name="on-column" id="">
|
||||||
|
{#each keys as key}
|
||||||
|
<option value={key}>{key}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
<label for="function">Using: </label>
|
||||||
|
<select bind:value={func} name="function" id="">
|
||||||
|
<option value="AVG">Average</option>
|
||||||
|
<option value="SUM">SUM</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="button" on:click={() => (promise = Aggregate())}
|
||||||
|
>Aggregate</button
|
||||||
|
>
|
||||||
|
</section>
|
||||||
|
{#if promise}
|
||||||
|
<section>
|
||||||
|
{#await promise}
|
||||||
|
<p>Loading...</p>
|
||||||
|
{:then res}
|
||||||
|
<table class="agg-table">
|
||||||
|
<tr>
|
||||||
|
<th>{group}</th>
|
||||||
|
<th>{func} of {onColumn}</th>
|
||||||
|
</tr>
|
||||||
|
{#each Object.entries(res) as [key, value]}
|
||||||
|
<tr>
|
||||||
|
<td>{key}</td>
|
||||||
|
<td>{value}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</table>
|
||||||
|
{:catch error}
|
||||||
|
<p>{error}</p>
|
||||||
|
{/await}
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: #343434;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
background-color: #110909;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,33 +1,44 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import * as rt from "../wailsjs/runtime/runtime"
|
import * as rt from "../wailsjs/runtime/runtime";
|
||||||
|
|
||||||
import Table from "./Table.svelte";
|
import Table from "./Table.svelte";
|
||||||
|
import { proto } from "../wailsjs/go/models";
|
||||||
|
import Aggregation from "./Aggregation.svelte";
|
||||||
|
|
||||||
let path: string;
|
let path: string;
|
||||||
let page = 0;
|
let page = 0;
|
||||||
|
|
||||||
|
let isAggregate = false;
|
||||||
|
|
||||||
let limitReached: boolean;
|
let limitReached: boolean;
|
||||||
|
|
||||||
$: console.log(limitReached)
|
$: console.log(limitReached);
|
||||||
|
|
||||||
|
const keys: string[] = Object.keys(new proto.Employee());
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
rt.EventsOn("proto-opened", (_path: string) => {
|
rt.EventsOn("proto-opened", (_path: string) => {
|
||||||
path = _path;
|
path = _path;
|
||||||
})
|
});
|
||||||
|
|
||||||
rt.EventsOn("csv-converted", (_path: string) => {
|
rt.EventsOn("csv-converted", (_path: string) => {
|
||||||
console.log(_path)
|
console.log(_path);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
rt.EventsOn("aggregation", () => {
|
||||||
|
isAggregate = true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
{#if path}
|
{#if path}
|
||||||
<Table {path} {page} bind:limitReached={limitReached} />
|
<Table {path} bind:page bind:limitReached />
|
||||||
<button disabled={page < 1} on:click={() => page--}>Prev</button>
|
<button disabled={page < 1} on:click={() => page--}>Prev</button>
|
||||||
<span>{page+1}</span>
|
<span>{page + 1}</span>
|
||||||
<button disabled={limitReached} on:click={() => page++}>Next</button>
|
<button disabled={limitReached} on:click={() => page++}>Next</button>
|
||||||
|
<Aggregation bind:isOpen={isAggregate} {keys} />
|
||||||
{/if}
|
{/if}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
35
frontend/src/Modal.svelte
Normal file
35
frontend/src/Modal.svelte
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let isOpen: boolean;
|
||||||
|
export let onClose: () => void;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if isOpen}
|
||||||
|
<dialog class="backdrop" open={isOpen}>
|
||||||
|
<div class="dialog">
|
||||||
|
<slot />
|
||||||
|
<button on:click={() => onClose()}>Close</button>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.backdrop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
background-color: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { GetEmployees } from "../wailsjs/go/main/App.js";
|
import { GetEmployees } from "../wailsjs/go/main/App.js";
|
||||||
// import type { proto } from "../wailsjs/go/models";
|
|
||||||
// let employees: proto.Employee[] = [];
|
|
||||||
export let path: string;
|
export let path: string;
|
||||||
export let page: number;
|
export let page: number;
|
||||||
let limit: number = 10;
|
let limit: number = 10;
|
||||||
@@ -12,11 +11,17 @@
|
|||||||
let column: string | null = null;
|
let column: string | null = null;
|
||||||
let query: string | null = null;
|
let query: string | null = null;
|
||||||
|
|
||||||
async function listEmployees(path: string, limit: number, page: number, column?: string, query?: string) {
|
async function listEmployees(
|
||||||
|
path: string,
|
||||||
|
limit: number,
|
||||||
|
page: number,
|
||||||
|
column?: string,
|
||||||
|
query?: string,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const employees = await GetEmployees(path, limit, page, column, query);
|
const employees = await GetEmployees(path, limit, page, column, query);
|
||||||
limitReached = employees.length < limit;
|
limitReached = employees.length < limit;
|
||||||
return employees
|
return employees;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error.message;
|
throw error.message;
|
||||||
}
|
}
|
||||||
@@ -40,10 +45,16 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
page = 0;
|
||||||
column = _column;
|
column = _column;
|
||||||
query = _query;
|
query = _query;
|
||||||
}}>Search</button
|
}}>Search</button
|
||||||
>
|
>
|
||||||
|
<button type="button" on:click={() => {
|
||||||
|
query = ""
|
||||||
|
column = null
|
||||||
|
page = 0
|
||||||
|
}}>Reset</button>
|
||||||
</div>
|
</div>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
7
frontend/wailsjs/go/main/App.d.ts
vendored
7
frontend/wailsjs/go/main/App.d.ts
vendored
@@ -1,14 +1,13 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
import {proto} from '../models';
|
import {proto} from '../models';
|
||||||
|
import {main} from '../models';
|
||||||
import {frontend} from '../models';
|
import {frontend} from '../models';
|
||||||
|
|
||||||
|
export function AggregateByColumn(arg1:proto.EmployeeField,arg2:proto.EmployeeField,arg3:main.FunctionAgg):Promise<{[key: string]: number}>;
|
||||||
|
|
||||||
export function GetEmployees(arg1:string,arg2:number,arg3:number,arg4:any,arg5:any):Promise<Array<proto.Employee>>;
|
export function GetEmployees(arg1:string,arg2:number,arg3:number,arg4:any,arg5:any):Promise<Array<proto.Employee>>;
|
||||||
|
|
||||||
export function GetProtoPath():Promise<string>;
|
export function GetProtoPath():Promise<string>;
|
||||||
|
|
||||||
export function IsPathValid(arg1:string):Promise<boolean>;
|
|
||||||
|
|
||||||
export function OpenPath(arg1:Array<frontend.FileFilter>):Promise<string>;
|
export function OpenPath(arg1:Array<frontend.FileFilter>):Promise<string>;
|
||||||
|
|
||||||
export function SaveData(arg1:Array<number>,arg2:string):Promise<void>;
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export function AggregateByColumn(arg1, arg2, arg3) {
|
||||||
|
return window['go']['main']['App']['AggregateByColumn'](arg1, arg2, arg3);
|
||||||
|
}
|
||||||
|
|
||||||
export function GetEmployees(arg1, arg2, arg3, arg4, arg5) {
|
export function GetEmployees(arg1, arg2, arg3, arg4, arg5) {
|
||||||
return window['go']['main']['App']['GetEmployees'](arg1, arg2, arg3, arg4, arg5);
|
return window['go']['main']['App']['GetEmployees'](arg1, arg2, arg3, arg4, arg5);
|
||||||
}
|
}
|
||||||
@@ -10,14 +14,6 @@ export function GetProtoPath() {
|
|||||||
return window['go']['main']['App']['GetProtoPath']();
|
return window['go']['main']['App']['GetProtoPath']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IsPathValid(arg1) {
|
|
||||||
return window['go']['main']['App']['IsPathValid'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OpenPath(arg1) {
|
export function OpenPath(arg1) {
|
||||||
return window['go']['main']['App']['OpenPath'](arg1);
|
return window['go']['main']['App']['OpenPath'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SaveData(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['SaveData'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|||||||
5
main.go
5
main.go
@@ -71,6 +71,11 @@ func main() {
|
|||||||
runtime.EventsEmit(app.ctx, "csv-converted", filePath)
|
runtime.EventsEmit(app.ctx, "csv-converted", filePath)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
analysisMenu :=appMenu.AddSubmenu("Analysis")
|
||||||
|
analysisMenu.AddText("Aggregation", keys.CmdOrCtrl("a"), func(_ *menu.CallbackData) {
|
||||||
|
runtime.EventsEmit(app.ctx, "aggregation")
|
||||||
|
})
|
||||||
|
|
||||||
// Create application with options
|
// Create application with options
|
||||||
err := wails.Run(&options.App{
|
err := wails.Run(&options.App{
|
||||||
Title: "bdooc-t",
|
Title: "bdooc-t",
|
||||||
|
|||||||
Reference in New Issue
Block a user