mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
761 lines
23 KiB
TypeScript
761 lines
23 KiB
TypeScript
import {Fragment, useCallback, useContext, useEffect} from 'react';
|
|
import {css} from '@emotion/react';
|
|
import styled from '@emotion/styled';
|
|
|
|
import {hideSidebar, showSidebar} from 'sentry/actionCreators/preferences';
|
|
import Feature from 'sentry/components/acl/feature';
|
|
import GuideAnchor from 'sentry/components/assistant/guideAnchor';
|
|
import Hook from 'sentry/components/hook';
|
|
import {OnboardingContext} from 'sentry/components/onboarding/onboardingContext';
|
|
import {getMergedTasks} from 'sentry/components/onboardingWizard/taskConfig';
|
|
import PerformanceOnboardingSidebar from 'sentry/components/performanceOnboarding/sidebar';
|
|
import ReplaysOnboardingSidebar from 'sentry/components/replaysOnboarding/sidebar';
|
|
import {isDone} from 'sentry/components/sidebar/utils';
|
|
import {
|
|
IconChevron,
|
|
IconDashboard,
|
|
IconGraph,
|
|
IconIssues,
|
|
IconLightning,
|
|
IconMegaphone,
|
|
IconPlay,
|
|
IconProfiling,
|
|
IconProject,
|
|
IconReleases,
|
|
IconSettings,
|
|
IconSiren,
|
|
IconStar,
|
|
IconStats,
|
|
IconSupport,
|
|
IconTelescope,
|
|
IconTimer,
|
|
} from 'sentry/icons';
|
|
import {t} from 'sentry/locale';
|
|
import ConfigStore from 'sentry/stores/configStore';
|
|
import DemoWalkthroughStore from 'sentry/stores/demoWalkthroughStore';
|
|
import HookStore from 'sentry/stores/hookStore';
|
|
import PreferencesStore from 'sentry/stores/preferencesStore';
|
|
import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
|
|
import {useLegacyStore} from 'sentry/stores/useLegacyStore';
|
|
import {space} from 'sentry/styles/space';
|
|
import type {Organization} from 'sentry/types';
|
|
import {isDemoWalkthrough} from 'sentry/utils/demoMode';
|
|
import {getDiscoverLandingUrl} from 'sentry/utils/discover/urls';
|
|
import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser';
|
|
import theme from 'sentry/utils/theme';
|
|
import {useLocation} from 'sentry/utils/useLocation';
|
|
import useMedia from 'sentry/utils/useMedia';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import useProjects from 'sentry/utils/useProjects';
|
|
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
|
|
import MetricsOnboardingSidebar from 'sentry/views/ddm/ddmOnboarding/sidebar';
|
|
|
|
import {ProfilingOnboardingSidebar} from '../profiling/ProfilingOnboarding/profilingOnboardingSidebar';
|
|
|
|
import Broadcasts from './broadcasts';
|
|
import SidebarHelp from './help';
|
|
import OnboardingStatus from './onboardingStatus';
|
|
import ServiceIncidents from './serviceIncidents';
|
|
import {SidebarAccordion} from './sidebarAccordion';
|
|
import SidebarDropdown from './sidebarDropdown';
|
|
import SidebarItem from './sidebarItem';
|
|
import type {SidebarOrientation} from './types';
|
|
import {SidebarPanelKey} from './types';
|
|
|
|
function activatePanel(panel: SidebarPanelKey) {
|
|
SidebarPanelStore.activatePanel(panel);
|
|
}
|
|
|
|
function togglePanel(panel: SidebarPanelKey) {
|
|
SidebarPanelStore.togglePanel(panel);
|
|
}
|
|
|
|
function hidePanel() {
|
|
SidebarPanelStore.hidePanel();
|
|
}
|
|
|
|
function useOpenOnboardingSidebar(organization?: Organization) {
|
|
const onboardingContext = useContext(OnboardingContext);
|
|
const {projects: project} = useProjects();
|
|
const location = useLocation();
|
|
|
|
const openOnboardingSidebar = (() => {
|
|
if (location?.hash === '#welcome') {
|
|
if (organization && !ConfigStore.get('demoMode')) {
|
|
const tasks = getMergedTasks({
|
|
organization,
|
|
projects: project,
|
|
onboardingContext,
|
|
});
|
|
|
|
const allDisplayedTasks = tasks
|
|
.filter(task => task.display)
|
|
.filter(task => !task.renderCard);
|
|
const doneTasks = allDisplayedTasks.filter(isDone);
|
|
|
|
return !(doneTasks.length >= allDisplayedTasks.length);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
})();
|
|
|
|
useEffect(() => {
|
|
if (openOnboardingSidebar) {
|
|
activatePanel(SidebarPanelKey.ONBOARDING_WIZARD);
|
|
}
|
|
}, [openOnboardingSidebar]);
|
|
}
|
|
|
|
function Sidebar() {
|
|
const location = useLocation();
|
|
const preferences = useLegacyStore(PreferencesStore);
|
|
const activePanel = useLegacyStore(SidebarPanelStore);
|
|
const organization = useOrganization({allowNull: true});
|
|
|
|
const collapsed = !!preferences.collapsed;
|
|
const horizontal = useMedia(`(max-width: ${theme.breakpoints.medium})`);
|
|
|
|
// Avoid showing superuser UI on self-hosted instances
|
|
const hasSuperuserSession = isActiveSuperuser() && !ConfigStore.get('isSelfHosted');
|
|
|
|
useOpenOnboardingSidebar();
|
|
|
|
const toggleCollapse = useCallback(() => {
|
|
if (collapsed) {
|
|
showSidebar();
|
|
} else {
|
|
hideSidebar();
|
|
}
|
|
}, [collapsed]);
|
|
|
|
// Close panel on any navigation
|
|
useEffect(() => void hidePanel(), [location?.pathname]);
|
|
|
|
// Add classname to body
|
|
useEffect(() => {
|
|
const bcl = document.body.classList;
|
|
|
|
bcl.add('body-sidebar');
|
|
return () => bcl.remove('body-sidebar');
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
Object.values(SidebarPanelKey).forEach(key => {
|
|
if (location?.hash === `#sidebar-${key}`) {
|
|
togglePanel(key);
|
|
}
|
|
});
|
|
}, [location?.hash]);
|
|
|
|
// Add sidebar collapse classname to body
|
|
useEffect(() => {
|
|
const bcl = document.body.classList;
|
|
|
|
if (collapsed) {
|
|
bcl.add('collapsed');
|
|
} else {
|
|
bcl.remove('collapsed');
|
|
}
|
|
|
|
return () => bcl.remove('collapsed');
|
|
}, [collapsed]);
|
|
|
|
const hasPanel = !!activePanel;
|
|
const hasOrganization = !!organization;
|
|
const orientation: SidebarOrientation = horizontal ? 'top' : 'left';
|
|
|
|
const sidebarItemProps = {
|
|
orientation,
|
|
collapsed,
|
|
hasPanel,
|
|
organization,
|
|
};
|
|
|
|
const sidebarAnchor = isDemoWalkthrough() ? (
|
|
<GuideAnchor target="projects" disabled={!DemoWalkthroughStore.get('sidebar')}>
|
|
{t('Projects')}
|
|
</GuideAnchor>
|
|
) : (
|
|
<GuideAnchor target="projects">{t('Projects')}</GuideAnchor>
|
|
);
|
|
|
|
const projects = hasOrganization && (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
index
|
|
icon={<IconProject />}
|
|
label={sidebarAnchor}
|
|
to={`/organizations/${organization.slug}/projects/`}
|
|
id="projects"
|
|
/>
|
|
);
|
|
|
|
const issues = hasOrganization && (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconIssues />}
|
|
label={<GuideAnchor target="issues">{t('Issues')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/issues/`}
|
|
search="?referrer=sidebar"
|
|
id="issues"
|
|
/>
|
|
);
|
|
|
|
const discover2 = hasOrganization && (
|
|
<Feature
|
|
hookName="feature-disabled:discover2-sidebar-item"
|
|
features="discover-basic"
|
|
organization={organization}
|
|
>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconTelescope />}
|
|
label={<GuideAnchor target="discover">{t('Discover')}</GuideAnchor>}
|
|
to={getDiscoverLandingUrl(organization)}
|
|
id="discover-v2"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const performance = hasOrganization && (
|
|
<Feature
|
|
hookName="feature-disabled:performance-sidebar-item"
|
|
features="performance-view"
|
|
organization={organization}
|
|
>
|
|
{(() => {
|
|
// If Database View or Web Vitals View is enabled, show a Performance accordion with a Database and/or Web Vitals sub-item
|
|
if (
|
|
organization.features.includes('performance-database-view') ||
|
|
organization.features.includes('starfish-browser-webvitals') ||
|
|
organization.features.includes('performance-screens-view')
|
|
) {
|
|
return (
|
|
<SidebarAccordion
|
|
{...sidebarItemProps}
|
|
icon={<IconLightning />}
|
|
label={<GuideAnchor target="performance">{t('Performance')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/performance/`}
|
|
id="performance"
|
|
>
|
|
<Feature features="performance-database-view" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
label={
|
|
<GuideAnchor target="performance-database">
|
|
{t('Queries')}
|
|
</GuideAnchor>
|
|
}
|
|
to={`/organizations/${organization.slug}/performance/database/`}
|
|
id="performance-database"
|
|
// collapsed controls whether the dot is visible or not.
|
|
// We always want it visible for these sidebar items so force it to true.
|
|
icon={<SubitemDot collapsed />}
|
|
/>
|
|
</Feature>
|
|
<Feature features="starfish-browser-webvitals" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
label={
|
|
<GuideAnchor target="performance-webvitals">
|
|
{t('Web Vitals')}
|
|
</GuideAnchor>
|
|
}
|
|
to={`/organizations/${organization.slug}/performance/browser/pageloads/`}
|
|
id="performance-webvitals"
|
|
icon={<SubitemDot collapsed />}
|
|
/>
|
|
</Feature>
|
|
<Feature features="performance-screens-view" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
label={t('Screen Loads')}
|
|
to={`/organizations/${organization.slug}/performance/mobile/screens/`}
|
|
id="performance-mobile-screens"
|
|
icon={<SubitemDot collapsed />}
|
|
/>
|
|
</Feature>
|
|
<Feature features="starfish-mobile-appstart" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
label={t('App Starts')}
|
|
to={`/organizations/${organization.slug}/performance/mobile/app-startup`}
|
|
id="performance-mobile-app-startup"
|
|
icon={<SubitemDot collapsed />}
|
|
isAlpha
|
|
/>
|
|
</Feature>
|
|
<Feature features="starfish-browser-resource-module-ui">
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
label={<GuideAnchor target="starfish">{t('Resources')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/performance/browser/resources`}
|
|
id="performance-browser-resources"
|
|
icon={<SubitemDot collapsed />}
|
|
/>
|
|
</Feature>
|
|
</SidebarAccordion>
|
|
);
|
|
}
|
|
|
|
// Otherwise, show a regular sidebar link to the Performance landing page
|
|
return (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconLightning />}
|
|
label={<GuideAnchor target="performance">{t('Performance')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/performance/`}
|
|
id="performance"
|
|
/>
|
|
);
|
|
})()}
|
|
</Feature>
|
|
);
|
|
|
|
const starfish = hasOrganization && (
|
|
<Feature
|
|
hookName="feature-disabled:starfish-view"
|
|
features="starfish-view"
|
|
organization={organization}
|
|
>
|
|
<SidebarAccordion
|
|
{...sidebarItemProps}
|
|
icon={<IconStar />}
|
|
aria-label={t('Starfish')}
|
|
label={<GuideAnchor target="starfish">{t('Starfish')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/starfish/`}
|
|
id="starfish"
|
|
exact
|
|
>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
label={<GuideAnchor target="starfish">{t('Interactions')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/performance/browser/interactions`}
|
|
id="performance-browser-interactions"
|
|
icon={<SubitemDot collapsed={collapsed} />}
|
|
/>
|
|
</SidebarAccordion>
|
|
</Feature>
|
|
);
|
|
|
|
const releases = hasOrganization && (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconReleases />}
|
|
label={<GuideAnchor target="releases">{t('Releases')}</GuideAnchor>}
|
|
to={`/organizations/${organization.slug}/releases/`}
|
|
id="releases"
|
|
/>
|
|
);
|
|
|
|
const userFeedback = hasOrganization && (
|
|
<Feature features="old-user-feedback" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconSupport />}
|
|
label={t('User Feedback')}
|
|
to={`/organizations/${organization.slug}/user-feedback/`}
|
|
id="user-feedback"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const feedback = hasOrganization && (
|
|
<Feature features="user-feedback-ui" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconMegaphone />}
|
|
label={t('User Feedback')}
|
|
isBeta
|
|
variant="short"
|
|
to={`/organizations/${organization.slug}/feedback/`}
|
|
id="feedback"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const alerts = hasOrganization && (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconSiren />}
|
|
label={t('Alerts')}
|
|
to={`/organizations/${organization.slug}/alerts/rules/`}
|
|
id="alerts"
|
|
/>
|
|
);
|
|
|
|
const monitors = hasOrganization && (
|
|
<Feature features="monitors" organization={organization}>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconTimer />}
|
|
label={t('Crons')}
|
|
to={`/organizations/${organization.slug}/crons/`}
|
|
id="crons"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const replays = hasOrganization && (
|
|
<Feature
|
|
hookName="feature-disabled:replay-sidebar-item"
|
|
features="session-replay-ui"
|
|
organization={organization}
|
|
requireAll={false}
|
|
>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconPlay />}
|
|
label={t('Replays')}
|
|
to={`/organizations/${organization.slug}/replays/`}
|
|
id="replays"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const ddmPath = `/organizations/${organization?.slug}/ddm/`;
|
|
const ddm = hasOrganization && (
|
|
<Feature
|
|
features={['ddm-ui', 'custom-metrics']}
|
|
organization={organization}
|
|
requireAll
|
|
>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconGraph />}
|
|
label={t('Metrics')}
|
|
to={ddmPath}
|
|
search={location.pathname === normalizeUrl(ddmPath) ? location.search : ''}
|
|
id="ddm"
|
|
isAlpha
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const dashboards = hasOrganization && (
|
|
<Feature
|
|
hookName="feature-disabled:dashboards-sidebar-item"
|
|
features={['discover', 'discover-query', 'dashboards-basic', 'dashboards-edit']}
|
|
organization={organization}
|
|
requireAll={false}
|
|
>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
index
|
|
icon={<IconDashboard />}
|
|
label={t('Dashboards')}
|
|
to={`/organizations/${organization.slug}/dashboards/`}
|
|
id="customizable-dashboards"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const profiling = hasOrganization && (
|
|
<Feature
|
|
hookName="feature-disabled:profiling-sidebar-item"
|
|
features="profiling"
|
|
organization={organization}
|
|
requireAll={false}
|
|
>
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
index
|
|
icon={<IconProfiling />}
|
|
label={t('Profiling')}
|
|
to={`/organizations/${organization.slug}/profiling/`}
|
|
id="profiling"
|
|
/>
|
|
</Feature>
|
|
);
|
|
|
|
const stats = hasOrganization && (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconStats />}
|
|
label={t('Stats')}
|
|
to={`/organizations/${organization.slug}/stats/`}
|
|
id="stats"
|
|
/>
|
|
);
|
|
|
|
const settings = hasOrganization && (
|
|
<SidebarItem
|
|
{...sidebarItemProps}
|
|
icon={<IconSettings />}
|
|
label={t('Settings')}
|
|
to={`/settings/${organization.slug}/`}
|
|
id="settings"
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<SidebarWrapper aria-label={t('Primary Navigation')} collapsed={collapsed}>
|
|
<SidebarSectionGroupPrimary>
|
|
<DropdownSidebarSection isSuperuser={hasSuperuserSession}>
|
|
<SidebarDropdown orientation={orientation} collapsed={collapsed} />
|
|
|
|
{hasSuperuserSession && <Hook name="component:superuser-warning" />}
|
|
</DropdownSidebarSection>
|
|
|
|
<PrimaryItems>
|
|
{hasOrganization && (
|
|
<Fragment>
|
|
<SidebarSection>
|
|
{issues}
|
|
{projects}
|
|
</SidebarSection>
|
|
|
|
<SidebarSection>
|
|
{performance}
|
|
{starfish}
|
|
{profiling}
|
|
{ddm}
|
|
{replays}
|
|
{feedback}
|
|
{monitors}
|
|
{alerts}
|
|
</SidebarSection>
|
|
|
|
<SidebarSection>
|
|
{discover2}
|
|
{dashboards}
|
|
{releases}
|
|
{userFeedback}
|
|
</SidebarSection>
|
|
|
|
<SidebarSection>
|
|
{stats}
|
|
{settings}
|
|
</SidebarSection>
|
|
</Fragment>
|
|
)}
|
|
</PrimaryItems>
|
|
</SidebarSectionGroupPrimary>
|
|
|
|
{hasOrganization && (
|
|
<SidebarSectionGroup>
|
|
<PerformanceOnboardingSidebar
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.PERFORMANCE_ONBOARDING)}
|
|
hidePanel={hidePanel}
|
|
{...sidebarItemProps}
|
|
/>
|
|
<ReplaysOnboardingSidebar
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.REPLAYS_ONBOARDING)}
|
|
hidePanel={hidePanel}
|
|
{...sidebarItemProps}
|
|
/>
|
|
<ProfilingOnboardingSidebar
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.PROFILING_ONBOARDING)}
|
|
hidePanel={hidePanel}
|
|
{...sidebarItemProps}
|
|
/>
|
|
<MetricsOnboardingSidebar
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.METRICS_ONBOARDING)}
|
|
hidePanel={hidePanel}
|
|
{...sidebarItemProps}
|
|
/>
|
|
<SidebarSection noMargin noPadding>
|
|
<OnboardingStatus
|
|
org={organization}
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.ONBOARDING_WIZARD)}
|
|
hidePanel={hidePanel}
|
|
{...sidebarItemProps}
|
|
/>
|
|
</SidebarSection>
|
|
|
|
<SidebarSection>
|
|
{HookStore.get('sidebar:bottom-items').length > 0 &&
|
|
HookStore.get('sidebar:bottom-items')[0]({
|
|
orientation,
|
|
collapsed,
|
|
hasPanel,
|
|
organization,
|
|
})}
|
|
<SidebarHelp
|
|
orientation={orientation}
|
|
collapsed={collapsed}
|
|
hidePanel={hidePanel}
|
|
organization={organization}
|
|
/>
|
|
<Broadcasts
|
|
orientation={orientation}
|
|
collapsed={collapsed}
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.BROADCASTS)}
|
|
hidePanel={hidePanel}
|
|
organization={organization}
|
|
/>
|
|
<ServiceIncidents
|
|
orientation={orientation}
|
|
collapsed={collapsed}
|
|
currentPanel={activePanel}
|
|
onShowPanel={() => togglePanel(SidebarPanelKey.SERVICE_INCIDENTS)}
|
|
hidePanel={hidePanel}
|
|
/>
|
|
</SidebarSection>
|
|
|
|
{!horizontal && (
|
|
<SidebarSection>
|
|
<SidebarCollapseItem
|
|
id="collapse"
|
|
data-test-id="sidebar-collapse"
|
|
{...sidebarItemProps}
|
|
icon={<IconChevron direction={collapsed ? 'right' : 'left'} size="sm" />}
|
|
label={collapsed ? t('Expand') : t('Collapse')}
|
|
onClick={toggleCollapse}
|
|
/>
|
|
</SidebarSection>
|
|
)}
|
|
</SidebarSectionGroup>
|
|
)}
|
|
</SidebarWrapper>
|
|
);
|
|
}
|
|
|
|
export default Sidebar;
|
|
|
|
const responsiveFlex = css`
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
@media (max-width: ${theme.breakpoints.medium}) {
|
|
flex-direction: row;
|
|
}
|
|
`;
|
|
|
|
export const SidebarWrapper = styled('nav')<{collapsed: boolean}>`
|
|
background: ${p => p.theme.sidebarGradient};
|
|
color: ${p => p.theme.sidebar.color};
|
|
line-height: 1;
|
|
padding: 12px 0 2px; /* Allows for 32px avatars */
|
|
width: ${p => p.theme.sidebar[p.collapsed ? 'collapsedWidth' : 'expandedWidth']};
|
|
position: fixed;
|
|
top: ${p => (ConfigStore.get('demoMode') ? p.theme.demo.headerSize : 0)};
|
|
left: 0;
|
|
bottom: 0;
|
|
justify-content: space-between;
|
|
z-index: ${p => p.theme.zIndex.sidebar};
|
|
border-right: solid 1px ${p => p.theme.sidebarBorder};
|
|
${responsiveFlex};
|
|
|
|
@media (max-width: ${p => p.theme.breakpoints.medium}) {
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: ${p => p.theme.sidebar.mobileHeight};
|
|
bottom: auto;
|
|
width: auto;
|
|
padding: 0 ${space(1)};
|
|
align-items: center;
|
|
border-right: none;
|
|
border-bottom: solid 1px ${p => p.theme.sidebarBorder};
|
|
}
|
|
`;
|
|
|
|
const SidebarSectionGroup = styled('div')`
|
|
${responsiveFlex};
|
|
flex-shrink: 0; /* prevents shrinking on Safari */
|
|
gap: 1px;
|
|
`;
|
|
|
|
const SidebarSectionGroupPrimary = styled('div')`
|
|
${responsiveFlex};
|
|
/* necessary for child flexing on msedge and ff */
|
|
min-height: 0;
|
|
min-width: 0;
|
|
flex: 1;
|
|
/* expand to fill the entire height on mobile */
|
|
@media (max-width: ${p => p.theme.breakpoints.medium}) {
|
|
height: 100%;
|
|
align-items: center;
|
|
}
|
|
`;
|
|
|
|
const PrimaryItems = styled('div')`
|
|
overflow: auto;
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1px;
|
|
-ms-overflow-style: -ms-autohiding-scrollbar;
|
|
@media (max-height: 675px) and (min-width: ${p => p.theme.breakpoints.medium}) {
|
|
border-bottom: 1px solid ${p => p.theme.gray400};
|
|
padding-bottom: ${space(1)};
|
|
box-shadow: rgba(0, 0, 0, 0.15) 0px -10px 10px inset;
|
|
}
|
|
@media (max-width: ${p => p.theme.breakpoints.medium}) {
|
|
overflow-y: visible;
|
|
flex-direction: row;
|
|
height: 100%;
|
|
align-items: center;
|
|
border-right: 1px solid ${p => p.theme.gray400};
|
|
padding-right: ${space(1)};
|
|
margin-right: ${space(0.5)};
|
|
box-shadow: rgba(0, 0, 0, 0.15) -10px 0px 10px inset;
|
|
::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
}
|
|
`;
|
|
|
|
const SubitemDot = styled('div')<{collapsed: boolean}>`
|
|
width: 3px;
|
|
height: 3px;
|
|
background: currentcolor;
|
|
border-radius: 50%;
|
|
|
|
opacity: ${p => (p.collapsed ? 1 : 0)};
|
|
@media (max-width: ${p => p.theme.breakpoints.medium}) {
|
|
opacity: 1;
|
|
}
|
|
`;
|
|
|
|
const SidebarSection = styled(SidebarSectionGroup)<{
|
|
noMargin?: boolean;
|
|
noPadding?: boolean;
|
|
}>`
|
|
${p => !p.noMargin && `margin: ${space(1)} 0`};
|
|
${p => !p.noPadding && `padding: 0 ${space(2)}`};
|
|
|
|
@media (max-width: ${p => p.theme.breakpoints.small}) {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
&:empty {
|
|
display: none;
|
|
}
|
|
`;
|
|
|
|
const DropdownSidebarSection = styled(SidebarSection)<{
|
|
isSuperuser?: boolean;
|
|
}>`
|
|
position: relative;
|
|
margin: 0;
|
|
padding: ${space(1)} ${space(2)};
|
|
|
|
${p =>
|
|
p.isSuperuser &&
|
|
css`
|
|
&:before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0 ${space(1)};
|
|
border-radius: ${p.theme.borderRadius};
|
|
background: ${p.theme.superuserSidebar};
|
|
}
|
|
`}
|
|
`;
|
|
|
|
const SidebarCollapseItem = styled(SidebarItem)`
|
|
@media (max-width: ${p => p.theme.breakpoints.medium}) {
|
|
display: none;
|
|
}
|
|
`;
|