-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #739 from silx-kit/matrix-csv-export
Implement CSV export for Matrix vis
- Loading branch information
Showing
15 changed files
with
220 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { FiDownload } from 'react-icons/fi'; | ||
import { useMatrixConfig } from '../vis-packs/core/matrix/config'; | ||
import { sliceToCsv } from '../vis-packs/core/matrix/utils'; | ||
import DownloadBtn from './controls/DownloadBtn'; | ||
import Toolbar from './Toolbar'; | ||
|
||
function MatrixToolbar() { | ||
const currentSlice = useMatrixConfig((state) => state.currentSlice); | ||
if (currentSlice && currentSlice.shape.length > 2) { | ||
throw new Error('Expected current slice to have at most two dimensions'); | ||
} | ||
|
||
return ( | ||
<Toolbar> | ||
{currentSlice && ( | ||
<DownloadBtn | ||
icon={FiDownload} | ||
label="CSV" | ||
filename="export.csv" | ||
getDownloadUrl={() => { | ||
const data = sliceToCsv(currentSlice); | ||
return URL.createObjectURL( | ||
new Blob([data], { type: 'text/csv;charset=utf-8' }) | ||
); | ||
}} | ||
/> | ||
)} | ||
</Toolbar> | ||
); | ||
} | ||
|
||
export default MatrixToolbar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import type { AriaAttributes } from 'react'; | ||
import type { IconType } from 'react-icons'; | ||
import styles from '../Toolbar.module.css'; | ||
|
||
interface Props extends AriaAttributes { | ||
label: string; | ||
icon?: IconType; | ||
iconOnly?: boolean; | ||
small?: boolean; | ||
raised?: boolean; | ||
onClick: () => void; | ||
disabled?: boolean; | ||
} | ||
|
||
function Btn(props: Props) { | ||
const { | ||
label, | ||
icon: Icon, | ||
iconOnly, | ||
small, | ||
raised, | ||
disabled, | ||
onClick, | ||
...ariaAttrs | ||
} = props; | ||
|
||
return ( | ||
<button | ||
className={styles.btn} | ||
type="button" | ||
onClick={() => onClick()} | ||
disabled={disabled} | ||
data-small={small || undefined} | ||
data-raised={raised || undefined} | ||
aria-label={iconOnly ? label : undefined} | ||
{...ariaAttrs} | ||
> | ||
<span className={styles.btnLike}> | ||
{Icon && <Icon className={styles.icon} />} | ||
{!iconOnly && <span className={styles.label}>{label}</span>} | ||
</span> | ||
</button> | ||
); | ||
} | ||
|
||
export type { Props as BtnProps }; | ||
export default Btn; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import type { AriaAttributes } from 'react'; | ||
import type { IconType } from 'react-icons/lib'; | ||
import styles from '../Toolbar.module.css'; | ||
|
||
interface Props extends AriaAttributes { | ||
label: string; | ||
icon?: IconType; | ||
iconOnly?: boolean; | ||
// If specified, browser will prompt user to download the file instead of opening a new tab | ||
filename?: string; | ||
// Invoked on click; must return URL to set as `href`, or `false` to do nothing | ||
getDownloadUrl: () => string | false; | ||
} | ||
|
||
function DownloadBtn(props: Props) { | ||
const { | ||
label, | ||
icon: Icon, | ||
iconOnly, | ||
filename, | ||
getDownloadUrl, | ||
...ariaAttrs | ||
} = props; | ||
|
||
return ( | ||
<a | ||
className={styles.btn} | ||
href="/" // placeholder replaced dynamically on click | ||
target="_blank" | ||
download={filename} | ||
aria-label={iconOnly ? label : undefined} | ||
{...ariaAttrs} | ||
onClick={(evt) => { | ||
const url = getDownloadUrl(); | ||
|
||
if (url === false) { | ||
evt.preventDefault(); | ||
return; | ||
} | ||
|
||
evt.currentTarget.setAttribute('href', url); | ||
}} | ||
> | ||
<span className={styles.btnLike}> | ||
{Icon && <Icon className={styles.icon} />} | ||
{!iconOnly && <span className={styles.label}>{label}</span>} | ||
</span> | ||
</a> | ||
); | ||
} | ||
|
||
export default DownloadBtn; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,13 @@ | ||
import type { AriaAttributes } from 'react'; | ||
import type { IconType } from 'react-icons'; | ||
import styles from '../Toolbar.module.css'; | ||
import Btn, { BtnProps } from './Btn'; | ||
|
||
interface Props extends AriaAttributes { | ||
label: string; | ||
icon?: IconType; | ||
iconOnly?: boolean; | ||
small?: boolean; | ||
raised?: boolean; | ||
interface Props extends Omit<BtnProps, 'onClick'> { | ||
value: boolean; | ||
onToggle: () => void; | ||
disabled?: boolean; | ||
} | ||
|
||
function ToggleBtn(props: Props) { | ||
const { | ||
label, | ||
icon: Icon, | ||
iconOnly, | ||
small, | ||
raised, | ||
value, | ||
onToggle, | ||
disabled, | ||
...ariaAttrs | ||
} = props; | ||
|
||
return ( | ||
<button | ||
className={styles.btn} | ||
type="button" | ||
onClick={() => onToggle()} | ||
disabled={disabled} | ||
data-small={small || undefined} | ||
data-raised={raised || undefined} | ||
aria-label={iconOnly ? label : undefined} | ||
aria-pressed={value} | ||
{...ariaAttrs} | ||
> | ||
<span className={styles.btnLike}> | ||
{Icon && <Icon className={styles.icon} />} | ||
{!iconOnly && <span className={styles.label}>{label}</span>} | ||
</span> | ||
</button> | ||
); | ||
const { value, onToggle, ...btnProps } = props; | ||
return <Btn {...btnProps} aria-pressed={value} onClick={() => onToggle()} />; | ||
} | ||
|
||
export default ToggleBtn; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { NdArray } from 'ndarray'; | ||
import create from 'zustand'; | ||
import createContext from 'zustand/context'; | ||
import type { Primitive } from '../../../providers/models'; | ||
import type { ConfigProviderProps } from '../../models'; | ||
import type { PrintableType } from '../models'; | ||
|
||
interface MatrixConfig { | ||
currentSlice: NdArray<Primitive<PrintableType>> | undefined; | ||
setCurrentSlice: (slice: NdArray<Primitive<PrintableType>>) => void; | ||
} | ||
|
||
function createStore() { | ||
return create<MatrixConfig>((set) => ({ | ||
currentSlice: undefined, | ||
setCurrentSlice: (slice) => set({ currentSlice: slice }), | ||
})); | ||
} | ||
|
||
const { Provider, useStore } = createContext<MatrixConfig>(); | ||
export const useMatrixConfig = useStore; | ||
|
||
export function MatrixConfigProvider(props: ConfigProviderProps) { | ||
const { children } = props; | ||
return <Provider createStore={createStore}>{children}</Provider>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.