Form interface and Loading menu
This commit is contained in:
parent
f084cf70ae
commit
8d26d56599
@ -5,7 +5,7 @@ import {
|
|||||||
type DataEditorRef,
|
type DataEditorRef,
|
||||||
type GridColumn,
|
type GridColumn,
|
||||||
} from '@glideapps/glide-data-grid';
|
} from '@glideapps/glide-data-grid';
|
||||||
import { ActionIcon, Stack } from '@mantine/core';
|
import { ActionIcon, Group, Stack } from '@mantine/core';
|
||||||
import { useElementSize, useMergedRef } from '@mantine/hooks';
|
import { useElementSize, useMergedRef } from '@mantine/hooks';
|
||||||
import { IconMenu2 } from '@tabler/icons-react';
|
import { IconMenu2 } from '@tabler/icons-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -19,6 +19,7 @@ import { SortUpSprite } from './components/sprites/SortUp';
|
|||||||
import { useGridlerStore } from './components/Store';
|
import { useGridlerStore } from './components/Store';
|
||||||
import classes from './Gridler.module.css';
|
import classes from './Gridler.module.css';
|
||||||
import { useGridTheme } from './hooks/use-grid-theme';
|
import { useGridTheme } from './hooks/use-grid-theme';
|
||||||
|
import { RightMenuIcon } from './components/RightMenuIcon';
|
||||||
|
|
||||||
export const GridlerDataGrid = () => {
|
export const GridlerDataGrid = () => {
|
||||||
const ref = React.useRef<DataEditorRef | null>(null);
|
const ref = React.useRef<DataEditorRef | null>(null);
|
||||||
@ -195,14 +196,11 @@ export const GridlerDataGrid = () => {
|
|||||||
rangeSelect="multi-rect"
|
rangeSelect="multi-rect"
|
||||||
ref={refMerged as any}
|
ref={refMerged as any}
|
||||||
rightElement={
|
rightElement={
|
||||||
<ActionIcon
|
<Group>
|
||||||
mr="xs"
|
{sections?.rightElementStart}
|
||||||
mt="2px"
|
<RightMenuIcon />
|
||||||
onClick={(e) => onContextClick('menu', e)}
|
{sections?.rightElementEnd}
|
||||||
variant="subtle"
|
</Group>
|
||||||
>
|
|
||||||
<IconMenu2 />
|
|
||||||
</ActionIcon>
|
|
||||||
}
|
}
|
||||||
rowHeight={rowHeight ?? 22}
|
rowHeight={rowHeight ?? 22}
|
||||||
//rowMarkersCheckboxStyle='square'
|
//rowMarkersCheckboxStyle='square'
|
||||||
|
|||||||
@ -20,6 +20,8 @@ export const APIAdaptorGoLangv2 = React.memo((props: APIOptions) => {
|
|||||||
const pageSize = getState('pageSize');
|
const pageSize = getState('pageSize');
|
||||||
const colFilters = getState('colFilters');
|
const colFilters = getState('colFilters');
|
||||||
const _active_requests = getState('_active_requests');
|
const _active_requests = getState('_active_requests');
|
||||||
|
setState('loadingData', true);
|
||||||
|
try {
|
||||||
//console.log('APIAdaptorGoLangv2', { _active_requests, index, pageSize, props });
|
//console.log('APIAdaptorGoLangv2', { _active_requests, index, pageSize, props });
|
||||||
if (props && props.url) {
|
if (props && props.url) {
|
||||||
const head = new Headers();
|
const head = new Headers();
|
||||||
@ -55,6 +57,7 @@ export const APIAdaptorGoLangv2 = React.memo((props: APIOptions) => {
|
|||||||
});
|
});
|
||||||
if (_active_requests && currentRequestIndex >= 0 && _active_requests[currentRequestIndex]) {
|
if (_active_requests && currentRequestIndex >= 0 && _active_requests[currentRequestIndex]) {
|
||||||
//console.log(`Already queued ${index}`, index, s._active_requests);
|
//console.log(`Already queued ${index}`, index, s._active_requests);
|
||||||
|
setState('loadingData', false);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,13 +80,20 @@ export const APIAdaptorGoLangv2 = React.memo((props: APIOptions) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
setState('loadingData', false);
|
||||||
return data ?? [];
|
return data ?? [];
|
||||||
}
|
}
|
||||||
addError(`${res.status} ${res.statusText}`, 'api', props.url);
|
addError(`${res.status} ${res.statusText}`, 'api', props.url);
|
||||||
|
|
||||||
await setStateFN('_active_requests', (cv) => [...(cv ?? []).filter((f) => f.page !== index)]);
|
await setStateFN('_active_requests', (cv) => [
|
||||||
|
...(cv ?? []).filter((f) => f.page !== index),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
//console.log('APIAdaptorGoLangv2 error', e);
|
||||||
|
addError(`Error: ${e}`, 'api', props.url);
|
||||||
|
}
|
||||||
|
setState('loadingData', false);
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
26
src/Gridler/components/GridlerFormInterface.tsx
Normal file
26
src/Gridler/components/GridlerFormInterface.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import type { FormRequestType } from '../utils/types';
|
||||||
|
|
||||||
|
import { type GridlerProps, useGridlerStore } from './Store';
|
||||||
|
|
||||||
|
export function GlidlerFormInterface(props: {
|
||||||
|
getMenuItems?: GridlerProps['getMenuItems'];
|
||||||
|
onRequestForm: (request: FormRequestType, data: Record<string, any>) => void;
|
||||||
|
}) {
|
||||||
|
// const [getMenuItems, getState, , mounted, setState] = useGridlerStore((s) => [
|
||||||
|
// s.getMenuItems,
|
||||||
|
// s.getState,
|
||||||
|
// s.mounted,
|
||||||
|
// s.setState,
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (mounted) {
|
||||||
|
// setState('getMenuItems', props.getMenuItems);
|
||||||
|
// setState('onRequestForm', props.onRequestForm);
|
||||||
|
// }
|
||||||
|
// }, [props.getMenuItems, props.onRequestForm, mounted, setState]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
23
src/Gridler/components/RightMenuIcon.tsx
Normal file
23
src/Gridler/components/RightMenuIcon.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ActionIcon } from '@mantine/core';
|
||||||
|
import { IconMenu2 } from '@tabler/icons-react';
|
||||||
|
|
||||||
|
import { useGridlerStore } from './Store';
|
||||||
|
|
||||||
|
export function RightMenuIcon() {
|
||||||
|
const { loadingData, onContextClick } = useGridlerStore((s) => ({
|
||||||
|
loadingData: s.loadingData,
|
||||||
|
onContextClick: s.onContextClick,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActionIcon
|
||||||
|
loading={loadingData}
|
||||||
|
mr="xs"
|
||||||
|
mt="2px"
|
||||||
|
onClick={(e) => onContextClick('menu', e)}
|
||||||
|
variant="subtle"
|
||||||
|
>
|
||||||
|
<IconMenu2 />
|
||||||
|
</ActionIcon>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -23,7 +23,7 @@ import { produce } from 'immer';
|
|||||||
import { type PropsWithChildren, type ReactNode, useEffect } from 'react';
|
import { type PropsWithChildren, type ReactNode, useEffect } from 'react';
|
||||||
|
|
||||||
import { type MantineBetterMenuInstance, useMantineBetterMenus } from '../../MantineBetterMenu';
|
import { type MantineBetterMenuInstance, useMantineBetterMenus } from '../../MantineBetterMenu';
|
||||||
import { type TRequest } from '../utils/types';
|
import { type FormRequestType } from '../utils/types';
|
||||||
import { ColumnFilterSet, type GridlerColumn, type GridlerColumns } from './Column';
|
import { ColumnFilterSet, type GridlerColumn, type GridlerColumns } from './Column';
|
||||||
import { SortDownSprite } from './sprites/SortDown';
|
import { SortDownSprite } from './sprites/SortDown';
|
||||||
import { SortUpSprite } from './sprites/SortUp';
|
import { SortUpSprite } from './sprites/SortUp';
|
||||||
@ -80,12 +80,14 @@ export interface GridlerProps extends PropsWithChildren {
|
|||||||
value: any,
|
value: any,
|
||||||
store: GridlerState
|
store: GridlerState
|
||||||
) => GridCell;
|
) => GridCell;
|
||||||
request?: TRequest;
|
|
||||||
rowHeight?: number;
|
rowHeight?: number;
|
||||||
sections?: {
|
sections?: {
|
||||||
bottom?: React.ReactNode;
|
bottom?: React.ReactNode;
|
||||||
left?: React.ReactNode;
|
left?: React.ReactNode;
|
||||||
right?: React.ReactNode;
|
right?: React.ReactNode;
|
||||||
|
rightElementEnd?: React.ReactNode;
|
||||||
|
rightElementStart?: React.ReactNode;
|
||||||
top?: React.ReactNode;
|
top?: React.ReactNode;
|
||||||
};
|
};
|
||||||
selectedRow?: number;
|
selectedRow?: number;
|
||||||
@ -115,8 +117,8 @@ export interface GridlerState {
|
|||||||
colSize?: Record<string, number>;
|
colSize?: Record<string, number>;
|
||||||
colSort?: Array<SortOption>;
|
colSort?: Array<SortOption>;
|
||||||
data?: Array<any>;
|
data?: Array<any>;
|
||||||
|
|
||||||
errors: Array<string>;
|
errors: Array<string>;
|
||||||
|
|
||||||
focused?: boolean;
|
focused?: boolean;
|
||||||
get: () => GridlerState;
|
get: () => GridlerState;
|
||||||
getCellContent: (cell: Item) => GridCell;
|
getCellContent: (cell: Item) => GridCell;
|
||||||
@ -126,8 +128,9 @@ export interface GridlerState {
|
|||||||
) => CellArray | GetCellsThunk;
|
) => CellArray | GetCellsThunk;
|
||||||
getRowBuffer: (row: number) => any;
|
getRowBuffer: (row: number) => any;
|
||||||
getState: <K extends keyof GridlerStoreState>(key: K) => GridlerStoreState[K];
|
getState: <K extends keyof GridlerStoreState>(key: K) => GridlerStoreState[K];
|
||||||
|
|
||||||
hasLocalData: boolean;
|
hasLocalData: boolean;
|
||||||
|
|
||||||
|
loadingData?: boolean;
|
||||||
loadPage: (page: number, clearMode?: 'all' | 'page') => Promise<void>;
|
loadPage: (page: number, clearMode?: 'all' | 'page') => Promise<void>;
|
||||||
mounted: boolean;
|
mounted: boolean;
|
||||||
onCellEdited: (cell: Item, newVal: EditableGridCell) => void;
|
onCellEdited: (cell: Item, newVal: EditableGridCell) => void;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Divider, Group, Stack, TagsInput, TextInput } from '@mantine/core';
|
import { Checkbox, Divider, Group, Stack, TagsInput, TextInput } from '@mantine/core';
|
||||||
import { useLocalStorage } from '@mantine/hooks';
|
import { useLocalStorage } from '@mantine/hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ export const GridlerGoAPIExampleEventlog = () => {
|
|||||||
const [apiKey, setApiKey] = useLocalStorage({ defaultValue: '', key: 'apikey' });
|
const [apiKey, setApiKey] = useLocalStorage({ defaultValue: '', key: 'apikey' });
|
||||||
const [selectRow, setSelectRow] = useState<string | undefined>('');
|
const [selectRow, setSelectRow] = useState<string | undefined>('');
|
||||||
const [values, setValues] = useState<Array<Record<string, any>>>([]);
|
const [values, setValues] = useState<Array<Record<string, any>>>([]);
|
||||||
|
const [sections, setSections] = useState<Record<string, unknown> | undefined>(undefined);
|
||||||
const columns: GridlerColumns = [
|
const columns: GridlerColumns = [
|
||||||
{
|
{
|
||||||
id: 'id_process',
|
id: 'id_process',
|
||||||
@ -49,6 +50,21 @@ export const GridlerGoAPIExampleEventlog = () => {
|
|||||||
<TextInput label="API Url" onChange={(e) => setApiUrl(e.target.value)} value={apiUrl} />
|
<TextInput label="API Url" onChange={(e) => setApiUrl(e.target.value)} value={apiUrl} />
|
||||||
<TextInput label="API Key" onChange={(e) => setApiKey(e.target.value)} value={apiKey} />
|
<TextInput label="API Key" onChange={(e) => setApiKey(e.target.value)} value={apiKey} />
|
||||||
<Divider />
|
<Divider />
|
||||||
|
<Checkbox
|
||||||
|
label="Show Side Sections"
|
||||||
|
checked={!!sections}
|
||||||
|
onChange={(e) => {
|
||||||
|
e.target.checked
|
||||||
|
? setSections({
|
||||||
|
bottom: <div style={{ backgroundColor: 'teal', height: '25px' }}>bottom</div>,
|
||||||
|
left: <div style={{ backgroundColor: 'orange', width: '20px' }}>L</div>,
|
||||||
|
right: <div style={{ backgroundColor: 'green', width: '20px' }}>R</div>,
|
||||||
|
top: <div style={{ backgroundColor: 'purple', height: '20px' }}>top</div>,
|
||||||
|
})
|
||||||
|
: setSections(undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Divider />
|
||||||
<Gridler
|
<Gridler
|
||||||
height="100%"
|
height="100%"
|
||||||
columns={columns}
|
columns={columns}
|
||||||
@ -69,12 +85,7 @@ export const GridlerGoAPIExampleEventlog = () => {
|
|||||||
//console.log('GridlerGoAPIExampleEventlog onChange', v);
|
//console.log('GridlerGoAPIExampleEventlog onChange', v);
|
||||||
setValues(v);
|
setValues(v);
|
||||||
}}
|
}}
|
||||||
sections={{
|
sections={sections}
|
||||||
bottom: <div style={{ backgroundColor: 'teal', height: '25px' }}>bottom</div>,
|
|
||||||
left: <div style={{ backgroundColor: 'orange', width: '20px' }}>L</div>,
|
|
||||||
right: <div style={{ backgroundColor: 'green', width: '20px' }}>R</div>,
|
|
||||||
top: <div style={{ backgroundColor: 'purple', height: '20px' }}>top</div>,
|
|
||||||
}}
|
|
||||||
selectedRow={selectRow ? parseInt(selectRow, 10) : undefined}
|
selectedRow={selectRow ? parseInt(selectRow, 10) : undefined}
|
||||||
selectMode="row"
|
selectMode="row"
|
||||||
uniqueid="gridtest"
|
uniqueid="gridtest"
|
||||||
|
|||||||
@ -15,4 +15,4 @@ export interface APIOptions {
|
|||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TRequest = 'change' | 'delete' | 'insert' | 'select' ;
|
export type FormRequestType = 'change' | 'delete' | 'insert' | 'select' ;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user