Skip to content

Commit

Permalink
feat: ✨ export to excel in grid
Browse files Browse the repository at this point in the history
  • Loading branch information
espenkalle committed Sep 19, 2023
1 parent d23379e commit 19bea52
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 200 deletions.
7 changes: 4 additions & 3 deletions apps/test-app/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Workspace } from '@equinor/workspace-fusion';
import { gridModule } from '@equinor/workspace-fusion/grid-module';
import { gardenModule } from '@equinor/workspace-fusion/garden-module';
import { gridModule } from '@equinor/workspace-fusion/grid-module';
import { GroupingOption } from '@equinor/workspace-garden';
import React from 'react';
import { createRoot } from 'react-dom/client';

export function App() {
return (
Expand All @@ -14,6 +14,7 @@ export function App() {
getRows: async ({ success, request }, filter) => {
success({ rowData: [{ id: '123' }, { id: '125' }, { id: '9342' }, { id: '1212' }], rowCount: 4 });
},
excelExport: async (filterState) => new Promise((res, rej) => setTimeout(() => {res(); console.log("løøøøøøø")}, 2000)),
}}
sidesheetOptions={{
type: 'default',
Expand Down
36 changes: 18 additions & 18 deletions packages/garden/src/lib/hooks/useItemWidths.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { useEffect, useState } from 'react';

export const defaultGardenPackageWidth = 300;

export function useItemWidths(columnCount: number) {
const [widths, setWidths] = useState<number[]>([]);

/**
* How to calculate longest width?
*/
useEffect(() => {
if (columnCount > 0) {
setWidths(new Array(columnCount).fill(defaultGardenPackageWidth));
}
}, [columnCount]);

return widths;
}
import { useEffect, useState } from 'react';

export const defaultGardenPackageWidth = 300;

export function useItemWidths(columnCount: number) {
const [widths, setWidths] = useState<number[]>([]);

/**
* How to calculate longest width?
*/
useEffect(() => {
if (columnCount > 0) {
setWidths(new Array(columnCount).fill(defaultGardenPackageWidth));
}
}, [columnCount]);

return widths;
}
67 changes: 35 additions & 32 deletions packages/workspace-fusion/src/lib/components/ErrorComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
import { Dialog, Typography } from '@equinor/eds-core-react';

interface DumpsterFireDialogProps {
title?: string;
text: string;
buttons: React.ReactElement[];
}

export function DumpsterFireDialog({
text,
title = 'Ooops, this is embarassing..',
buttons,
}: DumpsterFireDialogProps): JSX.Element {
return (
<Dialog style={{ width: '600px' }} open={true}>
<Dialog.Header>
<Dialog.Title>{title}</Dialog.Title>
</Dialog.Header>
<Dialog.CustomContent>
<Typography variant="body_short">{text}</Typography>
</Dialog.CustomContent>
<Dialog.Actions>
<>
{buttons.map((comp, i) => {
const Component = () => comp;
return <Component key={i} />;
})}
</>
</Dialog.Actions>
</Dialog>
);
}
import { Button, Dialog, Typography } from '@equinor/eds-core-react';
import { useState } from 'react';

interface DumpsterFireDialogProps {
title?: string;
text: string;
buttons?: React.ReactElement[];
}

export function DumpsterFireDialog({
text,
title = 'Ooops, this is embarassing..',
buttons,
}: DumpsterFireDialogProps): JSX.Element {
const [isOpen, setIsOpen] = useState(true);
return (
<Dialog style={{ width: '600px' }} open={isOpen} isDismissable={true}>
<Dialog.Header>
<Dialog.Title>{title}</Dialog.Title>
</Dialog.Header>
<Dialog.CustomContent>
<Typography variant="body_short">{text}</Typography>
</Dialog.CustomContent>
<Dialog.Actions>
<>
{buttons?.map((comp, i) => {
const Component = () => comp;
return <Component key={i} />;
})}
</>
<Button onClick={() => setIsOpen(false)}>OK</Button>
</Dialog.Actions>
</Dialog>
);
}
71 changes: 36 additions & 35 deletions packages/workspace-fusion/src/lib/integrations/grid/grid.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
/**
* Integrations folder for exporting types from the integration
* namespace: @equinor/workspace-fusion/grid
*/

import {
ColDef,
ColumnState,
GridOptions,
ICellRendererProps,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
Module,
} from '@equinor/workspace-ag-grid';

export type {
ColDef,
ColumnState,
GridConfig,
GridOptions,
ICellRendererProps,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
};

type GridConfig<T, TFilter> = {
columnDefinitions: ColDef<T>[];
getRows: (params: IServerSideGetRowsParams, filters: TFilter) => Promise<void>;
gridOptions?: Omit<GridOptions<T>, 'rowData' | 'context' | 'pagination' | 'paginationPageSize'>;
/**
* AG-grid-modules
* https://www.ag-grid.com/javascript-data-grid/modules/
*/
modules?: Module[];
};
/**
* Integrations folder for exporting types from the integration
* namespace: @equinor/workspace-fusion/grid
*/

import {
ColDef,
ColumnState,
GridOptions,
ICellRendererProps,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
Module,
} from '@equinor/workspace-ag-grid';

export type {
ColDef,
ColumnState,
GridConfig,
GridOptions,
ICellRendererProps,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
};

type GridConfig<T, TFilter> = {
columnDefinitions: ColDef<T>[];
getRows: (params: IServerSideGetRowsParams, filters: TFilter) => Promise<void>;
gridOptions?: Omit<GridOptions<T>, 'rowData' | 'context' | 'pagination' | 'paginationPageSize'>;
/**
* AG-grid-modules
* https://www.ag-grid.com/javascript-data-grid/modules/
*/
modules?: Module[];
excelExport?: (params: TFilter) => Promise<void>;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GridConfig } from '../grid';

export type WorkspaceGridProps<TData extends Record<PropertyKey, unknown>, TFilter> = {
gridOptions?: GridConfig<TData, TFilter>;
};
import { GridConfig } from '../grid';

export type WorkspaceGridProps<TData extends Record<PropertyKey, unknown>, TFilter> = {
gridOptions?: GridConfig<TData, TFilter>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const GardenWrapper = <TData extends Record<PropertyKey, unknown>, TFilte
}, [groupingKeys, timeInterval, dateVariant]);

const { setIcons } = useWorkspaceHeaderComponents();

useEffect(() => {
const icon: HeaderIcon = {
Icon: ({ anchor }) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Button, Icon, Popover, Progress } from '@equinor/eds-core-react';
import { close, more_vertical } from '@equinor/eds-icons';
import { tokens } from '@equinor/eds-tokens';
import { useMutation } from '@tanstack/react-query';
import { useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import styled from 'styled-components';
import { DumpsterFireDialog } from '../../../lib/components/ErrorComponent';

Icon.add({ close, more_vertical });

type GridOptionsPopoverProps = {
anchor: HTMLElement;
filterState: any;
excelExport?: (params: any) => Promise<void>;
};
export const GridOptionPopover = ({ anchor, excelExport, filterState }: GridOptionsPopoverProps) => {
const [isOpen, setIsOpen] = useState(false);
const pRef = useRef(null);
const popoverRef = useRef<HTMLDivElement | null>(null);

const { error, isLoading, isError, mutateAsync } = useMutation(['exportData'], async () => {
if (!excelExport) {
console.warn('No Excel export function found');
return;
}
return await excelExport(filterState);
});

const handleExportToExcel = () => {
mutateAsync();
};

return (
<>
<Icon
name="more_vertical"
color={tokens.colors.interactive.primary__resting.hex}
ref={pRef}
onClick={() => setIsOpen((s) => !s)}
/>
{createPortal(
<Popover ref={popoverRef} open={isOpen} anchorEl={pRef.current}>
<Popover.Header>
<StyledPopoverHeaderLine>
<Popover.Title>Grid Options</Popover.Title>
<Icon
name="close"
color={tokens.colors.interactive.primary__resting.hex}
onClick={() => setIsOpen(false)}
/>
</StyledPopoverHeaderLine>
</Popover.Header>
<Popover.Content style={{ overflow: 'hidden' }}>
<ButtContainer>
{isError && <DumpsterFireDialog text={typeof error === 'string' ? error : 'We encountered an issue fetching the data. Please try again later.'} />}
<Button disabled={excelExport == undefined} style={{ width: '130px' }} onClick={!isLoading ? handleExportToExcel : undefined}>
{isLoading ? <Progress.Dots color={'neutral'} /> : 'Export to Excel'}
</Button>
</ButtContainer>
</Popover.Content>
</Popover>,
anchor
)}
</>
);
};

const StyledPopoverHeaderLine = styled.div`
display: flex;
width: 268px;
justify-content: space-between;
align-items: center;
`;

const ButtContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
`;

export const StyledLoadingWrapper = styled.div`
display: flex;
align-items: center;
flex-direction: column;
gap: 1em;
width: 268px;
justify-content: center;
`;
Loading

0 comments on commit 19bea52

Please sign in to comment.