/********************************************************************************
* Copyright (c) 2020 TypeFox and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import { FunctionComponent, useState, useContext, useEffect, ReactNode } from 'react';
import { Typography, Box, Button } from '@mui/material';
import { useParams, useNavigate } from 'react-router';
import { NamespaceDetailView, NamespaceDetailConfigContext } from '../../components/namespace/namespace-detail-view';
import { ButtonWithProgress } from '../../components/button-with-progress';
import { MainContext } from '../../context';
import { StyledInput } from './namespace-input';
import { SearchListContainer } from './search-list-container';
import { AdminDashboardRoutes } from './admin-dashboard-routes';
import { NamespaceChangeDialog } from './namespace-change-dialog';
import { NamespaceDeleteDialog } from './namespace-delete-dialog';
import { useAdminNamespace, useClearAdminNamespace, useCreateNamespace } from './use-namespace-admin';
export const NamespaceAdmin: FunctionComponent = () => {
const { service, pageSettings, user, handleError } = useContext(MainContext);
const { namespace: nsParam } = useParams<{ namespace?: string }>();
const navigate = useNavigate();
const [searchName, setSearchName] = useState(nsParam ?? '');
const [inputValue, setInputValue] = useState(nsParam ?? '');
// The namespace detail view can drive the loading indicator while it performs its own work.
const [detailLoading, setDetailLoading] = useState(false);
const [changeDialogIsOpen, setChangeDialogIsOpen] = useState(false);
const [deleteDialogIsOpen, setDeleteDialogIsOpen] = useState(false);
const { data: currentNamespace, isFetching, error, refetch } = useAdminNamespace(searchName);
const { mutateAsync: createNamespace, isPending: isCreatingNamespace } = useCreateNamespace();
const clearNamespace = useClearAdminNamespace();
const is404 = !!error && (error as { status?: number }).status === 404;
const notFound = is404 ? searchName : '';
// Non-404 lookup failures keep flowing through the global error dialog.
useEffect(() => {
if (error && !is404) {
handleError(error);
}
}, [error, is404, handleError]);
// Keep the URL in sync with the searched namespace so the view is deep-linkable.
useEffect(() => {
const target = searchName
? `${AdminDashboardRoutes.NAMESPACE_ADMIN}/${encodeURIComponent(searchName)}`
: AdminDashboardRoutes.NAMESPACE_ADMIN;
navigate(target, { replace: true });
}, [searchName, navigate]);
const fetchNamespace = (namespaceName: string) => {
if (namespaceName && namespaceName === searchName) {
// Re-submitting the same name should force a fresh lookup.
refetch();
} else {
setSearchName(namespaceName);
}
};
const onChangeInput = (name: string) => {
setInputValue(name);
};
const handleDeleteNamespace = () => {
clearNamespace(searchName);
setSearchName('');
};
const onCreate = async () => {
try {
await createNamespace(inputValue);
setSearchName(inputValue);
} catch (err) {
handleError(err);
}
};
const loading = isFetching || detailLoading;
let listContainer: ReactNode = '';
if (currentNamespace && pageSettings && user) {
const headerActions = (
{Object.keys(currentNamespace.extensions).length === 0 && (
)}
);
listContainer = (
true}
fixSelf={false}
headerActions={headerActions}
extensionRoutePrefix={AdminDashboardRoutes.EXTENSION_ADMIN}
fetchExtension={(abortController, extension) =>
service.admin.getExtension(abortController, currentNamespace.name, extension.name)
}
/>
setChangeDialogIsOpen(false)}
namespace={currentNamespace}
setLoadingState={setDetailLoading}
/>
setDeleteDialogIsOpen(false)}
onDelete={() => {
setDeleteDialogIsOpen(false);
handleDeleteNamespace();
}}
namespace={currentNamespace}
setLoadingState={setDetailLoading}
/>
);
} else if (notFound) {
listContainer = (
Namespace {notFound} not found. Do you want to create it?
Create Namespace {notFound}
);
}
return (
]}
listContainer={listContainer}
loading={loading}
/>
);
};