> = ({
className="Firestore-Request-Details-Header-Return-Button"
icon={{ icon: 'arrow_back_ios', size: 'small' }}
tag={Link}
- to="/firestore/requests"
+ to={backLocation}
label="header-return-button"
/>
diff --git a/src/components/Firestore/Requests/RequestDetails/index.tsx b/src/components/Firestore/Requests/RequestDetails/index.tsx
index 07cb6979b..e2f17fa6d 100644
--- a/src/components/Firestore/Requests/RequestDetails/index.tsx
+++ b/src/components/Firestore/Requests/RequestDetails/index.tsx
@@ -105,10 +105,7 @@ export function getDetailsRequestData(
hour12: false,
}),
requestMethod: rulesContext.method,
- resourcePath: rulesContext.path.replace(
- '/databases/(default)/documents',
- ''
- ),
+ resourcePath: rulesContext.path,
outcome,
outcomeData: OUTCOME_DATA[outcome],
firestoreRules: rules,
@@ -141,7 +138,6 @@ export const RequestDetails: React.FC
> = ({
linesOutcome,
inspectionExpressions,
} = getDetailsRequestData(selectedRequest);
-
// Redirect to requests-table if (requestId) did not match any existing request
if (requestId && !selectedRequest) {
return ;
diff --git a/src/components/Firestore/Requests/RequestsCard/Table/TableRow.tsx b/src/components/Firestore/Requests/RequestsCard/Table/TableRow.tsx
index 56c5d10f7..1655fd782 100644
--- a/src/components/Firestore/Requests/RequestsCard/Table/TableRow.tsx
+++ b/src/components/Firestore/Requests/RequestsCard/Table/TableRow.tsx
@@ -20,7 +20,7 @@ import { DataTableCell, DataTableRow } from '@rmwc/data-table';
import { Icon } from '@rmwc/icon';
import { Tooltip } from '@rmwc/tooltip';
import React from 'react';
-import { useHistory } from 'react-router-dom';
+import { useHistory, useLocation } from 'react-router-dom';
import { CustomThemeProvider } from '../../../../../themes';
import RequestPath from '../../RequestPath';
@@ -47,10 +47,7 @@ function getTableRowRequestData(
hour12: false,
}),
requestMethod: rulesContext.method,
- resourcePath: rulesContext.path.replace(
- '/databases/(default)/documents',
- ''
- ),
+ resourcePath: rulesContext.path,
outcomeData: OUTCOME_DATA[outcome],
};
}
@@ -69,6 +66,7 @@ const RequestTableRow: React.FC> = ({
requestPathContainerWidth,
}) => {
const history = useHistory();
+ const location = useLocation();
const {
requestTimeComplete,
requestTimeFormatted,
@@ -76,10 +74,10 @@ const RequestTableRow: React.FC> = ({
resourcePath,
outcomeData,
} = getTableRowRequestData(request);
-
return (
history.push(`/firestore/requests/${requestId}`)}
+ // location.pathname is expected to be firestore/:databaseId/requests
+ onClick={() => history.push(`${location.pathname}/${requestId}`)}
>
{
it('renders appropriate number of rows when there are requests', () => {
const { getAllByRole, queryByText } = render(
-
+
+
+
);
// Header + 2 requests
expect(getAllByRole('row').length).toBe(3);
diff --git a/src/components/Firestore/Requests/RequestsCard/Table/index.tsx b/src/components/Firestore/Requests/RequestsCard/Table/index.tsx
index 4936d8fcf..e5e9e4a89 100644
--- a/src/components/Firestore/Requests/RequestsCard/Table/index.tsx
+++ b/src/components/Firestore/Requests/RequestsCard/Table/index.tsx
@@ -28,6 +28,7 @@ import classnames from 'classnames';
import React, { useRef } from 'react';
import { Callout } from '../../../../common/Callout';
+import { useDatabaseId } from '../../../FirestoreEmulatedApiProvider';
import { useFirestoreRequests } from '../../FirestoreRequestsProvider';
import { FirestoreRulesEvaluation } from '../../rules_evaluation_result_model';
import { usePathContainerWidth } from '../../utils';
@@ -131,7 +132,8 @@ export const RequestsTableWrapper: React.FC<
setShowCopyNotification: (show: boolean) => void;
}>
> = ({ setShowCopyNotification }) => {
- const evaluations = useFirestoreRequests().requests;
+ const databaseId = useDatabaseId();
+ const evaluations = useFirestoreRequests(databaseId).requests;
// TODO: Add support for filtering.
const filteredEvaluations = evaluations;
diff --git a/src/components/Firestore/Requests/index.test.tsx b/src/components/Firestore/Requests/index.test.tsx
index 6ff88a181..0aceab863 100644
--- a/src/components/Firestore/Requests/index.test.tsx
+++ b/src/components/Firestore/Requests/index.test.tsx
@@ -45,7 +45,7 @@ describe('Firestore Requests', () => {
const { getByTestId } = render(
-
+
@@ -62,7 +62,9 @@ describe('Firestore Requests', () => {
@@ -78,7 +80,9 @@ describe('Firestore Requests', () => {
diff --git a/src/components/Firestore/Requests/index.tsx b/src/components/Firestore/Requests/index.tsx
index d721dd4f2..7d8bd292c 100644
--- a/src/components/Firestore/Requests/index.tsx
+++ b/src/components/Firestore/Requests/index.tsx
@@ -37,7 +37,6 @@ const Requests: React.FC> = () => {
if (!isRequestsAvailable) {
return ;
}
-
return (
<>
> = () => {
style={{ flex: 1 }}
>
-
+
{/* TODO: Finish developing the RequestsHeader in order to render it */}
{/*
*/}
@@ -58,7 +57,7 @@ const Requests: React.FC
> = () => {
) => {
@@ -71,7 +70,8 @@ const Requests: React.FC> = () => {
);
}}
/>
-
+ {/** If no paths match, return to the request list */}
+
{
});
describe('Firestore sub-tabs navigation', () => {
- it('selects the Data tab when /firestore/data', async () => {
+ it('selects the Data tab when /firestore/default/data', async () => {
const { getByText } = await renderWithFirestore(async () => , {
- path: '/firestore/data',
+ path: '/firestore/default/data',
});
await act(() => delay(600)); // Wait for tab indicator async DOM updates.
@@ -73,9 +74,9 @@ describe('Firestore sub-tabs navigation', () => {
expect(isTabActive(getByText('Requests'))).toBe(false);
});
- it('selects the Requests tab when /firestore/requests', async () => {
+ it('selects the Requests tab when /firestore/default/requests', async () => {
const { getByText } = await renderWithFirestore(async () => , {
- path: '/firestore/requests',
+ path: '/firestore/default/requests',
});
await act(() => delay(300)); // Wait for tab indicator async DOM updates.
@@ -84,9 +85,9 @@ describe('Firestore sub-tabs navigation', () => {
expect(isTabActive(getByText('Requests'))).toBe(true);
});
- it('selects the Requests tab when /firestore/requests/:id', async () => {
+ it('selects the Requests tab when /firestore/default/requests/:id', async () => {
const { getByText } = await renderWithFirestore(async () => , {
- path: '/firestore/requests/uniqueRequestId',
+ path: '/firestore/default/requests/uniqueRequestId',
});
await act(() => delay(300)); // Wait for tab indicator async DOM updates.
@@ -95,7 +96,7 @@ describe('Firestore sub-tabs navigation', () => {
expect(isTabActive(getByText('Requests'))).toBe(true);
});
- it('Redirects to /firestore/data and selects the Data tab when /firestore', async () => {
+ it('Redirects to /firestore/default/data and selects the Data tab when /firestore', async () => {
const { getByText } = await renderWithFirestore(async () => , {
path: '/firestore',
});
@@ -119,7 +120,7 @@ describe('Firestore sub-tabs navigation', () => {
return ;
},
- { path: '/firestore/data' }
+ { path: '/firestore/default/data' }
);
await findByTestId('collection-list');
@@ -133,7 +134,7 @@ describe('Firestore sub-tabs navigation', () => {
const { getByTestId, findByTestId } = await renderWithFirestore(
async () => ,
{
- path: '/firestore/data',
+ path: '/firestore/default/data',
}
);
@@ -145,7 +146,7 @@ describe('Firestore sub-tabs navigation', () => {
const { findByTestId, queryByTestId } = await renderWithFirestore(
async () => ,
{
- path: '/firestore/data/coll',
+ path: '/firestore/default/data/coll',
}
);
@@ -161,7 +162,7 @@ describe('Firestore sub-tabs navigation', () => {
return ;
},
{
- path: '/firestore/data/coll/doc',
+ path: '/firestore/default/data/coll/doc',
}
);
@@ -182,17 +183,16 @@ describe('Firestore sub-tabs navigation', () => {
const { getByTestId, getByText, queryByTestId } =
await renderWithFirestore(
async () => (
- <>
+
}
/>
- >
+
),
{
- path: '/firestore/data',
+ path: '/firestore/default/data',
}
);
act(() => getByText('Clear all data').click());
@@ -213,7 +213,7 @@ describe('Firestore sub-tabs navigation', () => {
const { getByText } = await renderWithFirestore(
async () => ,
{
- path: '/firestore/data',
+ path: '/firestore/default/data',
}
);
act(() => getByText('Clear all data').click());
diff --git a/src/components/Firestore/index.tsx b/src/components/Firestore/index.tsx
index 6d3eb2b1b..16d86be34 100644
--- a/src/components/Firestore/index.tsx
+++ b/src/components/Firestore/index.tsx
@@ -69,28 +69,34 @@ interface FirestoreTabRoute {
label: string;
exact: boolean;
}
-const firestoreRoutes: ReadonlyArray = [
- {
- path: '/firestore/data',
- label: 'Data',
- exact: false,
- },
- {
- path: '/firestore/requests',
- label: 'Requests',
- exact: false,
- },
-];
export const Firestore: React.FC> = React.memo(
() => {
const location = useLocation();
+ // Location is expected to be firestore/:databaseId/data or /requests/:requestId
+ const databaseId = location.pathname.split('/')[2];
const history = useHistory();
const [isRefreshing, setIsRefreshing] = useState(false);
const eject = useEjector();
-
+ const firestoreRoutes: ReadonlyArray = [
+ {
+ path: `/firestore/${databaseId}/data`,
+ label: 'Data',
+ exact: false,
+ },
+ {
+ path: `/firestore/${databaseId}/requests`,
+ label: 'Requests',
+ exact: false,
+ },
+ ];
// TODO: do something better here!
- const path = location.pathname.replace(/^\/firestore\/data/, '');
+ // Regex based (roughly) on valid DB IDs here:
+ // https://firebase.google.com/docs/firestore/manage-databases#database_id
+ const path = location.pathname.replace(
+ /^\/firestore\/[a-zA-Z0-9-]{1,63}\/data/,
+ ''
+ );
const showCollectionShell = path.split('/').length < 2;
const showDocumentShell = path.split('/').length < 3;
@@ -117,13 +123,13 @@ export const Firestore: React.FC> = React.memo(
if (!shouldNuke) return;
setIsRefreshing(true);
await eject();
- handleNavigate();
+ handleNavigate(databaseId);
setIsRefreshing(false);
}
- function handleNavigate(path?: string) {
+ function handleNavigate(path?: string, databaseId: string = 'default') {
// TODO: move to routing constants
- const root = '/firestore/data';
+ const root = `/firestore/${databaseId}/data`;
if (path === undefined) {
history.push(root);
} else {
@@ -152,8 +158,8 @@ export const Firestore: React.FC> = React.memo(
}
>
- The Emulator Suite UI only supports the (default) database right
- now.
+ The Emulator Suite UI supports multiple DBs by editing the database
+ name in the URL.
@@ -164,19 +170,30 @@ export const Firestore: React.FC> = React.memo(