-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathDatabaseContainer.tsx
More file actions
127 lines (116 loc) · 3.72 KB
/
DatabaseContainer.tsx
File metadata and controls
127 lines (116 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Button } from '@rmwc/button';
import { Card } from '@rmwc/card';
import { Elevation } from '@rmwc/elevation';
import { GridCell } from '@rmwc/grid';
import React, { useState } from 'react';
import useSwr from 'swr';
import { DatabaseConfig } from '../../store/config';
import { Callout } from '../common/Callout';
import { useEmulatorConfig } from '../common/EmulatorConfigProvider';
import { fetchMaybeWithCredentials } from '../common/rest_api';
import DatabasePicker from './DatabasePicker';
export type Props = {
children?: React.ReactNode;
databases: string[] | undefined;
primary: string;
navigation: (db: string) => string;
};
export const DatabaseContainer: React.FC<React.PropsWithChildren<Props>> = ({
primary,
navigation,
databases,
children,
}) => {
const [dbs, setDbs] = useState(databases);
let hasNewDbs = false;
if (databases !== dbs) {
if (
dbs === undefined ||
databases === undefined ||
dbs.join('|') === databases.join('|') // databases are sorted
) {
// Don't show reload button for initial data or unchanged.
setDbs(databases);
} else {
hasNewDbs = true;
}
}
return (
<>
<GridCell span={12} className="Database-Container">
{hasNewDbs && (
<Callout
type="note"
actions={
<Button theme="secondary" onClick={() => setDbs(databases)}>
Reload
</Button>
}
>
There are new databases that have been created. Reload the page to
view them.
</Callout>
)}
<Elevation z={2} wrap>
<Card className="canvas-card">
<div className="Database">
<DatabasePicker
primary={primary}
navigation={navigation}
databases={dbs}
/>
{children}
</div>
</Card>
</Elevation>
</GridCell>
</>
);
};
export const DatabaseContainerWrapper: React.FC<
React.PropsWithChildren<Omit<Props, 'databases'>>
> = (props) => {
const config = useEmulatorConfig('database');
const { data } = useSwr(
// Put config object in cache key (compared shallowly) so databases will
// be cleared on emulator restart as expected (even if ports don't change).
['/dummy/database/databases', config, props.primary],
fetchDatabases,
{ refreshWhenOffline: true, fallbackData: undefined, refreshInterval: 5000 }
);
return <DatabaseContainer databases={data} {...props} />;
};
export interface DatabaseInfo {
name: string;
}
async function fetchDatabases(
_: string, // dummy path parameter, unused for actual fetching
config: DatabaseConfig,
primary: string
): Promise<string[]> {
const res = await fetchMaybeWithCredentials(
`//${config.hostAndPort}/.inspect/databases.json?ns=${primary}`
);
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const databaseInfos: DatabaseInfo[] = await res.json();
// Sort databases by name to avoid unnecessary "changes".
return databaseInfos.map((db) => db.name).sort();
}
export default DatabaseContainerWrapper;