mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Synthetics] Add project api keys settings tab (#147106)
## Summary Fixes https://github.com/elastic/kibana/issues/146039 Add API keys settings tab in synthetics settings page ### Initial State <img width="1792" alt="image" src="https://user-images.githubusercontent.com/3505601/206190656-8208368f-23a4-4a0b-a5a3-c6d2d4b98826.png"> ### Final state This API keys is from test env, so it's safe to display here <img width="1791" alt="image" src="https://user-images.githubusercontent.com/3505601/205942788-28b28b9f-a731-4090-8a26-4fcb88141fba.png">
This commit is contained in:
parent
39d27bb868
commit
7434d25fc1
14 changed files with 475 additions and 3 deletions
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './project_api_keys.journey';
|
||||
export * from './getting_started.journey';
|
||||
export * from './add_monitor.journey';
|
||||
export * from './monitor_selector.journey';
|
||||
|
|
|
@ -72,7 +72,7 @@ journey(`PrivateLocationsSettings`, async ({ page, params }) => {
|
|||
});
|
||||
let locationId: string;
|
||||
step('Click text=AlertingPrivate LocationsData Retention', async () => {
|
||||
await page.click('text=AlertingPrivate LocationsData Retention');
|
||||
await page.click('text=Private Locations');
|
||||
await page.click('h1:has-text("Settings")');
|
||||
|
||||
const privateLocations = await getPrivateLocations(params);
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { journey, step, expect, before } from '@elastic/synthetics';
|
||||
|
||||
journey('ProjectAPIKeys', async ({ page }) => {
|
||||
let apiKey = '';
|
||||
|
||||
page.setDefaultTimeout(3 * 30000);
|
||||
|
||||
before(async () => {
|
||||
page.on('request', (evt) => {
|
||||
if (evt.resourceType() === 'fetch' && evt.url().includes('uptime/service/api_key')) {
|
||||
evt
|
||||
.response()
|
||||
?.then((res) => res?.json())
|
||||
.then((res) => {
|
||||
apiKey = res.apiKey.encoded;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
step('Go to http://localhost:5620/login?next=%2Fapp%2Fsynthetics%2Fsettings', async () => {
|
||||
await page.goto('http://localhost:5620/login?next=%2Fapp%2Fsynthetics%2Fsettings');
|
||||
await page.click('input[name="username"]');
|
||||
await page.fill('input[name="username"]', 'elastic');
|
||||
await page.press('input[name="username"]', 'Tab');
|
||||
await page.fill('input[name="password"]', 'changeme');
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ url: 'http://localhost:5620/app/synthetics/settings/alerting' }),
|
||||
page.click('button:has-text("Log in")'),
|
||||
]);
|
||||
});
|
||||
step('Click text=Project API Keys', async () => {
|
||||
await page.click('text=Project API Keys');
|
||||
expect(page.url()).toBe('http://localhost:5620/app/synthetics/settings/api-keys');
|
||||
await page.click('button:has-text("Generate Project API key")');
|
||||
await page.click(
|
||||
'text=This API key will only be shown once. Please keep a copy for your own records.'
|
||||
);
|
||||
await page.click('strong:has-text("API key")');
|
||||
await page.click('text=Use as environment variable');
|
||||
await page.click(`text=${apiKey}`);
|
||||
await page.click('[aria-label="Account menu"]');
|
||||
});
|
||||
step('Click text=Log out', async () => {
|
||||
await page.click('text=Log out');
|
||||
expect(page.url()).toBe('http://localhost:5620/login?msg=LOGGED_OUT');
|
||||
await page.fill('input[name="username"]', 'viewer');
|
||||
await page.press('input[name="username"]', 'Tab');
|
||||
await page.fill('input[name="password"]', 'changeme');
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ url: 'http://localhost:5620/app/home' }),
|
||||
page.click('button:has-text("Log in")'),
|
||||
]);
|
||||
await page.goto('http://localhost:5620/app/synthetics/settings/api-keys', {
|
||||
waitUntil: 'networkidle',
|
||||
});
|
||||
});
|
||||
step('Click text=Synthetics', async () => {
|
||||
expect(page.url()).toBe('http://localhost:5620/app/synthetics/settings/api-keys');
|
||||
await page.isDisabled('button:has-text("Generate Project API key")');
|
||||
});
|
||||
});
|
|
@ -20,9 +20,9 @@ export function syntheticsAppPageProvider({ page, kibanaUrl }: { page: Page; kib
|
|||
const isRemote = Boolean(process.env.SYNTHETICS_REMOTE_ENABLED);
|
||||
const basePath = isRemote ? remoteKibanaUrl : kibanaUrl;
|
||||
const monitorManagement = `${basePath}/app/synthetics/monitors`;
|
||||
const settingsPage = `${basePath}/app/synthetics/settings`;
|
||||
const addMonitor = `${basePath}/app/synthetics/add-monitor`;
|
||||
const overview = `${basePath}/app/synthetics`;
|
||||
const settingsPage = `${basePath}/app/synthetics/settings`;
|
||||
|
||||
return {
|
||||
...loginPageProvider({
|
||||
|
|
|
@ -10,7 +10,12 @@ import { EuiPageHeaderProps } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { SYNTHETICS_SETTINGS_ROUTE } from '../../../../../common/constants';
|
||||
|
||||
export type SettingsTabId = 'data-retention' | 'params' | 'alerting' | 'private-locations';
|
||||
export type SettingsTabId =
|
||||
| 'data-retention'
|
||||
| 'params'
|
||||
| 'alerting'
|
||||
| 'private-locations'
|
||||
| 'api-keys';
|
||||
|
||||
export const getSettingsPageHeader = (
|
||||
history: ReturnType<typeof useHistory>,
|
||||
|
@ -56,6 +61,13 @@ export const getSettingsPageHeader = (
|
|||
isSelected: tabId === 'data-retention',
|
||||
href: replaceTab('data-retention'),
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.synthetics.settingsTabs.apiKeys', {
|
||||
defaultMessage: 'Project API Keys',
|
||||
}),
|
||||
isSelected: tabId === 'api-keys',
|
||||
href: replaceTab('api-keys'),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { ApiKeyBtn } from './api_key_btn';
|
||||
import { render } from '../../../utils/testing';
|
||||
|
||||
describe('<APIKeyButton />', () => {
|
||||
const setLoadAPIKey = jest.fn();
|
||||
|
||||
it('calls delete monitor on monitor deletion', () => {
|
||||
render(<ApiKeyBtn setLoadAPIKey={setLoadAPIKey} apiKey="" loading={false} />);
|
||||
|
||||
expect(screen.getByText('Generate Project API key')).toBeInTheDocument();
|
||||
userEvent.click(screen.getByTestId('uptimeMonitorManagementApiKeyGenerate'));
|
||||
expect(setLoadAPIKey).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows correct content on loading', () => {
|
||||
render(<ApiKeyBtn setLoadAPIKey={setLoadAPIKey} apiKey="" loading={true} />);
|
||||
|
||||
expect(screen.getByText('Generating API key')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows api key when available and hides button', () => {
|
||||
const apiKey = 'sampleApiKey';
|
||||
render(<ApiKeyBtn setLoadAPIKey={setLoadAPIKey} apiKey={apiKey} loading={false} />);
|
||||
|
||||
expect(screen.queryByText('Generate Project API key')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { EuiButton, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const ApiKeyBtn = ({
|
||||
isDisabled,
|
||||
apiKey,
|
||||
loading,
|
||||
setLoadAPIKey,
|
||||
}: {
|
||||
loading?: boolean;
|
||||
isDisabled?: boolean;
|
||||
apiKey?: string;
|
||||
setLoadAPIKey: (val: boolean) => void;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
{!apiKey && (
|
||||
<>
|
||||
<EuiButton
|
||||
fill
|
||||
isDisabled={isDisabled}
|
||||
fullWidth={true}
|
||||
isLoading={loading}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setLoadAPIKey(true);
|
||||
}}
|
||||
data-test-subj="uptimeMonitorManagementApiKeyGenerate"
|
||||
>
|
||||
{loading ? GET_API_KEY_LOADING_LABEL : GET_API_KEY_LABEL}
|
||||
</EuiButton>
|
||||
<EuiSpacer size="s" />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const GET_API_KEY_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.getProjectApiKey.label',
|
||||
{
|
||||
defaultMessage: 'Generate Project API key',
|
||||
}
|
||||
);
|
||||
|
||||
const GET_API_KEY_LOADING_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.getAPIKeyLabel.loading',
|
||||
{
|
||||
defaultMessage: 'Generating API key',
|
||||
}
|
||||
);
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiCallOut, EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const HelpCommands = ({ apiKey }: { apiKey: string }) => {
|
||||
return (
|
||||
<div className="text-left">
|
||||
<EuiCallOut title={API_KEY_WARNING_LABEL} iconType="iInCircle" size="s" />
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">
|
||||
<strong>{API_KEY_LABEL}</strong>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeBlock language="javascript" isCopyable fontSize="s" paddingSize="m" whiteSpace="pre">
|
||||
{apiKey}
|
||||
</EuiCodeBlock>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText size="s">
|
||||
<strong>{USE_AS_ENV}</strong>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeBlock language="javascript" isCopyable fontSize="s" paddingSize="m">
|
||||
export SYNTHETICS_API_KEY={apiKey}
|
||||
</EuiCodeBlock>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText size="s">
|
||||
<strong>{PROJECT_PUSH_COMMAND}</strong>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeBlock language="javascript" isCopyable fontSize="s" paddingSize="m">
|
||||
SYNTHETICS_API_KEY={apiKey} npm run push
|
||||
</EuiCodeBlock>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const API_KEY_LABEL = i18n.translate('xpack.synthetics.monitorManagement.apiKey.label', {
|
||||
defaultMessage: 'API key',
|
||||
});
|
||||
|
||||
const USE_AS_ENV = i18n.translate('xpack.synthetics.monitorManagement.useEnv.label', {
|
||||
defaultMessage: 'Use as environment variable',
|
||||
});
|
||||
|
||||
const PROJECT_PUSH_COMMAND = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.projectPush.label',
|
||||
{
|
||||
defaultMessage: 'Project push command',
|
||||
}
|
||||
);
|
||||
|
||||
const API_KEY_WARNING_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.apiKeyWarning.label',
|
||||
{
|
||||
defaultMessage:
|
||||
'This API key will only be shown once. Please keep a copy for your own records.',
|
||||
}
|
||||
);
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import * as observabilityPublic from '@kbn/observability-plugin/public';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { ProjectAPIKeys } from './project_api_keys';
|
||||
import { makeUptimePermissionsCore, render } from '../../../utils/testing';
|
||||
|
||||
jest.mock('@kbn/observability-plugin/public');
|
||||
|
||||
describe('<ProjectAPIKeys />', () => {
|
||||
const state = {
|
||||
syntheticsEnablement: {
|
||||
enablement: {
|
||||
canManageApiKeys: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
jest.spyOn(observabilityPublic, 'useFetcher').mockReturnValue({
|
||||
data: undefined,
|
||||
status: observabilityPublic.FETCH_STATUS.SUCCESS,
|
||||
refetch: () => {},
|
||||
});
|
||||
});
|
||||
|
||||
it('shows the button', () => {
|
||||
jest.spyOn(observabilityPublic, 'useFetcher').mockReturnValue({
|
||||
data: undefined,
|
||||
status: observabilityPublic.FETCH_STATUS.SUCCESS,
|
||||
refetch: () => {},
|
||||
});
|
||||
render(<ProjectAPIKeys />);
|
||||
|
||||
expect(screen.queryByText('Generate API key')).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/Use an API key to push monitors remotely from a CLI or CD pipeline/)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows appropriate content when user does not have correct uptime save permissions', () => {
|
||||
// const apiKey = 'sampleApiKey';
|
||||
render(<ProjectAPIKeys />, {
|
||||
state,
|
||||
core: makeUptimePermissionsCore({ save: false }),
|
||||
});
|
||||
|
||||
expect(screen.getByText(/Please contact your administrator./)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows appropriate content when user does not api key management permissions', () => {
|
||||
render(<ProjectAPIKeys />, {
|
||||
state: {
|
||||
syntheticsEnablement: {
|
||||
enablement: {
|
||||
canManageApiKeys: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
core: makeUptimePermissionsCore({ save: true }),
|
||||
});
|
||||
|
||||
expect(screen.getByText(/Please contact your administrator./)).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { EuiText, EuiLink, EuiEmptyPrompt } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useFetcher } from '@kbn/observability-plugin/public';
|
||||
import { HelpCommands } from './help_commands';
|
||||
import { LoadingState } from '../../monitors_page/overview/overview/monitor_detail_flyout';
|
||||
import { fetchServiceAPIKey } from '../../../state/monitor_management/api';
|
||||
import { ClientPluginsStart } from '../../../../../plugin';
|
||||
import { ApiKeyBtn } from './api_key_btn';
|
||||
import { useEnablement } from '../../../hooks';
|
||||
|
||||
const syntheticsTestRunDocsLink =
|
||||
'https://www.elastic.co/guide/en/observability/current/synthetic-run-tests.html';
|
||||
|
||||
export const ProjectAPIKeys = () => {
|
||||
const {
|
||||
loading: enablementLoading,
|
||||
enablement: { canManageApiKeys },
|
||||
} = useEnablement();
|
||||
const [apiKey, setApiKey] = useState<string | undefined>(undefined);
|
||||
const [loadAPIKey, setLoadAPIKey] = useState(false);
|
||||
|
||||
const kServices = useKibana<ClientPluginsStart>().services;
|
||||
const canSaveIntegrations: boolean =
|
||||
!!kServices?.fleet?.authz.integrations.writeIntegrationPolicies;
|
||||
|
||||
const { data, loading } = useFetcher(async () => {
|
||||
if (loadAPIKey) {
|
||||
return fetchServiceAPIKey();
|
||||
}
|
||||
return null;
|
||||
}, [loadAPIKey]);
|
||||
|
||||
useEffect(() => {
|
||||
setApiKey(data?.apiKey.encoded);
|
||||
}, [data]);
|
||||
|
||||
const canSave: boolean = !!useKibana().services?.application?.capabilities.uptime.save;
|
||||
|
||||
if (enablementLoading) {
|
||||
return <LoadingState />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiEmptyPrompt
|
||||
style={{ maxWidth: '50%' }}
|
||||
title={<h2>{GET_API_KEY_GENERATE}</h2>}
|
||||
body={
|
||||
canSave && canManageApiKeys ? (
|
||||
<>
|
||||
<EuiText>
|
||||
{GET_API_KEY_LABEL_DESCRIPTION}{' '}
|
||||
{!canSaveIntegrations ? `${API_KEY_DISCLAIMER} ` : ''}
|
||||
<EuiLink href={syntheticsTestRunDocsLink} external target="_blank">
|
||||
{LEARN_MORE_LABEL}
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<EuiText>
|
||||
{GET_API_KEY_REDUCED_PERMISSIONS_LABEL}{' '}
|
||||
<EuiLink href={syntheticsTestRunDocsLink} external target="_blank">
|
||||
{LEARN_MORE_LABEL}
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
</>
|
||||
)
|
||||
}
|
||||
actions={
|
||||
<ApiKeyBtn
|
||||
loading={loading}
|
||||
setLoadAPIKey={setLoadAPIKey}
|
||||
apiKey={apiKey}
|
||||
isDisabled={!canSave || !canManageApiKeys}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{apiKey && <HelpCommands apiKey={apiKey} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const LEARN_MORE_LABEL = i18n.translate('xpack.synthetics.monitorManagement.learnMore.label', {
|
||||
defaultMessage: 'Learn more',
|
||||
});
|
||||
|
||||
const GET_API_KEY_GENERATE = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.getProjectAPIKeyLabel.generate',
|
||||
{
|
||||
defaultMessage: 'Generate Project API Key',
|
||||
}
|
||||
);
|
||||
|
||||
const GET_API_KEY_LABEL_DESCRIPTION = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.getAPIKeyLabel.description',
|
||||
{
|
||||
defaultMessage: 'Use an API key to push monitors remotely from a CLI or CD pipeline.',
|
||||
}
|
||||
);
|
||||
|
||||
const API_KEY_DISCLAIMER = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.getAPIKeyLabel.disclaimer',
|
||||
{
|
||||
defaultMessage:
|
||||
'Please note: In order to use push monitors using private testing locations, you must generate this API key with a user who has Fleet and Integrations write permissions.',
|
||||
}
|
||||
);
|
||||
|
||||
const GET_API_KEY_REDUCED_PERMISSIONS_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.getAPIKeyReducedPermissions.description',
|
||||
{
|
||||
defaultMessage:
|
||||
'Use an API key to push monitors remotely from a CLI or CD pipeline. To generate an API key, you must have permissions to manage API keys and Uptime write access. Please contact your administrator.',
|
||||
}
|
||||
);
|
|
@ -8,6 +8,7 @@
|
|||
import React from 'react';
|
||||
import { Redirect, useParams } from 'react-router-dom';
|
||||
import { SettingsTabId } from './page_header';
|
||||
import { ProjectAPIKeys } from './project_api_keys/project_api_keys';
|
||||
import { DataRetentionTab } from './data_retention';
|
||||
import { useSettingsBreadcrumbs } from './use_settings_breadcrumbs';
|
||||
import { ManagePrivateLocations } from './private_locations/manage_private_locations';
|
||||
|
@ -19,6 +20,8 @@ export const SettingsPage = () => {
|
|||
|
||||
const renderTab = () => {
|
||||
switch (tabId) {
|
||||
case 'api-keys':
|
||||
return <ProjectAPIKeys />;
|
||||
case 'private-locations':
|
||||
return <ManagePrivateLocations />;
|
||||
case 'data-retention':
|
||||
|
|
|
@ -28,6 +28,7 @@ export function useEnablement() {
|
|||
return {
|
||||
enablement: {
|
||||
areApiKeysEnabled: enablement?.areApiKeysEnabled,
|
||||
canManageApiKeys: enablement?.canManageApiKeys,
|
||||
canEnable: enablement?.canEnable,
|
||||
isEnabled: enablement?.isEnabled,
|
||||
},
|
||||
|
|
|
@ -40,3 +40,9 @@ export const getMonitorAPI = async ({
|
|||
}): Promise<DecryptedSyntheticsMonitorSavedObject> => {
|
||||
return await apiService.get(`${API_URLS.SYNTHETICS_MONITORS}/${id}`);
|
||||
};
|
||||
|
||||
export const fetchServiceAPIKey = async (): Promise<{
|
||||
apiKey: { encoded: string };
|
||||
}> => {
|
||||
return await apiService.get(API_URLS.SYNTHETICS_APIKEY);
|
||||
};
|
||||
|
|
|
@ -366,3 +366,26 @@ const wrappedInClass = (element: HTMLElement | Element, classWrapper: string): b
|
|||
|
||||
export const forMobileOnly = finderWithClassWrapper('hideForDesktop');
|
||||
export const forDesktopOnly = finderWithClassWrapper('hideForMobile');
|
||||
|
||||
export const makeUptimePermissionsCore = (
|
||||
permissions: Partial<{
|
||||
'alerting:save': boolean;
|
||||
configureSettings: boolean;
|
||||
save: boolean;
|
||||
show: boolean;
|
||||
}>
|
||||
) => {
|
||||
return {
|
||||
application: {
|
||||
capabilities: {
|
||||
uptime: {
|
||||
'alerting:save': true,
|
||||
configureSettings: true,
|
||||
save: true,
|
||||
show: true,
|
||||
...permissions,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue