bring back children arrow return in PageErrorHandlingWrapper to prevent NPE errors

This commit is contained in:
Rares Mardare 2022-11-21 11:23:05 +02:00
parent ecf54678ac
commit 75c7d2bb56
8 changed files with 471 additions and 448 deletions

View file

@ -36,7 +36,7 @@ export default function PageErrorHandlingWrapper({
objectName?: string;
pageName: string;
itemNotFoundMessage?: string;
children: React.ReactNode;
children: () => React.ReactNode;
}): JSX.Element {
useEffect(() => {
if (!errorData) {

View file

@ -143,79 +143,81 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
pageName="escalations"
itemNotFoundMessage={`Escalation chain with id=${query?.id} is not found. Please select escalation chain from the list.`}
>
<>
<div className={cx('root')}>
<div className={cx('filters')}>
<EscalationsFilters value={escalationChainsFilters} onChange={this.handleEscalationsFiltersChange} />
</div>
{!searchResult || searchResult.length ? (
<div className={cx('escalations')}>
<div className={cx('left-column')}>
<WithPermissionControl userAction={UserAction.UpdateAlertReceiveChannels}>
<Button
onClick={() => {
this.setState({ showCreateEscalationChainModal: true });
}}
icon="plus"
className={cx('new-escalation-chain')}
>
New escalation chain
</Button>
</WithPermissionControl>
<div className={cx('escalations-list')}>
{searchResult ? (
<GList
autoScroll
selectedId={selectedEscalationChain}
items={searchResult}
itemKey="id"
onSelect={this.setSelectedEscalationChain}
>
{(item) => <EscalationChainCard id={item.id} />}
</GList>
) : (
<LoadingPlaceholder className={cx('loading')} text="Loading..." />
)}
</div>
</div>
<div className={cx('escalation')}>{this.renderEscalation()}</div>
{() => (
<>
<div className={cx('root')}>
<div className={cx('filters')}>
<EscalationsFilters value={escalationChainsFilters} onChange={this.handleEscalationsFiltersChange} />
</div>
) : (
<Tutorial
step={TutorialStep.Escalations}
title={
<VerticalGroup align="center" spacing="lg">
<Text type="secondary">No escalations found, check your filtering and current team.</Text>
<WithPermissionControl userAction={UserAction.UpdateEscalationPolicies}>
{!searchResult || searchResult.length ? (
<div className={cx('escalations')}>
<div className={cx('left-column')}>
<WithPermissionControl userAction={UserAction.UpdateAlertReceiveChannels}>
<Button
icon="plus"
variant="primary"
size="lg"
onClick={() => {
this.setState({ showCreateEscalationChainModal: true });
}}
icon="plus"
className={cx('new-escalation-chain')}
>
New Escalation Chain
New escalation chain
</Button>
</WithPermissionControl>
</VerticalGroup>
}
<div className={cx('escalations-list')}>
{searchResult ? (
<GList
autoScroll
selectedId={selectedEscalationChain}
items={searchResult}
itemKey="id"
onSelect={this.setSelectedEscalationChain}
>
{(item) => <EscalationChainCard id={item.id} />}
</GList>
) : (
<LoadingPlaceholder className={cx('loading')} text="Loading..." />
)}
</div>
</div>
<div className={cx('escalation')}>{this.renderEscalation()}</div>
</div>
) : (
<Tutorial
step={TutorialStep.Escalations}
title={
<VerticalGroup align="center" spacing="lg">
<Text type="secondary">No escalations found, check your filtering and current team.</Text>
<WithPermissionControl userAction={UserAction.UpdateEscalationPolicies}>
<Button
icon="plus"
variant="primary"
size="lg"
onClick={() => {
this.setState({ showCreateEscalationChainModal: true });
}}
>
New Escalation Chain
</Button>
</WithPermissionControl>
</VerticalGroup>
}
/>
)}
</div>
{showCreateEscalationChainModal && (
<EscalationChainForm
escalationChainId={escalationChainIdToCopy}
onHide={() => {
this.setState({
showCreateEscalationChainModal: false,
escalationChainIdToCopy: undefined,
});
}}
onUpdate={this.handleEscalationChainCreate}
/>
)}
</div>
{showCreateEscalationChainModal && (
<EscalationChainForm
escalationChainId={escalationChainIdToCopy}
onHide={() => {
this.setState({
showCreateEscalationChainModal: false,
escalationChainIdToCopy: undefined,
});
}}
onUpdate={this.handleEscalationChainCreate}
/>
)}
</>
</>
)}
</PageErrorHandlingWrapper>
</PluginPage>
);

View file

@ -129,65 +129,67 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
return (
<PluginPage pageNav={pages['incident'].getPageNav()}>
<PageErrorHandlingWrapper errorData={errorData} objectName="alert group" pageName="incidents">
<div className={cx('root')}>
{errorData.isNotFoundError ? (
<div className={cx('not-found')}>
<VerticalGroup spacing="lg" align="center">
<Text.Title level={1}>404</Text.Title>
<Text.Title level={4}>Incident not found</Text.Title>
<PluginLink query={{ page: 'incidents', cursor, start, perpage }}>
<Button variant="secondary" icon="arrow-left" size="md">
Go to incidents page
</Button>
</PluginLink>
</VerticalGroup>
</div>
) : (
<>
{this.renderHeader()}
<div className={cx('content')}>
<div className={cx('column')}>
<Incident incident={incident} datetimeReference={this.getIncidentDatetimeReference(incident)} />
<GroupedIncidentsList
id={incident.pk}
getIncidentDatetimeReference={this.getIncidentDatetimeReference}
/>
<AttachedIncidentsList id={incident.pk} getUnattachClickHandler={this.getUnattachClickHandler} />
</div>
<div className={cx('column')}>{this.renderTimeline()}</div>
{() => (
<div className={cx('root')}>
{errorData.isNotFoundError ? (
<div className={cx('not-found')}>
<VerticalGroup spacing="lg" align="center">
<Text.Title level={1}>404</Text.Title>
<Text.Title level={4}>Incident not found</Text.Title>
<PluginLink query={{ page: 'incidents', cursor, start, perpage }}>
<Button variant="secondary" icon="arrow-left" size="md">
Go to incidents page
</Button>
</PluginLink>
</VerticalGroup>
</div>
{showIntegrationSettings && (
<IntegrationSettings
alertGroupId={incident.pk}
onUpdate={() => {
alertReceiveChannelStore.updateItem(incident.alert_receive_channel.id);
}}
onUpdateTemplates={() => {
store.alertGroupStore.getAlert(id);
}}
startTab={IntegrationSettingsTab.Templates}
id={incident.alert_receive_channel.id}
onHide={() =>
this.setState({
showIntegrationSettings: undefined,
})
}
/>
)}
{showAttachIncidentForm && (
<AttachIncidentForm
id={id}
onHide={() => {
this.setState({
showAttachIncidentForm: false,
});
}}
onUpdate={this.update}
/>
)}
</>
)}
</div>
) : (
<>
{this.renderHeader()}
<div className={cx('content')}>
<div className={cx('column')}>
<Incident incident={incident} datetimeReference={this.getIncidentDatetimeReference(incident)} />
<GroupedIncidentsList
id={incident.pk}
getIncidentDatetimeReference={this.getIncidentDatetimeReference}
/>
<AttachedIncidentsList id={incident.pk} getUnattachClickHandler={this.getUnattachClickHandler} />
</div>
<div className={cx('column')}>{this.renderTimeline()}</div>
</div>
{showIntegrationSettings && (
<IntegrationSettings
alertGroupId={incident.pk}
onUpdate={() => {
alertReceiveChannelStore.updateItem(incident.alert_receive_channel.id);
}}
onUpdateTemplates={() => {
store.alertGroupStore.getAlert(id);
}}
startTab={IntegrationSettingsTab.Templates}
id={incident.alert_receive_channel.id}
onHide={() =>
this.setState({
showIntegrationSettings: undefined,
})
}
/>
)}
{showAttachIncidentForm && (
<AttachIncidentForm
id={id}
onHide={() => {
this.setState({
showAttachIncidentForm: false,
});
}}
onUpdate={this.update}
/>
)}
</>
)}
</div>
)}
</PageErrorHandlingWrapper>
</PluginPage>
);

View file

@ -104,10 +104,12 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
return (
<PluginPage pageNav={pages['incidents'].getPageNav()}>
<PageErrorHandlingWrapper pageName="incidents">
<div className={cx('root')}>
{this.renderIncidentFilters()}
{this.renderTable()}
</div>
{() => (
<div className={cx('root')}>
{this.renderIncidentFilters()}
{this.renderTable()}
</div>
)}
</PageErrorHandlingWrapper>
</PluginPage>
);

View file

@ -139,110 +139,112 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
pageName="integrations"
itemNotFoundMessage={`Integration with id=${query?.id} is not found. Please select integration from the list.`}
>
<>
<div className={cx('root')}>
<div className={cx('filters')}>
<IntegrationsFilters value={integrationsFilters} onChange={this.handleIntegrationsFiltersChange} />
</div>
{searchResult?.length ? (
<div className={cx('integrations')}>
<div className={cx('integrationsList')}>
<WithPermissionControl userAction={UserAction.UpdateAlertReceiveChannels}>
<Button
onClick={() => {
this.setState({ showCreateIntegrationModal: true });
}}
icon="plus"
className={cx('newIntegrationButton')}
>
New integration for receiving alerts
</Button>
</WithPermissionControl>
<div className={cx('alert-receive-channels-list')}>
<GList
autoScroll
selectedId={store.selectedAlertReceiveChannel}
items={searchResult}
itemKey="id"
onSelect={this.handleAlertReceiveChannelSelect}
>
{(item) => (
<AlertReceiveChannelCard
id={item.id}
onShowHeartbeatModal={() => {
this.setState({
alertReceiveChannelToShowSettings: item.id,
integrationSettingsTab: IntegrationSettingsTab.Heartbeat,
});
}}
/>
)}
</GList>
</div>
</div>
<div className={cx('alert-rules', 'alertRulesBorder')}>
<AlertRules
alertReceiveChannelId={store.selectedAlertReceiveChannel}
onDelete={this.handleDeleteAlertReceiveChannel}
onShowSettings={(integrationSettingsTab?: IntegrationSettingsTab) => {
this.setState({
alertReceiveChannelToShowSettings: store.selectedAlertReceiveChannel,
integrationSettingsTab,
});
}}
/>
</div>
{() => (
<>
<div className={cx('root')}>
<div className={cx('filters')}>
<IntegrationsFilters value={integrationsFilters} onChange={this.handleIntegrationsFiltersChange} />
</div>
) : searchResult ? (
<Tutorial
step={TutorialStep.Integrations}
title={
<VerticalGroup align="center" spacing="lg">
<Text type="secondary">No integrations found. Review your filter and team settings.</Text>
{searchResult?.length ? (
<div className={cx('integrations')}>
<div className={cx('integrationsList')}>
<WithPermissionControl userAction={UserAction.UpdateAlertReceiveChannels}>
<Button
icon="plus"
variant="primary"
size="lg"
onClick={() => {
this.setState({ showCreateIntegrationModal: true });
}}
icon="plus"
className={cx('newIntegrationButton')}
>
New integration for receiving alerts
</Button>
</WithPermissionControl>
</VerticalGroup>
}
<div className={cx('alert-receive-channels-list')}>
<GList
autoScroll
selectedId={store.selectedAlertReceiveChannel}
items={searchResult}
itemKey="id"
onSelect={this.handleAlertReceiveChannelSelect}
>
{(item) => (
<AlertReceiveChannelCard
id={item.id}
onShowHeartbeatModal={() => {
this.setState({
alertReceiveChannelToShowSettings: item.id,
integrationSettingsTab: IntegrationSettingsTab.Heartbeat,
});
}}
/>
)}
</GList>
</div>
</div>
<div className={cx('alert-rules', 'alertRulesBorder')}>
<AlertRules
alertReceiveChannelId={store.selectedAlertReceiveChannel}
onDelete={this.handleDeleteAlertReceiveChannel}
onShowSettings={(integrationSettingsTab?: IntegrationSettingsTab) => {
this.setState({
alertReceiveChannelToShowSettings: store.selectedAlertReceiveChannel,
integrationSettingsTab,
});
}}
/>
</div>
</div>
) : searchResult ? (
<Tutorial
step={TutorialStep.Integrations}
title={
<VerticalGroup align="center" spacing="lg">
<Text type="secondary">No integrations found. Review your filter and team settings.</Text>
<WithPermissionControl userAction={UserAction.UpdateAlertReceiveChannels}>
<Button
icon="plus"
variant="primary"
size="lg"
onClick={() => {
this.setState({ showCreateIntegrationModal: true });
}}
>
New integration for receiving alerts
</Button>
</WithPermissionControl>
</VerticalGroup>
}
/>
) : (
<LoadingPlaceholder text="Loading..." />
)}
</div>
{alertReceiveChannelToShowSettings && (
<IntegrationSettings
onUpdate={() => {
alertReceiveChannelStore.updateItem(alertReceiveChannelToShowSettings);
}}
startTab={integrationSettingsTab}
id={alertReceiveChannelToShowSettings}
onHide={() => {
this.setState({
alertReceiveChannelToShowSettings: undefined,
integrationSettingsTab: undefined,
});
LocationHelper.update({ tab: undefined }, 'partial');
}}
/>
) : (
<LoadingPlaceholder text="Loading..." />
)}
</div>
{alertReceiveChannelToShowSettings && (
<IntegrationSettings
onUpdate={() => {
alertReceiveChannelStore.updateItem(alertReceiveChannelToShowSettings);
}}
startTab={integrationSettingsTab}
id={alertReceiveChannelToShowSettings}
onHide={() => {
this.setState({
alertReceiveChannelToShowSettings: undefined,
integrationSettingsTab: undefined,
});
LocationHelper.update({ tab: undefined }, 'partial');
}}
/>
)}
{showCreateIntegrationModal && (
<CreateAlertReceiveChannelContainer
onHide={() => {
this.setState({ showCreateIntegrationModal: false });
}}
onCreate={this.handleCreateNewAlertReceiveChannel}
/>
)}
</>
{showCreateIntegrationModal && (
<CreateAlertReceiveChannelContainer
onHide={() => {
this.setState({ showCreateIntegrationModal: false });
}}
onCreate={this.handleCreateNewAlertReceiveChannel}
/>
)}
</>
)}
</PageErrorHandlingWrapper>
</PluginPage>
);

View file

@ -118,43 +118,45 @@ class OutgoingWebhooks extends React.Component<OutgoingWebhooksProps, OutgoingWe
pageName="outgoing_webhooks"
itemNotFoundMessage={`Outgoing webhook with id=${query?.id} is not found. Please select outgoing webhook from the list.`}
>
<>
<div className={cx('root')}>
<GTable
emptyText={webhooks ? 'No outgoing webhooks found' : 'Loading...'}
title={() => (
<div className={cx('header')}>
<LegacyNavHeading>
<Text.Title level={3}>Outgoing Webhooks</Text.Title>
</LegacyNavHeading>
<div className="u-pull-right">
<PluginLink
partial
query={{ id: 'new' }}
disabled={!store.isUserActionAllowed(UserAction.UpdateCustomActions)}
>
<WithPermissionControl userAction={UserAction.UpdateCustomActions}>
<Button variant="primary" icon="plus">
Create
</Button>
</WithPermissionControl>
</PluginLink>
{() => (
<>
<div className={cx('root')}>
<GTable
emptyText={webhooks ? 'No outgoing webhooks found' : 'Loading...'}
title={() => (
<div className={cx('header')}>
<LegacyNavHeading>
<Text.Title level={3}>Outgoing Webhooks</Text.Title>
</LegacyNavHeading>
<div className="u-pull-right">
<PluginLink
partial
query={{ id: 'new' }}
disabled={!store.isUserActionAllowed(UserAction.UpdateCustomActions)}
>
<WithPermissionControl userAction={UserAction.UpdateCustomActions}>
<Button variant="primary" icon="plus">
Create
</Button>
</WithPermissionControl>
</PluginLink>
</div>
</div>
</div>
)}
rowKey="id"
columns={columns}
data={webhooks}
/>
</div>
{outgoingWebhookIdToEdit && (
<OutgoingWebhookForm
id={outgoingWebhookIdToEdit}
onUpdate={this.update}
onHide={this.handleOutgoingWebhookFormHide}
/>
)}
</>
)}
rowKey="id"
columns={columns}
data={webhooks}
/>
</div>
{outgoingWebhookIdToEdit && (
<OutgoingWebhookForm
id={outgoingWebhookIdToEdit}
onUpdate={this.update}
onHide={this.handleOutgoingWebhookFormHide}
/>
)}
</>
)}
</PageErrorHandlingWrapper>
</PluginPage>
);

View file

@ -115,144 +115,155 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
return (
<PluginPage pageNav={pages['schedule'].getPageNav()}>
<PageErrorHandlingWrapper pageName="schedules">
<div className={cx('root')}>
<VerticalGroup spacing="lg">
<div className={cx('header')}>
<HorizontalGroup justify="space-between">
<HorizontalGroup>
<PluginLink query={{ page: 'schedules' }}>
<IconButton style={{ marginTop: '5px' }} name="arrow-left" size="xl" />
</PluginLink>
<Text.Title editable editModalTitle="Schedule name" level={2} onTextChange={this.handleNameChange}>
{schedule?.name}
</Text.Title>
{schedule && <ScheduleWarning item={schedule} />}
</HorizontalGroup>
<HorizontalGroup spacing="lg">
{users && (
{() => (
<>
<div className={cx('root')}>
<VerticalGroup spacing="lg">
<div className={cx('header')}>
<HorizontalGroup justify="space-between">
<HorizontalGroup>
<Text type="secondary">Current timezone:</Text>
<UserTimezoneSelect
value={currentTimezone}
users={users}
onChange={this.handleTimezoneChange}
/>
<PluginLink query={{ page: 'schedules' }}>
<IconButton style={{ marginTop: '5px' }} name="arrow-left" size="xl" />
</PluginLink>
<Text.Title
editable
editModalTitle="Schedule name"
level={2}
onTextChange={this.handleNameChange}
>
{schedule?.name}
</Text.Title>
{schedule && <ScheduleWarning item={schedule} />}
</HorizontalGroup>
)}
<HorizontalGroup>
{schedule?.type === ScheduleType.Ical && (
<HorizontalGroup spacing="lg">
{users && (
<HorizontalGroup>
<Text type="secondary">Current timezone:</Text>
<UserTimezoneSelect
value={currentTimezone}
users={users}
onChange={this.handleTimezoneChange}
/>
</HorizontalGroup>
)}
<HorizontalGroup>
<Button variant="secondary" onClick={this.handleExportClick()}>
Export
</Button>
<Button variant="secondary" onClick={this.handleReloadClick(scheduleId)}>
Reload
</Button>
{schedule?.type === ScheduleType.Ical && (
<HorizontalGroup>
<Button variant="secondary" onClick={this.handleExportClick()}>
Export
</Button>
<Button variant="secondary" onClick={this.handleReloadClick(scheduleId)}>
Reload
</Button>
</HorizontalGroup>
)}
<ToolbarButton
icon="cog"
tooltip="Settings"
onClick={() => {
this.setState({ showEditForm: true });
}}
/>
<WithConfirm>
<ToolbarButton icon="trash-alt" tooltip="Delete" onClick={this.handleDelete} />
</WithConfirm>
</HorizontalGroup>
)}
<ToolbarButton
icon="cog"
tooltip="Settings"
onClick={() => {
this.setState({ showEditForm: true });
}}
/>
<WithConfirm>
<ToolbarButton icon="trash-alt" tooltip="Delete" onClick={this.handleDelete} />
</WithConfirm>
</HorizontalGroup>
</HorizontalGroup>
</HorizontalGroup>
</div>
{schedule?.type !== ScheduleType.API && (
<Text className={cx('desc')} type="secondary">
Ical and API/Terraform schedules are read-only
</Text>
)}
<div className={cx('users-timezones')}>
<UsersTimezones
scheduleId={scheduleId}
startMoment={startMoment}
onCallNow={schedule?.on_call_now || []}
userIds={
scheduleStore.relatedUsers[scheduleId] ? Object.keys(scheduleStore.relatedUsers[scheduleId]) : []
}
tz={currentTimezone}
onTzChange={this.handleTimezoneChange}
/>
</div>
<div className={cx('rotations')}>
<div className={cx('controls')}>
<HorizontalGroup justify="space-between">
<HorizontalGroup>
<Button variant="secondary" onClick={this.handleTodayClick}>
Today
</Button>
<HorizontalGroup spacing="xs">
<Button variant="secondary" onClick={this.handleLeftClick}>
<Icon name="angle-left" />
</Button>
<Button variant="secondary" onClick={this.handleRightClick}>
<Icon name="angle-right" />
</Button>
</HorizontalGroup>
<Text.Title style={{ marginLeft: '8px' }} level={4} type="primary">
{startMoment.format('DD MMM')} - {startMoment.add(6, 'day').format('DD MMM')}
</Text.Title>
</HorizontalGroup>
</HorizontalGroup>
</div>
<ScheduleFinal
scheduleId={scheduleId}
currentTimezone={currentTimezone}
startMoment={startMoment}
onClick={this.handleShowForm}
disabled={disabled}
/>
<Rotations
scheduleId={scheduleId}
currentTimezone={currentTimezone}
startMoment={startMoment}
onCreate={this.handleCreateRotation}
onUpdate={this.handleUpdateRotation}
onDelete={this.handleDeleteRotation}
shiftIdToShowRotationForm={shiftIdToShowRotationForm}
onShowRotationForm={this.handleShowRotationForm}
disabled={disabled}
/>
<ScheduleOverrides
scheduleId={scheduleId}
currentTimezone={currentTimezone}
startMoment={startMoment}
onCreate={this.handleCreateOverride}
onUpdate={this.handleUpdateOverride}
onDelete={this.handleDeleteOverride}
shiftIdToShowRotationForm={shiftIdToShowOverridesForm}
onShowRotationForm={this.handleShowOverridesForm}
disabled={disabled}
/>
</div>
{schedule?.type !== ScheduleType.API && (
<Text className={cx('desc')} type="secondary">
Ical and API/Terraform schedules are read-only
</Text>
)}
<div className={cx('users-timezones')}>
<UsersTimezones
scheduleId={scheduleId}
startMoment={startMoment}
onCallNow={schedule?.on_call_now || []}
userIds={
scheduleStore.relatedUsers[scheduleId]
? Object.keys(scheduleStore.relatedUsers[scheduleId])
: []
}
tz={currentTimezone}
onTzChange={this.handleTimezoneChange}
/>
</div>
<div className={cx('rotations')}>
<div className={cx('controls')}>
<HorizontalGroup justify="space-between">
<HorizontalGroup>
<Button variant="secondary" onClick={this.handleTodayClick}>
Today
</Button>
<HorizontalGroup spacing="xs">
<Button variant="secondary" onClick={this.handleLeftClick}>
<Icon name="angle-left" />
</Button>
<Button variant="secondary" onClick={this.handleRightClick}>
<Icon name="angle-right" />
</Button>
</HorizontalGroup>
<Text.Title style={{ marginLeft: '8px' }} level={4} type="primary">
{startMoment.format('DD MMM')} - {startMoment.add(6, 'day').format('DD MMM')}
</Text.Title>
</HorizontalGroup>
</HorizontalGroup>
</div>
<ScheduleFinal
scheduleId={scheduleId}
currentTimezone={currentTimezone}
startMoment={startMoment}
onClick={this.handleShowForm}
disabled={disabled}
/>
<Rotations
scheduleId={scheduleId}
currentTimezone={currentTimezone}
startMoment={startMoment}
onCreate={this.handleCreateRotation}
onUpdate={this.handleUpdateRotation}
onDelete={this.handleDeleteRotation}
shiftIdToShowRotationForm={shiftIdToShowRotationForm}
onShowRotationForm={this.handleShowRotationForm}
disabled={disabled}
/>
<ScheduleOverrides
scheduleId={scheduleId}
currentTimezone={currentTimezone}
startMoment={startMoment}
onCreate={this.handleCreateOverride}
onUpdate={this.handleUpdateOverride}
onDelete={this.handleDeleteOverride}
shiftIdToShowRotationForm={shiftIdToShowOverridesForm}
onShowRotationForm={this.handleShowOverridesForm}
disabled={disabled}
/>
</div>
</VerticalGroup>
</div>
</VerticalGroup>
</div>
{showEditForm && (
<ScheduleForm
id={schedule.id}
onUpdate={this.update}
onHide={() => {
this.setState({ showEditForm: false });
}}
/>
)}
{showScheduleICalSettings && (
<Modal
isOpen
title="Schedule export"
closeOnEscape
onDismiss={() => this.setState({ showScheduleICalSettings: false })}
>
<ScheduleICalSettings id={scheduleId} />
</Modal>
{showEditForm && (
<ScheduleForm
id={schedule.id}
onUpdate={this.update}
onHide={() => {
this.setState({ showEditForm: false });
}}
/>
)}
{showScheduleICalSettings && (
<Modal
isOpen
title="Schedule export"
closeOnEscape
onDismiss={() => this.setState({ showScheduleICalSettings: false })}
>
<ScheduleICalSettings id={scheduleId} />
</Modal>
)}
</>
)}
</PageErrorHandlingWrapper>
</PluginPage>

View file

@ -180,74 +180,76 @@ class Users extends React.Component<UsersProps, UsersState> {
pageName="users"
itemNotFoundMessage={`User with id=${query?.id} is not found. Please select user from the list.`}
>
<>
<div className={cx('root')}>
<div className={cx('root', 'TEST-users-page')}>
<div className={cx('users-header')}>
<div style={{ display: 'flex', alignItems: 'baseline' }}>
<div>
<LegacyNavHeading>
<Text.Title level={3}>Users</Text.Title>
</LegacyNavHeading>
<Text type="secondary">
To manage permissions or add users, please visit{' '}
<a href="/org/users">Grafana user management</a>
</Text>
{() => (
<>
<div className={cx('root')}>
<div className={cx('root', 'TEST-users-page')}>
<div className={cx('users-header')}>
<div style={{ display: 'flex', alignItems: 'baseline' }}>
<div>
<LegacyNavHeading>
<Text.Title level={3}>Users</Text.Title>
</LegacyNavHeading>
<Text type="secondary">
To manage permissions or add users, please visit{' '}
<a href="/org/users">Grafana user management</a>
</Text>
</div>
</div>
</div>
<PluginLink partial query={{ id: 'me' }}>
<Button variant="primary" icon="user">
View my profile
</Button>
</PluginLink>
</div>
{store.isUserActionAllowed(UserAction.ViewOtherUsers) ? (
<>
<div className={cx('user-filters-container')}>
<UsersFilters
className={cx('users-filters')}
value={usersFilters}
onChange={this.handleUsersFiltersChange}
/>
<Button
variant="secondary"
icon="times"
onClick={handleClear}
className={cx('searchIntegrationClear')}
>
Clear filters
<PluginLink partial query={{ id: 'me' }}>
<Button variant="primary" icon="user">
View my profile
</Button>
</div>
</PluginLink>
</div>
{store.isUserActionAllowed(UserAction.ViewOtherUsers) ? (
<>
<div className={cx('user-filters-container')}>
<UsersFilters
className={cx('users-filters')}
value={usersFilters}
onChange={this.handleUsersFiltersChange}
/>
<Button
variant="secondary"
icon="times"
onClick={handleClear}
className={cx('searchIntegrationClear')}
>
Clear filters
</Button>
</div>
<GTable
emptyText={results ? 'No users found' : 'Loading...'}
rowKey="pk"
data={results}
columns={columns}
rowClassName={getUserRowClassNameFn(userPkToEdit, userStore.currentUserPk)}
pagination={{
page,
total: Math.ceil((count || 0) / ITEMS_PER_PAGE),
onChange: this.handleChangePage,
}}
<GTable
emptyText={results ? 'No users found' : 'Loading...'}
rowKey="pk"
data={results}
columns={columns}
rowClassName={getUserRowClassNameFn(userPkToEdit, userStore.currentUserPk)}
pagination={{
page,
total: Math.ceil((count || 0) / ITEMS_PER_PAGE),
onChange: this.handleChangePage,
}}
/>
</>
) : (
<Alert
/* @ts-ignore */
title={
<>
You don't have enough permissions to view other users because you are not Admin.{' '}
<PluginLink query={{ page: 'users', id: 'me' }}>Click here</PluginLink> to open your profile
</>
}
severity="info"
/>
</>
) : (
<Alert
/* @ts-ignore */
title={
<>
You don't have enough permissions to view other users because you are not Admin.{' '}
<PluginLink query={{ page: 'users', id: 'me' }}>Click here</PluginLink> to open your profile
</>
}
severity="info"
/>
)}
)}
</div>
{userPkToEdit && <UserSettings id={userPkToEdit} onHide={this.handleHideUserSettings} />}
</div>
{userPkToEdit && <UserSettings id={userPkToEdit} onHide={this.handleHideUserSettings} />}
</div>
</>
</>
)}
</PageErrorHandlingWrapper>
</PluginPage>
);