mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-29 08:12:56 +00:00
203 lines
5.2 KiB
Svelte
203 lines
5.2 KiB
Svelte
<script lang="ts">
|
|
import { GridApi, createGrid, type IDatasource } from 'ag-grid-community'
|
|
|
|
import 'ag-grid-community/styles/ag-grid.css'
|
|
import 'ag-grid-community/styles/ag-theme-alpine.css'
|
|
import { twMerge } from 'tailwind-merge'
|
|
import DarkModeObserver from './DarkModeObserver.svelte'
|
|
import { HelpersService } from '$lib/gen'
|
|
import { enterpriseLicense, workspaceStore } from '$lib/stores'
|
|
import { Download } from 'lucide-svelte'
|
|
|
|
// import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css'
|
|
|
|
let selectedRowIndex = -1
|
|
export let s3resource: string
|
|
export let storage: string | undefined
|
|
export let workspaceId: string | undefined
|
|
export let disable_download: boolean = false
|
|
|
|
let csvSeparatorChar: string = ','
|
|
let datasource: IDatasource = {
|
|
rowCount: 0,
|
|
getRows: async function (params) {
|
|
try {
|
|
const searchCol = params.filterModel ? Object.keys(params.filterModel)?.[0] : undefined
|
|
const csv = s3resource.endsWith('.csv')
|
|
|
|
const requestBody = {
|
|
workspace: workspaceId ?? $workspaceStore!,
|
|
path: s3resource,
|
|
offset: params.startRow,
|
|
limit: params.endRow - params.startRow,
|
|
sortCol: params.sortModel?.[0]?.colId,
|
|
sortDesc: params.sortModel?.[0]?.sort == 'desc',
|
|
searchCol: searchCol,
|
|
searchTerm: searchCol ? params.filterModel?.[searchCol]?.filter : undefined,
|
|
storage: storage,
|
|
csvSeparator: csv ? csvSeparatorChar : undefined
|
|
}
|
|
const res = (
|
|
csv
|
|
? await HelpersService.loadCsvPreview(requestBody)
|
|
: await HelpersService.loadParquetPreview(requestBody)
|
|
) as any
|
|
for (let i = 0; i < res.rows.length; i++) {
|
|
res.rows[i]['__index'] = i + params.startRow
|
|
if (!$enterpriseLicense) {
|
|
Object.keys(res.rows[i]).forEach((key) => {
|
|
if (key != '__index') {
|
|
res.rows[i][key] = 'Require EE'
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
params.successCallback(res.rows)
|
|
} catch (e) {
|
|
console.error(e)
|
|
params.failCallback()
|
|
}
|
|
}
|
|
}
|
|
|
|
function toggleRow(row: any) {
|
|
if (row) {
|
|
let rowIndex = row.rowIndex
|
|
let data = { ...row.data }
|
|
delete data['__index']
|
|
if (selectedRowIndex !== rowIndex) {
|
|
selectedRowIndex = rowIndex
|
|
}
|
|
}
|
|
}
|
|
|
|
function toggleRows(rows: any[]) {
|
|
toggleRow(rows[0])
|
|
}
|
|
|
|
let eGui: HTMLDivElement
|
|
|
|
$: eGui && mountGrid()
|
|
|
|
let error: string | undefined = undefined
|
|
async function mountGrid() {
|
|
if (eGui) {
|
|
try {
|
|
const csv = s3resource.endsWith('.csv')
|
|
|
|
const res = csv
|
|
? await HelpersService.loadCsvPreview({
|
|
workspace: $workspaceStore!,
|
|
path: s3resource,
|
|
limit: 0,
|
|
storage: storage,
|
|
csvSeparator: csvSeparatorChar
|
|
})
|
|
: await HelpersService.loadParquetPreview({
|
|
workspace: $workspaceStore!,
|
|
path: s3resource,
|
|
limit: 0,
|
|
storage: storage
|
|
})
|
|
|
|
createGrid(
|
|
eGui,
|
|
{
|
|
rowModelType: 'infinite',
|
|
datasource,
|
|
// @ts-ignore
|
|
columnDefs: res.columns.map((c) => {
|
|
return {
|
|
field: c,
|
|
sortable: true,
|
|
filter: true,
|
|
filterParams: {
|
|
filterOptions: ['contains'],
|
|
maxNumConditions: 1
|
|
}
|
|
}
|
|
}),
|
|
pagination: false,
|
|
// defaultColDef: {
|
|
// flex: 1
|
|
// },
|
|
suppressColumnMoveAnimation: true,
|
|
rowSelection: 'multiple',
|
|
rowMultiSelectWithClick: true,
|
|
suppressRowDeselection: true,
|
|
|
|
onSelectionChanged: (e) => {
|
|
onSelectionChanged(e.api)
|
|
},
|
|
getRowId: (data) => {
|
|
return (data as any).data['__index']
|
|
}
|
|
},
|
|
{}
|
|
)
|
|
error = undefined
|
|
} catch (e) {
|
|
error = e.body
|
|
console.error(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
function onSelectionChanged(api: GridApi<any>) {
|
|
const rows = api.getSelectedNodes()
|
|
if (rows != undefined) {
|
|
toggleRows(rows)
|
|
}
|
|
}
|
|
|
|
let darkMode: boolean = false
|
|
</script>
|
|
|
|
<DarkModeObserver bind:darkMode />
|
|
|
|
<div class={twMerge('mt-2 flex flex-col h-full min-h-[600px]')}>
|
|
{#if s3resource.endsWith('.csv')}
|
|
<div class="flex flex-row-reverse w-full">
|
|
<div class="flex items-baseline">
|
|
<label for="csvSeparatorChar" class="text-2xs text-secondary">Separator</label>
|
|
|
|
<div class="w-12 ml-2 mr-2">
|
|
<select class="h-8" bind:value={csvSeparatorChar} on:change={(e) => mountGrid()}>
|
|
<option value=",">,</option>
|
|
<option value=";">;</option>
|
|
<option value="\t">\t</option>
|
|
<option value="|">|</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
{#if !disable_download && !s3resource.endsWith('.csv')}
|
|
<a
|
|
target="_blank"
|
|
href="/api/w/{workspaceId}/job_helpers/download_s3_parquet_file_as_csv?file_key={s3resource}{storage
|
|
? `&storage=${storage}`
|
|
: ''}"
|
|
class="text-secondary w-full text-right underline text-2xs whitespace-nowrap"
|
|
><div class="flex flex-row-reverse gap-2 items-center"><Download size={12} /> CSV</div></a
|
|
>
|
|
{/if}
|
|
|
|
<div
|
|
class="ag-theme-alpine shadow-sm h-full"
|
|
class:ag-theme-alpine-dark={darkMode}
|
|
style="height: 600px;"
|
|
>
|
|
{#if error}
|
|
<div class="text-red-500">{error}</div>
|
|
<div>Try changing separator to fix it</div>
|
|
{/if}
|
|
<div bind:this={eGui} style="height:100%; " />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- <div class="flex gap-1 absolute bottom-1 right-2 text-sm text-secondary"
|
|
>{firstRow}{'->'}{lastRow + 1} of {datasource?.rowCount} rows</div
|
|
> -->
|