diff --git a/ui/src/app/pages/analysis/notebook-list.spec.tsx b/ui/src/app/pages/analysis/notebook-list.spec.tsx deleted file mode 100644 index 7eff1d2af0a..00000000000 --- a/ui/src/app/pages/analysis/notebook-list.spec.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import * as React from 'react'; -import { MemoryRouter } from 'react-router'; -import { mount } from 'enzyme'; - -import { NotebooksApi, ProfileApi, WorkspacesApi } from 'generated/fetch'; - -import { - MODIFIED_BY_COLUMN_NUMBER, - MODIFIED_DATE_COLUMN_NUMBER, - NAME_COLUMN_NUMBER, - RESOURCE_TYPE_COLUMN_NUMBER, - resourceTableColumns, -} from 'app/components/resource-list.spec'; -import { analysisTabPath } from 'app/routing/utils'; -import { registerApiClient } from 'app/services/swagger-fetch-clients'; -import { displayDateWithoutHours } from 'app/utils/dates'; -import { currentWorkspaceStore } from 'app/utils/navigation'; - -import { waitOneTickAndUpdate } from 'testing/react-test-helpers'; -import { NotebooksApiStub } from 'testing/stubs/notebooks-api-stub'; -import { ProfileApiStub } from 'testing/stubs/profile-api-stub'; -import { workspaceDataStub } from 'testing/stubs/workspaces'; -import { WorkspacesApiStub } from 'testing/stubs/workspaces-api-stub'; - -import { NotebookList } from './notebook-list'; - -describe('NotebookList', () => { - beforeEach(() => { - registerApiClient(WorkspacesApi, new WorkspacesApiStub()); - registerApiClient(NotebooksApi, new NotebooksApiStub()); - registerApiClient(ProfileApi, new ProfileApiStub()); - }); - - it('should render notebooks', async () => { - currentWorkspaceStore.next(workspaceDataStub); - const wrapper = mount( - - {}} /> - - ); - await waitOneTickAndUpdate(wrapper); - - // Second Column of notebook table displays the type of resource: Notebook - expect( - resourceTableColumns(wrapper).at(RESOURCE_TYPE_COLUMN_NUMBER).text() - ).toMatch('Notebook'); - - // Third column of notebook table displays the notebook file name - expect(resourceTableColumns(wrapper).at(NAME_COLUMN_NUMBER).text()).toMatch( - NotebooksApiStub.stubNotebookList()[0].name.split('.ipynb')[0] - ); - - // Forth column of notebook table displays last modified time - expect( - resourceTableColumns(wrapper).at(MODIFIED_DATE_COLUMN_NUMBER).text() - ).toMatch( - displayDateWithoutHours( - NotebooksApiStub.stubNotebookList()[0].lastModifiedTime - ) - ); - - // Fifth column of notebook table displays last modified by - expect( - resourceTableColumns(wrapper).at(MODIFIED_BY_COLUMN_NUMBER).text() - ).toMatch(NotebooksApiStub.stubNotebookList()[0].lastModifiedBy); - }); - - it('should redirect to notebook playground mode when either resource type or name is clicked', async () => { - currentWorkspaceStore.next(workspaceDataStub); - const wrapper = mount( - - {}} /> - - ); - await waitOneTickAndUpdate(wrapper); - - const expected = `${analysisTabPath( - workspaceDataStub.namespace, - workspaceDataStub.id - )}/preview/mockFile.ipynb`; - expect( - resourceTableColumns(wrapper) - .at(RESOURCE_TYPE_COLUMN_NUMBER) - .find('a') - .prop('href') - ).toBe(expected); - - expect( - resourceTableColumns(wrapper) - .at(NAME_COLUMN_NUMBER) - .find('a') - .prop('href') - ).toBe(expected); - }); -}); diff --git a/ui/src/app/pages/analysis/notebook-list.tsx b/ui/src/app/pages/analysis/notebook-list.tsx deleted file mode 100644 index 322e444f787..00000000000 --- a/ui/src/app/pages/analysis/notebook-list.tsx +++ /dev/null @@ -1,286 +0,0 @@ -import * as React from 'react'; -import { - faExclamationTriangle, - faPlusCircle, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - -import { BillingStatus, FileDetail } from 'generated/fetch'; - -import { Clickable } from 'app/components/buttons'; -import { FadeBox } from 'app/components/containers'; -import { FlexColumn, FlexRow } from 'app/components/flex'; -import { ListPageHeader } from 'app/components/headers'; -import { InfoIcon } from 'app/components/icons'; -import { TooltipTrigger } from 'app/components/popups'; -import { ResourceList } from 'app/components/resource-list'; -import { SpinnerOverlay } from 'app/components/spinners'; -import { WithSpinnerOverlayProps } from 'app/components/with-spinner-overlay'; -import { NewJupyterNotebookModal } from 'app/pages/analysis/new-jupyter-notebook-modal'; -import { profileApi, workspacesApi } from 'app/services/swagger-fetch-clients'; -import colors, { colorWithWhiteness } from 'app/styles/colors'; -import { withCurrentWorkspace } from 'app/utils'; -import { AnalyticsTracker } from 'app/utils/analytics'; -import { convertToResources } from 'app/utils/resources'; -import { ACTION_DISABLED_INVALID_BILLING } from 'app/utils/strings'; -import { WorkspaceData } from 'app/utils/workspace-data'; -import { WorkspacePermissionsUtil } from 'app/utils/workspace-permissions'; - -import { listNotebooks } from './util'; - -const styles = { - heading: { - color: colors.primary, - fontSize: 20, - fontWeight: 600, - lineHeight: '24px', - }, - cloneNotebookCard: { - backgroundColor: colorWithWhiteness(colors.warning, 0.75), - minWidth: '200px', - maxWidth: '200px', - minHeight: '223px', - maxHeight: '223px', - border: 'none', - }, - cloneNotebookMsg: { - color: colors.primary, - fontSize: '12px', - fontWeight: 600, - paddingTop: '0.75rem', - }, -}; - -const NOTEBOOK_TRANSFER_CHECK_INTERVAL = 3000; - -interface Props extends WithSpinnerOverlayProps { - workspace: WorkspaceData; -} - -export const NotebookList = withCurrentWorkspace()( - class extends React.Component< - Props, - { - notebookList: FileDetail[]; - notebookNameList: string[]; - creating: boolean; - loading: boolean; - showWaitingForNotebookTransferMsg: boolean; - } - > { - private interval: NodeJS.Timeout; - constructor(props) { - super(props); - this.state = { - notebookList: [], - notebookNameList: [], - creating: false, - loading: false, - showWaitingForNotebookTransferMsg: false, - }; - } - - componentDidMount() { - this.props.hideSpinner(); - profileApi().updatePageVisits({ page: 'notebook' }); - this.confirmNotebookTransferIsDone(); - } - - componentDidUpdate(prevProps) { - if (this.workspaceChanged(prevProps)) { - this.loadNotebooks(); - } - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - async confirmNotebookTransferIsDone() { - await workspacesApi() - .notebookTransferComplete( - this.props.workspace.namespace, - this.props.workspace.id - ) - .then((transferDone) => { - if (!transferDone) { - // Set the interval so that file transfer check is done after every 3 sec - this.interval = setInterval( - this.tick, - NOTEBOOK_TRANSFER_CHECK_INTERVAL - ); - this.setState({ - loading: true, - showWaitingForNotebookTransferMsg: true, - }); - } else { - // Notebook transfer is done load the notebooks - this.loadNotebooks(); - } - }); - } - - // Will execute after every 3 sec: Call getCloneFileTransferDetails to check if the notebook file transfer is done - tick = () => { - workspacesApi() - .notebookTransferComplete( - this.props.workspace.namespace, - this.props.workspace.id - ) - .then((time) => { - if (!!time) { - this.setState({ - loading: false, - showWaitingForNotebookTransferMsg: false, - }); - clearInterval(this.interval); - this.loadNotebooks(); - } - }); - }; - - private workspaceChanged(prevProps) { - return ( - this.props.workspace.namespace !== prevProps.workspace.namespace || - this.props.workspace.id !== prevProps.workspace.id - ); - } - - private async loadNotebooks() { - try { - const { workspace } = this.props; - this.setState({ loading: true }); - listNotebooks(workspace).then((notebookList) => { - this.setState({ - notebookList, - notebookNameList: notebookList.map((fd) => fd.name), - }); - }); - } catch (error) { - console.error(error); - } finally { - this.setState({ loading: false }); - } - } - - private canWrite(): boolean { - return WorkspacePermissionsUtil.canWrite( - this.props.workspace.accessLevel - ); - } - - private disabledCreateButtonText(): string { - if (this.props.workspace.billingStatus === BillingStatus.INACTIVE) { - return ACTION_DISABLED_INVALID_BILLING; - } else if (!this.canWrite()) { - return 'Write permission required to create notebooks'; - } - } - - getNotebookListAsResources = () => { - const { workspace } = this.props; - const { notebookList } = this.state; - return convertToResources(notebookList, workspace); - }; - - render() { - const { workspace } = this.props; - const { - notebookNameList, - creating, - loading, - showWaitingForNotebookTransferMsg, - } = this.state; - return ( - -
-
- {showWaitingForNotebookTransferMsg ? ( - -
- -
-
- Copying 1 or more notebooks from another workspace. This may - take a few minutes. -
-
- ) : ( - - - {/* disable if user does not have write permission*/} - - { - AnalyticsTracker.Notebooks.OpenCreateModal(); - this.setState({ creating: true }); - }} - disabled={ - workspace.billingStatus === BillingStatus.INACTIVE || - !this.canWrite() - } - > - - - - Create a New Notebook -
- - - -
-
- {!loading && ( - this.loadNotebooks()} - /> - )} -
- )} -
-
- {loading && } - {creating && ( - this.setState({ creating: false })} - /> - )} -
- ); - } - } -); diff --git a/ui/src/app/pages/appAnalysis/app-files-list.spec.tsx b/ui/src/app/pages/appAnalysis/app-files-list.spec.tsx index 0b45500cda4..47732a0b0df 100644 --- a/ui/src/app/pages/appAnalysis/app-files-list.spec.tsx +++ b/ui/src/app/pages/appAnalysis/app-files-list.spec.tsx @@ -25,7 +25,7 @@ const component = async () => {}} hideSpinner={() => {}} /> ); -describe('AppsList', () => { +describe(AppFilesList.name, () => { let workspacesApiStub: WorkspacesApiStub; let notebooksApiStub: NotebooksApiStub; let user; diff --git a/ui/src/app/pages/data/cohort/overview.tsx b/ui/src/app/pages/data/cohort/overview.tsx index 80d533e8b80..78b2258d1c2 100644 --- a/ui/src/app/pages/data/cohort/overview.tsx +++ b/ui/src/app/pages/data/cohort/overview.tsx @@ -16,7 +16,6 @@ import { WorkspaceAccessLevel, } from 'generated/fetch'; -import { environment } from 'environments/environment'; import { Button, Clickable } from 'app/components/buttons'; import { ComboChart } from 'app/components/combo-chart.component'; import { ConfirmDeleteModal } from 'app/components/confirm-delete-modal'; @@ -657,27 +656,25 @@ export const ListOverview = fp.flow( /> )} - {environment.showCBFunnelPlot && ( - View Funnel Plot}> - { - AnalyticsTracker.CohortBuilder.ViewFunnelPlot(); - this.funnelOverlay.toggle(e); - }} - > - - - - )} + View Funnel Plot}> + { + AnalyticsTracker.CohortBuilder.ViewFunnelPlot(); + this.funnelOverlay.toggle(e); + }} + > + + + Delete cohort}> `/workspaces/${namespace}/${id}`; // internal name of the analysis tab, also used to construct URLs -export const analysisTabName = environment.showNewAnalysisTab - ? 'analysis' - : 'notebooks'; +export const analysisTabName = 'analysis'; export const analysisTabPath = (namespace: string, id: string): string => `${workspacePath(namespace, id)}/${analysisTabName}`; diff --git a/ui/src/app/routing/workspace-app-routing.tsx b/ui/src/app/routing/workspace-app-routing.tsx index 29a0c33f8ba..252fce3a270 100644 --- a/ui/src/app/routing/workspace-app-routing.tsx +++ b/ui/src/app/routing/workspace-app-routing.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { Redirect, Switch, useParams, useRouteMatch } from 'react-router-dom'; import * as fp from 'lodash/fp'; -import { environment } from 'environments/environment'; import { AppRoute, withRouteData } from 'app/components/app-router'; import { BreadcrumbType } from 'app/components/breadcrumb-type'; import { LEONARDO_APP_PAGE_KEY } from 'app/components/help-sidebar'; @@ -13,7 +12,6 @@ import { LeoApplicationType, LeonardoAppLauncher, } from 'app/pages/analysis/leonardo-app-launcher'; -import { NotebookList } from 'app/pages/analysis/notebook-list'; import { AppFilesList } from 'app/pages/appAnalysis/app-files-list'; import { CohortActions } from 'app/pages/data/cohort/cohort-actions'; import { CohortPage } from 'app/pages/data/cohort/cohort-page'; @@ -77,10 +75,6 @@ const InteractiveNotebookPage = fp.flow( withRouteData, withRoutingSpinner )(InteractiveNotebook); -const NotebookListPage = fp.flow( - withRouteData, - withRoutingSpinner -)(NotebookList); const LeonardoAppRedirectPage = fp.flow( withRouteData, withRoutingSpinner @@ -154,25 +148,14 @@ export const WorkspaceRoutes = () => { path={`${path}/${analysisTabName}`} guards={[adminLockedGuard(ns, wsid)]} > - {environment.showNewAnalysisTab ? ( - - ) : ( - - )} +