fix: colors and width issues- fixes #7079

fixes #7079
This commit is contained in:
Jonathan Summers-Muir committed 2022-05-31 18:13:19 +08:00
1 parent 7185112fdd
commit 9cfeb44b77
7 files changed
+180 -219

No files matched your search

@@ -34,9 +34,9 @@ export const ForeignKeyFormatter = (
return (
<div className="sb-grid-foreign-key-formatter flex justify-between">
<p className="sb-grid-foreign-key-formatter__text">
<span className="sb-grid-foreign-key-formatter__text">
{value === null ? <NullValue /> : value}
</p>
</span>
<ForeignTableModal columnName={p.column.key} defaultValue={value} onChange={onChange} />
</div>
)
@@ -134,7 +134,11 @@ export function ColumnHeader<R>({
function renderColumnIcon(type: ColumnType) {
switch (type) {
case 'foreign_key':
return <IconLink size="tiny" strokeWidth={2} />
return (
<div>
<IconLink size="tiny" strokeWidth={2} />
</div>
)
default:
return null
}
@@ -1,141 +1,128 @@
import * as React from 'react';
import { useDispatch, useTrackedState } from '../../store';
import {
Button,
Divider,
IconDownload,
IconPlus,
IconX,
IconTrash,
Typography,
} from '@supabase/ui';
import FileSaver from 'file-saver';
import FilterDropdown from './filter';
import SortPopover from './sort';
import StatusLabel from './StatusLabel';
import RefreshButton from './RefreshButton';
import { exportRowsToCsv } from '../../utils';
import { showConfirmAlert } from '../common';
import * as React from 'react'
import { useDispatch, useTrackedState } from '../../store'
import { Button, Divider, IconDownload, IconPlus, IconX, IconTrash, Typography } from '@supabase/ui'
import FileSaver from 'file-saver'
import FilterDropdown from './filter'
import SortPopover from './sort'
import StatusLabel from './StatusLabel'
import RefreshButton from './RefreshButton'
import { exportRowsToCsv } from '../../utils'
import { showConfirmAlert } from '../common'
type HeaderProps = {
onAddColumn?: () => void;
onAddRow?: () => void;
headerActions?: React.ReactNode;
};
onAddColumn?: () => void
onAddRow?: () => void
headerActions?: React.ReactNode
}
const Header: React.FC<HeaderProps> = ({
onAddColumn,
onAddRow,
headerActions,
}) => {
const state = useTrackedState();
const { selectedRows } = state;
const Header: React.FC<HeaderProps> = ({ onAddColumn, onAddRow, headerActions }) => {
const state = useTrackedState()
const { selectedRows } = state
return (
<div className="sb-grid-header">
<div className="sb-grid-header__inner">
{selectedRows.size > 0 ? (
<RowHeader />
) : (
<DefaultHeader onAddColumn={onAddColumn} onAddRow={onAddRow} />
)}
</div>
<div className="bg-scale-100 dark:bg-scale-300 flex h-10 justify-between px-5">
{selectedRows.size > 0 ? (
<RowHeader />
) : (
<DefaultHeader onAddColumn={onAddColumn} onAddRow={onAddRow} />
)}
<div className="sb-grid-header__inner">
{headerActions}
<StatusLabel />
</div>
</div>
);
};
export default Header;
)
}
export default Header
type DefaultHeaderProps = {
onAddColumn?: () => void;
onAddRow?: () => void;
};
const DefaultHeader: React.FC<DefaultHeaderProps> = ({
onAddColumn,
onAddRow,
}) => {
onAddColumn?: () => void
onAddRow?: () => void
}
const DefaultHeader: React.FC<DefaultHeaderProps> = ({ onAddColumn, onAddRow }) => {
const renderNewColumn = (onAddColumn?: () => void) => {
if (!onAddColumn) return null;
return (
<Button type="text" onClick={onAddColumn} style={{ padding: '4px 8px' }}>
New Column
</Button>
);
};
const renderAddRow = (onAddRow?: () => void) => {
if (!onAddRow) return null;
if (!onAddColumn) return null
return (
<Button
style={{ padding: '4px 8px' }}
icon={<IconPlus size="tiny" />}
type="text"
onClick={onAddColumn}
// style={{ padding: '4px 8px' }}
>
New Column
</Button>
)
}
const renderAddRow = (onAddRow?: () => void) => {
if (!onAddRow) return null
return (
<Button
size="tiny"
// style={{ padding: '4px 8px' }}
icon={<IconPlus size={14} strokeWidth={2} />}
onClick={onAddRow}
>
Insert row
</Button>
);
};
)
}
return (
<>
<RefreshButton />
<FilterDropdown />
<SortPopover />
<Divider
light
type="vertical"
className="sb-grid-header__inner__divider"
/>
{renderNewColumn(onAddColumn)}
{renderAddRow(onAddRow)}
</>
);
};
<div className="flex items-center gap-4">
<div className="flex items-center gap-1">
<RefreshButton />
<FilterDropdown />
<SortPopover />
</div>
<div className="bg-scale-600 h-[50%] w-px"></div>
<div className="flex items-center gap-2">
{renderNewColumn(onAddColumn)}
{renderAddRow(onAddRow)}
</div>
</div>
)
}
type RowHeaderProps = {};
type RowHeaderProps = {}
const RowHeader: React.FC<RowHeaderProps> = ({}) => {
const state = useTrackedState();
const dispatch = useDispatch();
const state = useTrackedState()
const dispatch = useDispatch()
const { selectedRows, rows: allRows, editable } = state;
const { selectedRows, rows: allRows, editable } = state
const onRowsDelete = () => {
showConfirmAlert({
title: 'Confirm to delete',
message:
'Are you sure you want to delete the selected rows? This action cannot be undone.',
message: 'Are you sure you want to delete the selected rows? This action cannot be undone.',
onConfirm: async () => {
const rowIdxs = Array.from(selectedRows) as number[];
const rows = allRows.filter((x) => rowIdxs.includes(x.idx));
const { error } = state.rowService!.delete(rows);
const rowIdxs = Array.from(selectedRows) as number[]
const rows = allRows.filter((x) => rowIdxs.includes(x.idx))
const { error } = state.rowService!.delete(rows)
if (error) {
if (state.onError) state.onError(error);
if (state.onError) state.onError(error)
} else {
dispatch({ type: 'REMOVE_ROWS', payload: { rowIdxs } });
dispatch({ type: 'REMOVE_ROWS', payload: { rowIdxs } })
dispatch({
type: 'SELECTED_ROWS_CHANGE',
payload: { selectedRows: new Set() },
});
})
}
},
});
};
})
}
function onRowsExportCsv() {
const rows = allRows.filter((x) => selectedRows.has(x.idx));
const csv = exportRowsToCsv(state.table!.columns, rows);
const csvData = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
FileSaver.saveAs(csvData, `${state.table!.name}_rows.csv`);
const rows = allRows.filter((x) => selectedRows.has(x.idx))
const csv = exportRowsToCsv(state.table!.columns, rows)
const csvData = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
FileSaver.saveAs(csvData, `${state.table!.name}_rows.csv`)
}
function deselectRows() {
dispatch({
type: 'SELECTED_ROWS_CHANGE',
payload: { selectedRows: new Set() },
});
})
}
return (
@@ -147,11 +134,7 @@ const RowHeader: React.FC<RowHeaderProps> = ({}) => {
onClick={deselectRows}
/>
<div>
<Typography.Text
small
type="secondary"
className="row_header__selected-rows"
>
<Typography.Text small type="secondary" className="row_header__selected-rows">
{selectedRows.size > 1
? `${selectedRows.size} rows selected`
: `${selectedRows.size} row selected`}
@@ -160,7 +143,8 @@ const RowHeader: React.FC<RowHeaderProps> = ({}) => {
<Button
type="primary"
size="tiny"
style={{ padding: '4px 8px' }}
// style={{ padding: '4px 8px' }}
icon={<IconDownload />}
onClick={onRowsExportCsv}
>
@@ -168,15 +152,12 @@ const RowHeader: React.FC<RowHeaderProps> = ({}) => {
</Button>
{editable && (
<>
<Divider
type="vertical"
className="sb-grid-header__inner__divider"
light
/>
<Divider type="vertical" className="sb-grid-header__inner__divider" light />
<Button
type="default"
size="tiny"
style={{ padding: '4px 8px' }}
// style={{ padding: '4px 8px' }}
icon={<IconTrash size="tiny" />}
onClick={onRowsDelete}
>
@@ -187,5 +168,5 @@ const RowHeader: React.FC<RowHeaderProps> = ({}) => {
</>
)}
</>
);
};
)
}
@@ -1,32 +1,36 @@
import * as React from 'react';
import { Button, IconRefreshCw } from '@supabase/ui';
import { useDispatch, useTrackedState } from '../../store';
import { fetchCount, fetchPage } from '../../utils';
import * as React from 'react'
import { Button, IconRefreshCw } from '@supabase/ui'
import { useDispatch, useTrackedState } from '../../store'
import { fetchCount, fetchPage } from '../../utils'
type RefreshButtonProps = {};
type RefreshButtonProps = {}
const RefreshButton: React.FC<RefreshButtonProps> = ({}) => {
const [loading, setLoading] = React.useState(false);
const state = useTrackedState();
const dispatch = useDispatch();
const [loading, setLoading] = React.useState(false)
const state = useTrackedState()
const dispatch = useDispatch()
async function onClick() {
setLoading(true);
await fetchCount(state, dispatch);
await fetchPage(state, dispatch);
setLoading(false);
setLoading(true)
await fetchCount(state, dispatch)
await fetchPage(state, dispatch)
setLoading(false)
}
return (
<Button
type="text"
style={{ padding: '4px 8px' }}
icon={<IconRefreshCw />}
// style={{ padding: '4px 8px' }}
icon={
<div className="text-scale-900">
<IconRefreshCw strokeWidth={1.5} />
</div>
}
onClick={onClick}
loading={loading}
>
Refresh
</Button>
);
};
export default RefreshButton;
)
}
export default RefreshButton
@@ -1,40 +1,37 @@
import React, { FC } from 'react';
import { Button, IconPlus, IconFilter, Popover } from '@supabase/ui';
import { useDispatch, useTrackedState } from '../../../store';
import FilterRow from './FilterRow';
import React, { FC } from 'react'
import { Button, IconPlus, IconFilter, Popover } from '@supabase/ui'
import { useDispatch, useTrackedState } from '../../../store'
import FilterRow from './FilterRow'
const FilterPopover: FC = () => {
const state = useTrackedState();
const state = useTrackedState()
const btnText =
state.filters.length > 0
? `Filtered by ${state.filters.length} rule${
state.filters.length > 1 ? 's' : ''
}`
: 'Filter';
? `Filtered by ${state.filters.length} rule${state.filters.length > 1 ? 's' : ''}`
: 'Filter'
return (
<Popover
size="large"
align="start"
className="sb-grid-filter-popover"
overlay={<Filter />}
>
<Popover size="large" align="start" className="sb-grid-filter-popover" overlay={<Filter />}>
<Button
as={'span'}
type="text"
icon={<IconFilter />}
style={{ padding: '4px 8px' }}
icon={
<div className="text-scale-900">
<IconFilter strokeWidth={1.5} />
</div>
}
// style={{ padding: '4px 8px' }}
>
{btnText}
</Button>
</Popover>
);
};
export default FilterPopover;
)
}
export default FilterPopover
const Filter: FC = () => {
const state = useTrackedState();
const dispatch = useDispatch();
const state = useTrackedState()
const dispatch = useDispatch()
function onAddFilter() {
dispatch({
@@ -44,27 +41,19 @@ const Filter: FC = () => {
operator: '=',
value: '',
},
});
})
}
return (
<div className="space-y-2 py-2">
<div className="space-y-2">
{state.filters.map((_, index) => (
<FilterRow
key={`filter-${index}`}
filterIdx={index}
now={Date.now()}
/>
<FilterRow key={`filter-${index}`} filterIdx={index} now={Date.now()} />
))}
{state.filters.length == 0 && (
<div className="space-y-1 px-3">
<h5 className="text-sm text-scale-1100">
No filters applied to this view
</h5>
<p className="text-xs text-scale-900">
Add a column below to filter the view
</p>
<h5 className="text-scale-1100 text-sm">No filters applied to this view</h5>
<p className="text-scale-900 text-xs">Add a column below to filter the view</p>
</div>
)}
</div>
@@ -75,5 +64,5 @@ const Filter: FC = () => {
</Button>
</div>
</div>
);
};
)
}
@@ -1,70 +1,63 @@
import React, { FC } from 'react';
import { Button, IconList, IconChevronDown, Popover } from '@supabase/ui';
import { DropdownControl } from '../../common';
import { useDispatch, useTrackedState } from '../../../store';
import SortRow from './SortRow';
import React, { FC } from 'react'
import { Button, IconList, IconChevronDown, Popover } from '@supabase/ui'
import { DropdownControl } from '../../common'
import { useDispatch, useTrackedState } from '../../../store'
import SortRow from './SortRow'
const SortPopover: FC = () => {
const state = useTrackedState();
const state = useTrackedState()
const btnText =
state.sorts.length > 0
? `Sorted by ${state.sorts.length} rule${
state.sorts.length > 1 ? 's' : ''
}`
: 'Sort';
? `Sorted by ${state.sorts.length} rule${state.sorts.length > 1 ? 's' : ''}`
: 'Sort'
return (
<Popover
size="large"
align="start"
className="sb-grid-sort-popover"
overlay={<Sort />}
>
<Popover size="large" align="start" className="sb-grid-sort-popover" overlay={<Sort />}>
<Button
as={'span'}
type="text"
icon={<IconList />}
style={{ padding: '4px 8px' }}
icon={
<div className="text-scale-900">
<IconList strokeWidth={1.5} />
</div>
}
// style={{ padding: '4px 8px' }}
>
{btnText}
</Button>
</Popover>
);
};
export default SortPopover;
)
}
export default SortPopover
const Sort: FC = () => {
const state = useTrackedState();
const dispatch = useDispatch();
const state = useTrackedState()
const dispatch = useDispatch()
const columns = state?.table?.columns!.filter((x) => {
const found = state.sorts.find((y) => y.column == x.name);
return !found;
});
const found = state.sorts.find((y) => y.column == x.name)
return !found
})
const dropdownOptions =
columns?.map((x) => {
return { value: x.name, label: x.name };
}) || [];
return { value: x.name, label: x.name }
}) || []
function onAddSort(columnName: string | number) {
dispatch({
type: 'ADD_SORT',
payload: { column: columnName, ascending: true },
});
})
}
return (
<div className="py-2 space-y-2">
<div className="space-y-2 py-2">
{state.sorts.map((x, index) => (
<SortRow key={x.column} columnName={x.column} index={index} />
))}
{state.sorts.length == 0 && (
<div className="space-y-1 px-3">
<h5 className="text-sm text-scale-1100">
No sorts applied to this view
</h5>
<p className="text-xs text-scale-900">
Add a column below to sort the view
</p>
<h5 className="text-scale-1100 text-sm">No sorts applied to this view</h5>
<p className="text-scale-900 text-xs">Add a column below to sort the view</p>
</div>
)}
@@ -83,15 +76,13 @@ const Sort: FC = () => {
iconRight={<IconChevronDown />}
className="sb-grid-dropdown__item-trigger"
>
{`Pick ${
state.sorts.length > 1 ? 'another' : 'a'
} column to sort by`}
{`Pick ${state.sorts.length > 1 ? 'another' : 'a'} column to sort by`}
</Button>
</DropdownControl>
) : (
<p className="text-sm text-scale-1100">All columns have been added</p>
<p className="text-scale-1100 text-sm">All columns have been added</p>
)}
</div>
</div>
);
};
)
}
+5 -13
View File
@@ -10,7 +10,7 @@
.rdg-cell {
@apply flex;
@apply border-scale-400 dark:border-scale-500 border-r border-b text-sm;
@apply text-typography-body-light dark:text-typography-body-dark;
@apply text-scale-1200;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -129,12 +129,6 @@
@apply hover:bg-bg-secondary-light dark:hover:bg-bg-secondary-dark;
}
.rdg-row .rdg-cell span,
/* .rdg-row .rdg-cell svg, */
.rdg-row .rdg-cell div {
@apply text-typography-body-light dark:text-typography-body-dark;
}
.tab-cursor {
cursor: pointer !important;
}
@@ -466,18 +460,17 @@
}
.sb-grid-column-header__inner {
@apply flex items-center space-x-2 overflow-hidden overflow-ellipsis;
@apply flex items-center gap-2 overflow-hidden overflow-ellipsis;
}
.sb-grid-column-header__inner__name {
@apply overflow-hidden overflow-ellipsis text-sm;
@apply text-typography-body-light dark:text-typography-body-dark;
@apply text-scale-1200 overflow-hidden overflow-ellipsis text-xs;
}
.sb-grid-column-header__inner__format {
@apply text-xs;
@apply overflow-hidden overflow-ellipsis font-normal;
@apply text-typography-body-secondary-light dark:text-typography-body-secondary-dark;
@apply text-scale-1000;
}
.sb-grid-column-header__inner__primary-key {
@@ -485,8 +478,7 @@
}
.sb-grid-column-header__inner svg {
@apply mr-1;
@apply border-green-900 text-green-900 dark:border-green-900 dark:text-green-900;
@apply border-brand-900 text-brand-900 dark:border-brand-900 dark:text-brand-900;
}
/*