Skip to content

Commit 6972419

Browse files
committed
2 parents 00b27e5 + ba028b8 commit 6972419

File tree

6 files changed

+174
-12
lines changed

6 files changed

+174
-12
lines changed

packages/semantic-ui/src/components/DataTableColumnSelector.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ const useColumnSelector = (WrappedComponent: ComponentType<any>) => (
4343
};
4444
}
4545

46+
/**
47+
* Reset the columns on the state when the props change.
48+
*
49+
* @param prevProps
50+
*/
51+
componentDidUpdate(prevProps: Props): * {
52+
if (prevProps.columns !== this.props.columns) {
53+
this.setState({ columns: this.props.columns });
54+
}
55+
}
56+
4657
/**
4758
* Toggles the hidden property for the passed column.
4859
*
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// @flow
2+
3+
import React, {
4+
useCallback,
5+
useEffect,
6+
useMemo,
7+
useRef,
8+
useState
9+
} from 'react';
10+
import axios from 'axios';
11+
import _ from 'underscore';
12+
import ListTable from './ListTable';
13+
import MenuSidebar from './MenuSidebar';
14+
15+
type Props = {
16+
columnCount?: number,
17+
title: string,
18+
url: string
19+
};
20+
21+
const DatabaseView = (props: Props) => {
22+
const [columns, setColumns] = useState([]);
23+
const [selectedTable, setSelectedTable] = useState();
24+
const [tables, setTables] = useState([]);
25+
26+
const menuRef = useRef();
27+
28+
const service = useMemo(() => ({
29+
getColumns: (params) => axios.get(`${props.url}/api/columns`, { params }),
30+
getData: (params) => axios.post(`${props.url}/api/search`, params),
31+
getTables: () => axios.get(`${props.url}/api/tables`)
32+
}), [props.url]);
33+
34+
const resolveValue = useCallback((column, item) => {
35+
let value = item[column.column_name];
36+
37+
const { data_type: dataType } = column;
38+
39+
if (value) {
40+
switch (dataType) {
41+
case 'timestamp without time zone':
42+
value = new Date(value).toLocaleDateString();
43+
break;
44+
45+
default:
46+
// Value is already set
47+
}
48+
}
49+
50+
return value;
51+
}, []);
52+
53+
useEffect(() => {
54+
if (service) {
55+
service
56+
.getTables()
57+
.then(({ data }) => {
58+
setTables(data);
59+
setSelectedTable(_.first(data));
60+
});
61+
}
62+
}, [service]);
63+
64+
useEffect(() => {
65+
if (selectedTable) {
66+
service
67+
.getColumns({ table_name: selectedTable.table_name })
68+
.then(({ data }) => setColumns(data));
69+
}
70+
}, [selectedTable, service]);
71+
72+
const test = useMemo(() => _.map(columns, (column, index) => ({
73+
name: column.column_name,
74+
label: column.column_name,
75+
resolve: resolveValue.bind(this, column),
76+
sortable: true,
77+
hidden: index > props.columnCount
78+
})), [columns, resolveValue, props.columnCount]);
79+
80+
return (
81+
<div
82+
className='database-view'
83+
>
84+
<MenuSidebar
85+
contextRef={menuRef}
86+
header={{
87+
content: props.title,
88+
inverted: true
89+
}}
90+
inverted
91+
items={[{
92+
items: _.map(tables, (table) => ({
93+
active: selectedTable === table,
94+
content: table.table_name,
95+
onClick: () => setSelectedTable(table)
96+
}))
97+
}]}
98+
style={{
99+
overflow: 'auto',
100+
width: '250px'
101+
}}
102+
/>
103+
<div
104+
style={{
105+
marginLeft: '250px'
106+
}}
107+
>
108+
{ selectedTable && (
109+
<ListTable
110+
collectionName='items'
111+
columns={test}
112+
onLoad={(params) => service.getData({ ...params, table_name: selectedTable.table_name })}
113+
perPageOptions={[10, 25, 50, 100]}
114+
searchable
115+
/>
116+
)}
117+
</div>
118+
</div>
119+
);
120+
};
121+
122+
DatabaseView.defaultProps = {
123+
columnCount: Number.MAX_SAFE_INTEGER
124+
};
125+
126+
export default DatabaseView;

packages/semantic-ui/src/components/ListTable.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import type { Column } from './DataTable';
1010

1111
type Props = {
1212
columns: Array<Column>,
13+
defaultSort?: string,
14+
defaultSortDirection?: string,
1315
page: number,
1416
onSort: (sortColumn: string, sortDirection: string, page?: number) => void,
1517
onInit: (page?: number) => void,
@@ -49,20 +51,21 @@ const ListTable = (props: Props) => {
4951
* sortable column.
5052
*/
5153
useEffect(() => {
52-
const { page, sortColumn, sortDirection = SORT_ASCENDING } = props;
54+
const { page, defaultSort, defaultSortDirection = SORT_ASCENDING } = props;
5355

54-
if (props.sortColumn) {
55-
props.onSort(sortColumn, sortDirection, page);
56+
if (defaultSort) {
57+
props.onSort(defaultSort, defaultSortDirection, page);
5658
} else {
5759
const sortableColumn = _.findWhere(props.columns, { sortable: true });
60+
5861
if (sortableColumn) {
5962
onColumnClick(sortableColumn);
6063
} else {
6164
// If no columns are sortable, load the data as is
6265
props.onInit();
6366
}
6467
}
65-
}, []);
68+
}, [props.columns]);
6669

6770
return (
6871
<DataTable

packages/semantic-ui/src/components/LoginModal.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,15 @@ const LoginModal = (props: Props) => (
8787
>
8888
{ i18n.t('LoginModal.buttonLogin') }
8989
</Button>
90-
<Button
91-
basic
92-
onClick={props.onClose.bind(this)}
93-
size='large'
94-
>
95-
{ i18n.t('LoginModal.buttonCancel') }
96-
</Button>
90+
{ props.onClose && (
91+
<Button
92+
basic
93+
onClick={props.onClose.bind(this)}
94+
size='large'
95+
>
96+
{ i18n.t('LoginModal.buttonCancel') }
97+
</Button>
98+
)}
9799
</Modal.Actions>
98100
</Modal>
99101
)}

packages/shared/src/services/BaseService.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @flow
22

3-
import axios, { type AxiosResponse } from 'axios';
3+
import axios, { type AxiosResponse, type AxiosStatic } from 'axios';
44

55
/**
66
* Base class for making API calls. This class uses Axios under the hood and a customizable transform class for
@@ -102,6 +102,15 @@ class BaseService {
102102

103103
// protected
104104

105+
/**
106+
* Returns the axios instance.
107+
*
108+
* @returns {AxiosStatic}
109+
*/
110+
getAxios(): AxiosStatic {
111+
return axios;
112+
}
113+
105114
/**
106115
* Returns the API base URL string.
107116
*/

packages/storybook/src/semantic-ui/LoginModal.stories.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,14 @@ export const Default = () => (
2222
open={boolean('Open', true)}
2323
/>
2424
);
25+
26+
export const NoCloseButton = () => (
27+
<LoginModal
28+
disabled={boolean('Disabled', false)}
29+
loginFailed={boolean('Login failed', false)}
30+
onLogin={action('login')}
31+
onPasswordChange={action('password-change')}
32+
onUsernameChange={action('username-change')}
33+
open={boolean('Open', true)}
34+
/>
35+
);

0 commit comments

Comments
 (0)