2021-11-12 11:47:19 +01:00
|
|
|
import { Tab, Tabs, useMediaQuery } from '@material-ui/core';
|
2022-02-21 15:22:37 +01:00
|
|
|
import React, { useState } from 'react';
|
2022-02-15 10:57:57 +01:00
|
|
|
import { Archive, FileCopy, Label, WatchLater } from '@material-ui/icons';
|
2022-03-09 14:59:24 +01:00
|
|
|
import { Link, Route, useHistory, useParams, Switch } from 'react-router-dom';
|
2022-03-28 10:49:59 +02:00
|
|
|
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
|
2022-03-10 10:52:50 +01:00
|
|
|
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
2022-03-28 10:49:59 +02:00
|
|
|
import useProject from 'hooks/api/getters/useProject/useProject';
|
|
|
|
import useTabs from 'hooks/useTabs';
|
|
|
|
import useToast from 'hooks/useToast';
|
2022-03-10 10:52:50 +01:00
|
|
|
import { IFeatureViewParams } from 'interfaces/params';
|
2022-01-14 15:50:02 +01:00
|
|
|
import {
|
|
|
|
CREATE_FEATURE,
|
|
|
|
DELETE_FEATURE,
|
|
|
|
UPDATE_FEATURE,
|
2022-03-28 10:49:59 +02:00
|
|
|
} from 'component/providers/AccessProvider/permissions';
|
|
|
|
import Dialogue from 'component/common/Dialogue';
|
|
|
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
2021-10-01 13:49:18 +02:00
|
|
|
import FeatureLog from './FeatureLog/FeatureLog';
|
|
|
|
import FeatureOverview from './FeatureOverview/FeatureOverview';
|
|
|
|
import FeatureVariants from './FeatureVariants/FeatureVariants';
|
2022-02-21 15:22:37 +01:00
|
|
|
import { FeatureMetrics } from './FeatureMetrics/FeatureMetrics';
|
2022-02-04 10:36:08 +01:00
|
|
|
import { useStyles } from './FeatureView.styles';
|
2022-03-02 10:15:37 +01:00
|
|
|
import { FeatureSettings } from './FeatureSettings/FeatureSettings';
|
2022-03-28 10:49:59 +02:00
|
|
|
import useLoading from 'hooks/useLoading';
|
|
|
|
import ConditionallyRender from 'component/common/ConditionallyRender';
|
2021-11-12 11:47:19 +01:00
|
|
|
import StaleDialog from './FeatureOverview/StaleDialog/StaleDialog';
|
|
|
|
import AddTagDialog from './FeatureOverview/AddTagDialog/AddTagDialog';
|
2022-03-28 10:49:59 +02:00
|
|
|
import StatusChip from 'component/common/StatusChip/StatusChip';
|
2022-03-25 12:34:20 +01:00
|
|
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
2022-03-10 10:52:50 +01:00
|
|
|
import { FeatureNotFound } from 'component/feature/FeatureView/FeatureNotFound/FeatureNotFound';
|
2021-09-14 14:20:23 +02:00
|
|
|
|
2022-03-02 10:15:37 +01:00
|
|
|
export const FeatureView = () => {
|
2021-10-01 13:49:18 +02:00
|
|
|
const { projectId, featureId } = useParams<IFeatureViewParams>();
|
2021-10-19 12:36:51 +02:00
|
|
|
const { refetch: projectRefetch } = useProject(projectId);
|
2021-11-12 11:47:19 +01:00
|
|
|
const [openTagDialog, setOpenTagDialog] = useState(false);
|
2021-10-01 13:49:18 +02:00
|
|
|
const { a11yProps } = useTabs(0);
|
2021-10-08 11:23:29 +02:00
|
|
|
const { archiveFeatureToggle } = useFeatureApi();
|
2022-01-14 15:50:02 +01:00
|
|
|
const { setToastData, setToastApiError } = useToast();
|
2021-10-08 11:23:29 +02:00
|
|
|
const [showDelDialog, setShowDelDialog] = useState(false);
|
2021-11-12 11:47:19 +01:00
|
|
|
const [openStaleDialog, setOpenStaleDialog] = useState(false);
|
|
|
|
const smallScreen = useMediaQuery(`(max-width:${500}px)`);
|
|
|
|
|
2022-03-10 10:52:50 +01:00
|
|
|
const { feature, loading, error, status } = useFeature(
|
|
|
|
projectId,
|
|
|
|
featureId
|
|
|
|
);
|
|
|
|
|
2021-09-27 13:35:32 +02:00
|
|
|
const styles = useStyles();
|
2021-09-30 11:44:30 +02:00
|
|
|
const history = useHistory();
|
2021-10-08 16:19:06 +02:00
|
|
|
const ref = useLoading(loading);
|
2021-09-30 11:44:30 +02:00
|
|
|
|
2022-02-04 10:36:08 +01:00
|
|
|
const basePath = `/projects/${projectId}/features/${featureId}`;
|
2021-09-30 11:44:30 +02:00
|
|
|
|
2021-10-08 11:23:29 +02:00
|
|
|
const archiveToggle = async () => {
|
|
|
|
try {
|
|
|
|
await archiveFeatureToggle(projectId, featureId);
|
|
|
|
setToastData({
|
2022-01-14 15:50:02 +01:00
|
|
|
text: 'Your feature toggle has been archived',
|
2021-10-08 11:23:29 +02:00
|
|
|
type: 'success',
|
2022-01-14 15:50:02 +01:00
|
|
|
title: 'Feature archived',
|
2021-10-08 11:23:29 +02:00
|
|
|
});
|
|
|
|
setShowDelDialog(false);
|
2021-10-19 12:36:51 +02:00
|
|
|
projectRefetch();
|
2021-10-08 11:23:29 +02:00
|
|
|
history.push(`/projects/${projectId}`);
|
2022-02-25 10:55:39 +01:00
|
|
|
} catch (error: unknown) {
|
2022-02-21 13:47:54 +01:00
|
|
|
setToastApiError(formatUnknownError(error));
|
2021-10-08 11:23:29 +02:00
|
|
|
setShowDelDialog(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleCancel = () => setShowDelDialog(false);
|
|
|
|
|
2021-09-27 13:35:32 +02:00
|
|
|
const tabData = [
|
2021-09-30 11:44:30 +02:00
|
|
|
{
|
|
|
|
title: 'Overview',
|
2021-10-08 16:19:06 +02:00
|
|
|
path: `${basePath}`,
|
2021-09-30 11:44:30 +02:00
|
|
|
name: 'overview',
|
|
|
|
},
|
2021-10-01 13:49:18 +02:00
|
|
|
{
|
|
|
|
title: 'Metrics',
|
|
|
|
path: `${basePath}/metrics`,
|
|
|
|
name: 'Metrics',
|
|
|
|
},
|
2021-11-12 11:47:19 +01:00
|
|
|
{ title: 'Variants', path: `${basePath}/variants`, name: 'Variants' },
|
|
|
|
{ title: 'Settings', path: `${basePath}/settings`, name: 'Settings' },
|
2021-10-01 13:49:18 +02:00
|
|
|
{
|
|
|
|
title: 'Event log',
|
|
|
|
path: `${basePath}/logs`,
|
|
|
|
name: 'Event log',
|
|
|
|
},
|
2021-09-27 13:35:32 +02:00
|
|
|
];
|
|
|
|
|
2022-03-09 14:59:24 +01:00
|
|
|
const activeTab =
|
|
|
|
tabData.find(tab => tab.path === history.location.pathname) ??
|
|
|
|
tabData[0];
|
|
|
|
|
2021-09-27 13:35:32 +02:00
|
|
|
const renderTabs = () => {
|
|
|
|
return tabData.map((tab, index) => {
|
|
|
|
return (
|
|
|
|
<Tab
|
2021-10-08 16:19:06 +02:00
|
|
|
data-loading
|
2021-09-27 13:35:32 +02:00
|
|
|
key={tab.title}
|
|
|
|
label={tab.title}
|
2021-10-01 13:49:18 +02:00
|
|
|
value={tab.path}
|
2021-09-27 13:35:32 +02:00
|
|
|
{...a11yProps(index)}
|
2021-09-30 11:44:30 +02:00
|
|
|
onClick={() => {
|
|
|
|
history.push(tab.path);
|
|
|
|
}}
|
2021-09-27 13:35:32 +02:00
|
|
|
className={styles.tabButton}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2022-03-10 10:52:50 +01:00
|
|
|
if (status === 404) {
|
|
|
|
return <FeatureNotFound />;
|
|
|
|
}
|
2021-10-15 11:52:35 +02:00
|
|
|
|
2021-09-14 14:20:23 +02:00
|
|
|
return (
|
2021-10-15 11:52:35 +02:00
|
|
|
<ConditionallyRender
|
|
|
|
condition={error === undefined}
|
|
|
|
show={
|
|
|
|
<div ref={ref}>
|
|
|
|
<div className={styles.header}>
|
|
|
|
<div className={styles.innerContainer}>
|
2021-11-12 11:47:19 +01:00
|
|
|
<div className={styles.toggleInfoContainer}>
|
|
|
|
<h2
|
|
|
|
className={styles.featureViewHeader}
|
|
|
|
data-loading
|
|
|
|
>
|
|
|
|
{feature.name}{' '}
|
|
|
|
</h2>
|
|
|
|
<ConditionallyRender
|
|
|
|
condition={!smallScreen}
|
|
|
|
show={<StatusChip stale={feature?.stale} />}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
2021-10-15 11:52:35 +02:00
|
|
|
<div className={styles.actions}>
|
|
|
|
<PermissionIconButton
|
2022-01-14 15:50:02 +01:00
|
|
|
permission={CREATE_FEATURE}
|
2021-10-20 12:05:44 +02:00
|
|
|
projectId={projectId}
|
2021-10-15 11:52:35 +02:00
|
|
|
data-loading
|
|
|
|
component={Link}
|
2022-02-04 10:36:08 +01:00
|
|
|
to={`/projects/${projectId}/features/${featureId}/strategies/copy`}
|
2021-10-15 11:52:35 +02:00
|
|
|
>
|
2022-02-21 13:47:54 +01:00
|
|
|
<FileCopy titleAccess="Copy" />
|
2021-10-15 11:52:35 +02:00
|
|
|
</PermissionIconButton>
|
|
|
|
<PermissionIconButton
|
2022-01-14 15:50:02 +01:00
|
|
|
permission={DELETE_FEATURE}
|
2021-10-20 12:05:44 +02:00
|
|
|
projectId={projectId}
|
2021-10-15 11:52:35 +02:00
|
|
|
data-loading
|
|
|
|
onClick={() => setShowDelDialog(true)}
|
|
|
|
>
|
2022-02-21 13:47:54 +01:00
|
|
|
<Archive titleAccess="Archive feature toggle" />
|
2021-10-15 11:52:35 +02:00
|
|
|
</PermissionIconButton>
|
2021-11-12 11:47:19 +01:00
|
|
|
<PermissionIconButton
|
|
|
|
onClick={() => setOpenStaleDialog(true)}
|
|
|
|
permission={UPDATE_FEATURE}
|
|
|
|
projectId={projectId}
|
|
|
|
data-loading
|
|
|
|
>
|
2022-02-21 13:47:54 +01:00
|
|
|
<WatchLater titleAccess="Toggle stale status" />
|
2021-11-12 11:47:19 +01:00
|
|
|
</PermissionIconButton>
|
|
|
|
<PermissionIconButton
|
|
|
|
onClick={() => setOpenTagDialog(true)}
|
|
|
|
permission={UPDATE_FEATURE}
|
|
|
|
projectId={projectId}
|
|
|
|
data-loading
|
|
|
|
>
|
2022-02-21 13:47:54 +01:00
|
|
|
<Label titleAccess="Add tag" />
|
2021-11-12 11:47:19 +01:00
|
|
|
</PermissionIconButton>
|
2021-10-15 11:52:35 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className={styles.separator} />
|
|
|
|
<div className={styles.tabContainer}>
|
|
|
|
<Tabs
|
2022-03-09 14:59:24 +01:00
|
|
|
value={activeTab.path}
|
2021-10-15 11:52:35 +02:00
|
|
|
indicatorColor="primary"
|
|
|
|
textColor="primary"
|
|
|
|
className={styles.tabNavigation}
|
|
|
|
>
|
|
|
|
{renderTabs()}
|
|
|
|
</Tabs>
|
|
|
|
</div>
|
2021-10-08 11:23:29 +02:00
|
|
|
</div>
|
2022-03-09 14:59:24 +01:00
|
|
|
<Switch>
|
|
|
|
<Route
|
|
|
|
path={`/projects/:projectId/features/:featureId/metrics`}
|
|
|
|
component={FeatureMetrics}
|
|
|
|
/>
|
|
|
|
<Route
|
|
|
|
path={`/projects/:projectId/features/:featureId/logs`}
|
|
|
|
component={FeatureLog}
|
|
|
|
/>
|
|
|
|
<Route
|
|
|
|
path={`/projects/:projectId/features/:featureId/variants`}
|
|
|
|
component={FeatureVariants}
|
|
|
|
/>
|
|
|
|
<Route
|
|
|
|
path={`/projects/:projectId/features/:featureId/settings`}
|
|
|
|
component={FeatureSettings}
|
|
|
|
/>
|
|
|
|
<Route
|
|
|
|
path={`/projects/:projectId/features/:featureId`}
|
|
|
|
component={FeatureOverview}
|
|
|
|
/>
|
|
|
|
</Switch>
|
2021-10-15 11:52:35 +02:00
|
|
|
<Dialogue
|
|
|
|
onClick={() => archiveToggle()}
|
|
|
|
open={showDelDialog}
|
|
|
|
onClose={handleCancel}
|
|
|
|
primaryButtonText="Archive toggle"
|
|
|
|
secondaryButtonText="Cancel"
|
|
|
|
title="Archive feature toggle"
|
2021-09-27 13:35:32 +02:00
|
|
|
>
|
2021-10-15 11:52:35 +02:00
|
|
|
Are you sure you want to archive this feature toggle?
|
|
|
|
</Dialogue>
|
2021-11-12 11:47:19 +01:00
|
|
|
<StaleDialog
|
|
|
|
stale={feature.stale}
|
|
|
|
open={openStaleDialog}
|
|
|
|
setOpen={setOpenStaleDialog}
|
|
|
|
/>
|
|
|
|
<AddTagDialog
|
|
|
|
open={openTagDialog}
|
|
|
|
setOpen={setOpenTagDialog}
|
|
|
|
/>
|
2021-09-27 13:35:32 +02:00
|
|
|
</div>
|
2021-10-15 11:52:35 +02:00
|
|
|
}
|
|
|
|
/>
|
2021-09-14 14:20:23 +02:00
|
|
|
);
|
|
|
|
};
|