mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(core): Add documentation hints for API keys to SettingApiView.vue
(no-changelog) (#13617)
This commit is contained in:
parent
4067fb0b12
commit
a7f0c66e30
|
@ -73,10 +73,6 @@ describe('ApiKeyCreateOrEditModal', () => {
|
||||||
getByText('Make sure to copy your API key now as you will not be able to see this again.'),
|
getByText('Make sure to copy your API key now as you will not be able to see this again.'),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
expect(getByText('You can find more details in')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(getByText('the API documentation')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(getByText('Click to copy')).toBeInTheDocument();
|
expect(getByText('Click to copy')).toBeInTheDocument();
|
||||||
|
|
||||||
expect(getByText('new api key')).toBeInTheDocument();
|
expect(getByText('new api key')).toBeInTheDocument();
|
||||||
|
@ -138,10 +134,6 @@ describe('ApiKeyCreateOrEditModal', () => {
|
||||||
getByText('Make sure to copy your API key now as you will not be able to see this again.'),
|
getByText('Make sure to copy your API key now as you will not be able to see this again.'),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
expect(getByText('You can find more details in')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(getByText('the API documentation')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(getByText('Click to copy')).toBeInTheDocument();
|
expect(getByText('Click to copy')).toBeInTheDocument();
|
||||||
|
|
||||||
expect(getByText('new api key')).toBeInTheDocument();
|
expect(getByText('new api key')).toBeInTheDocument();
|
||||||
|
@ -187,10 +179,6 @@ describe('ApiKeyCreateOrEditModal', () => {
|
||||||
getByText('Make sure to copy your API key now as you will not be able to see this again.'),
|
getByText('Make sure to copy your API key now as you will not be able to see this again.'),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
expect(getByText('You can find more details in')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(getByText('the API documentation')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(getByText('Click to copy')).toBeInTheDocument();
|
expect(getByText('Click to copy')).toBeInTheDocument();
|
||||||
|
|
||||||
expect(getByText('new api key')).toBeInTheDocument();
|
expect(getByText('new api key')).toBeInTheDocument();
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Modal from '@/components/Modal.vue';
|
import Modal from '@/components/Modal.vue';
|
||||||
import { API_KEY_CREATE_OR_EDIT_MODAL_KEY, DOCS_DOMAIN } from '@/constants';
|
import { API_KEY_CREATE_OR_EDIT_MODAL_KEY } from '@/constants';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { createEventBus } from '@n8n/utils/event-bus';
|
import { createEventBus } from '@n8n/utils/event-bus';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
|
||||||
import { useRootStore } from '@/stores/root.store';
|
import { useRootStore } from '@/stores/root.store';
|
||||||
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useApiKeysStore } from '@/stores/apiKeys.store';
|
import { useApiKeysStore } from '@/stores/apiKeys.store';
|
||||||
|
@ -29,17 +28,13 @@ const { showError, showMessage } = useToast();
|
||||||
|
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const { isSwaggerUIEnabled, publicApiPath, publicApiLatestVersion } = settingsStore;
|
|
||||||
const { createApiKey, updateApiKey, apiKeysById } = useApiKeysStore();
|
const { createApiKey, updateApiKey, apiKeysById } = useApiKeysStore();
|
||||||
const { baseUrl } = useRootStore();
|
|
||||||
const documentTitle = useDocumentTitle();
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const label = ref('');
|
const label = ref('');
|
||||||
const expirationDaysFromNow = ref(EXPIRATION_OPTIONS['30_DAYS']);
|
const expirationDaysFromNow = ref(EXPIRATION_OPTIONS['30_DAYS']);
|
||||||
const modalBus = createEventBus();
|
const modalBus = createEventBus();
|
||||||
const newApiKey = ref<ApiKeyWithRawValue | null>(null);
|
const newApiKey = ref<ApiKeyWithRawValue | null>(null);
|
||||||
const apiDocsURL = ref('');
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const rawApiKey = ref('');
|
const rawApiKey = ref('');
|
||||||
const customExpirationDate = ref('');
|
const customExpirationDate = ref('');
|
||||||
|
@ -110,10 +105,6 @@ onMounted(() => {
|
||||||
label.value = apiKey.label ?? '';
|
label.value = apiKey.label ?? '';
|
||||||
apiKeyCreationDate.value = getApiKeyCreationTime(apiKey);
|
apiKeyCreationDate.value = getApiKeyCreationTime(apiKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
apiDocsURL.value = isSwaggerUIEnabled
|
|
||||||
? `${baseUrl}${publicApiPath}/v${publicApiLatestVersion}/docs`
|
|
||||||
: `https://${DOCS_DOMAIN}/api/api-reference/`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function onInput(value: string): void {
|
function onInput(value: string): void {
|
||||||
|
@ -222,26 +213,6 @@ const onSelect = (value: number) => {
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div>
|
<div>
|
||||||
<p v-if="newApiKey" class="mb-s">
|
|
||||||
<n8n-info-tip :bold="false">
|
|
||||||
<i18n-t keypath="settings.api.view.info" tag="span">
|
|
||||||
<template #apiAction>
|
|
||||||
<a
|
|
||||||
href="https://docs.n8n.io/api"
|
|
||||||
target="_blank"
|
|
||||||
v-text="i18n.baseText('settings.api.view.info.api')"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #webhookAction>
|
|
||||||
<a
|
|
||||||
href="https://docs.n8n.io/integrations/core-nodes/n8n-nodes-base.webhook/"
|
|
||||||
target="_blank"
|
|
||||||
v-text="i18n.baseText('settings.api.view.info.webhook')"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</n8n-info-tip>
|
|
||||||
</p>
|
|
||||||
<n8n-card v-if="newApiKey" class="mb-4xs">
|
<n8n-card v-if="newApiKey" class="mb-4xs">
|
||||||
<CopyInput
|
<CopyInput
|
||||||
:label="newApiKey.label"
|
:label="newApiKey.label"
|
||||||
|
@ -253,23 +224,6 @@ const onSelect = (value: number) => {
|
||||||
/>
|
/>
|
||||||
</n8n-card>
|
</n8n-card>
|
||||||
|
|
||||||
<div v-if="newApiKey" :class="$style.hint">
|
|
||||||
<N8nText size="small">
|
|
||||||
{{
|
|
||||||
i18n.baseText(
|
|
||||||
`settings.api.view.${settingsStore.isSwaggerUIEnabled ? 'tryapi' : 'more-details'}`,
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</N8nText>
|
|
||||||
{{ ' ' }}
|
|
||||||
<n8n-link :to="apiDocsURL" :new-window="true" size="small">
|
|
||||||
{{
|
|
||||||
i18n.baseText(
|
|
||||||
`settings.api.view.${isSwaggerUIEnabled ? 'apiPlayground' : 'external-docs'}`,
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</n8n-link>
|
|
||||||
</div>
|
|
||||||
<div v-else :class="$style.form">
|
<div v-else :class="$style.form">
|
||||||
<N8nInputLabel
|
<N8nInputLabel
|
||||||
:label="i18n.baseText('settings.api.view.modal.form.label')"
|
:label="i18n.baseText('settings.api.view.modal.form.label')"
|
||||||
|
@ -362,11 +316,6 @@ const onSelect = (value: number) => {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hint {
|
|
||||||
color: var(--color-text-light);
|
|
||||||
margin-bottom: var(--spacing-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form {
|
.form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -9,12 +9,51 @@ import { setActivePinia } from 'pinia';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import { useApiKeysStore } from '@/stores/apiKeys.store';
|
import { useApiKeysStore } from '@/stores/apiKeys.store';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
import { useRootStore } from '@/stores/root.store';
|
||||||
|
|
||||||
setActivePinia(createTestingPinia());
|
setActivePinia(createTestingPinia());
|
||||||
|
|
||||||
const settingsStore = mockedStore(useSettingsStore);
|
const settingsStore = mockedStore(useSettingsStore);
|
||||||
const cloudStore = mockedStore(useCloudPlanStore);
|
const cloudStore = mockedStore(useCloudPlanStore);
|
||||||
const apiKeysStore = mockedStore(useApiKeysStore);
|
const apiKeysStore = mockedStore(useApiKeysStore);
|
||||||
|
const rootStore = mockedStore(useRootStore);
|
||||||
|
|
||||||
|
const assertHintsAreShown = ({ isSwaggerUIEnabled }: { isSwaggerUIEnabled: boolean }) => {
|
||||||
|
const apiDocsLink = screen.getByTestId('api-docs-link');
|
||||||
|
expect(apiDocsLink).toBeInTheDocument();
|
||||||
|
expect(apiDocsLink).toHaveAttribute('href', 'https://docs.n8n.io/api');
|
||||||
|
expect(apiDocsLink).toHaveAttribute('target', '_blank');
|
||||||
|
|
||||||
|
const webhookDocsLink = screen.getByTestId('webhook-docs-link');
|
||||||
|
expect(webhookDocsLink).toBeInTheDocument();
|
||||||
|
expect(webhookDocsLink).toHaveAttribute(
|
||||||
|
'href',
|
||||||
|
'https://docs.n8n.io/integrations/core-nodes/n8n-nodes-base.webhook/',
|
||||||
|
);
|
||||||
|
expect(webhookDocsLink).toHaveAttribute('target', '_blank');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.getByText('Use your API Key to control n8n programmatically using the', {
|
||||||
|
exact: false,
|
||||||
|
}),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.getByText('. But if you only want to trigger workflows, consider using the', {
|
||||||
|
exact: false,
|
||||||
|
}),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByText('instead.', { exact: false })).toBeInTheDocument();
|
||||||
|
|
||||||
|
if (isSwaggerUIEnabled) {
|
||||||
|
expect(screen.getByText('Try it out using the')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('API Playground')).toBeInTheDocument();
|
||||||
|
} else {
|
||||||
|
expect(screen.getByText('You can find more details in')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('the API documentation')).toBeInTheDocument();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
describe('SettingsApiView', () => {
|
describe('SettingsApiView', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -50,11 +89,15 @@ describe('SettingsApiView', () => {
|
||||||
expect(screen.getByText('n8n API')).toBeInTheDocument();
|
expect(screen.getByText('n8n API')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('if user public api enabled and there are API Keys in account, they should be rendered', async () => {
|
it('if user public api enabled, swagger enabled, and there are API Keys in account, they should be rendered', async () => {
|
||||||
const dateInTheFuture = DateTime.now().plus({ days: 1 });
|
const dateInTheFuture = DateTime.now().plus({ days: 1 });
|
||||||
const dateInThePast = DateTime.now().minus({ days: 1 });
|
const dateInThePast = DateTime.now().minus({ days: 1 });
|
||||||
|
|
||||||
|
rootStore.baseUrl = 'http://localhost:5678';
|
||||||
|
settingsStore.publicApiPath = '/api';
|
||||||
|
settingsStore.publicApiLatestVersion = 1;
|
||||||
settingsStore.isPublicApiEnabled = true;
|
settingsStore.isPublicApiEnabled = true;
|
||||||
|
settingsStore.isSwaggerUIEnabled = true;
|
||||||
cloudStore.userIsTrialing = false;
|
cloudStore.userIsTrialing = false;
|
||||||
apiKeysStore.apiKeys = [
|
apiKeysStore.apiKeys = [
|
||||||
{
|
{
|
||||||
|
@ -98,6 +141,64 @@ describe('SettingsApiView', () => {
|
||||||
expect(screen.getByText('This API key has expired')).toBeInTheDocument();
|
expect(screen.getByText('This API key has expired')).toBeInTheDocument();
|
||||||
expect(screen.getByText('****Wtcr')).toBeInTheDocument();
|
expect(screen.getByText('****Wtcr')).toBeInTheDocument();
|
||||||
expect(screen.getByText('test-key-3')).toBeInTheDocument();
|
expect(screen.getByText('test-key-3')).toBeInTheDocument();
|
||||||
|
|
||||||
|
assertHintsAreShown({ isSwaggerUIEnabled: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('if user public api enabled, swagger disabled and there are API Keys in account, they should be rendered', async () => {
|
||||||
|
const dateInTheFuture = DateTime.now().plus({ days: 1 });
|
||||||
|
const dateInThePast = DateTime.now().minus({ days: 1 });
|
||||||
|
|
||||||
|
rootStore.baseUrl = 'http://localhost:5678';
|
||||||
|
settingsStore.publicApiPath = '/api';
|
||||||
|
settingsStore.publicApiLatestVersion = 1;
|
||||||
|
settingsStore.isPublicApiEnabled = true;
|
||||||
|
settingsStore.isSwaggerUIEnabled = false;
|
||||||
|
cloudStore.userIsTrialing = false;
|
||||||
|
apiKeysStore.apiKeys = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
label: 'test-key-1',
|
||||||
|
createdAt: new Date().toString(),
|
||||||
|
updatedAt: new Date().toString(),
|
||||||
|
apiKey: '****Atcr',
|
||||||
|
expiresAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
label: 'test-key-2',
|
||||||
|
createdAt: new Date().toString(),
|
||||||
|
updatedAt: new Date().toString(),
|
||||||
|
apiKey: '****Bdcr',
|
||||||
|
expiresAt: dateInTheFuture.toSeconds(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
label: 'test-key-3',
|
||||||
|
createdAt: new Date().toString(),
|
||||||
|
updatedAt: new Date().toString(),
|
||||||
|
apiKey: '****Wtcr',
|
||||||
|
expiresAt: dateInThePast.toSeconds(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
renderComponent(SettingsApiView);
|
||||||
|
|
||||||
|
expect(screen.getByText('Never expires')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('****Atcr')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('test-key-1')).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.getByText(`Expires on ${dateInTheFuture.toFormat('ccc, MMM d yyyy')}`),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('****Bdcr')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('test-key-2')).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByText('This API key has expired')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('****Wtcr')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('test-key-3')).toBeInTheDocument();
|
||||||
|
|
||||||
|
assertHintsAreShown({ isSwaggerUIEnabled: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show delete warning when trying to delete an API key', async () => {
|
it('should show delete warning when trying to delete an API key', async () => {
|
||||||
|
|
|
@ -6,13 +6,14 @@ import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
||||||
import { API_KEY_CREATE_OR_EDIT_MODAL_KEY, MODAL_CONFIRM } from '@/constants';
|
import { API_KEY_CREATE_OR_EDIT_MODAL_KEY, DOCS_DOMAIN, MODAL_CONFIRM } from '@/constants';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
|
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useApiKeysStore } from '@/stores/apiKeys.store';
|
import { useApiKeysStore } from '@/stores/apiKeys.store';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useRootStore } from '@/stores/root.store';
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
@ -29,9 +30,13 @@ const loading = ref(false);
|
||||||
const apiKeysStore = useApiKeysStore();
|
const apiKeysStore = useApiKeysStore();
|
||||||
const { getAndCacheApiKeys, deleteApiKey } = apiKeysStore;
|
const { getAndCacheApiKeys, deleteApiKey } = apiKeysStore;
|
||||||
const { apiKeysSortByCreationDate } = storeToRefs(apiKeysStore);
|
const { apiKeysSortByCreationDate } = storeToRefs(apiKeysStore);
|
||||||
|
const { isSwaggerUIEnabled, publicApiPath, publicApiLatestVersion } = settingsStore;
|
||||||
|
const { baseUrl } = useRootStore();
|
||||||
|
|
||||||
const { isPublicApiEnabled } = settingsStore;
|
const { isPublicApiEnabled } = settingsStore;
|
||||||
|
|
||||||
|
const apiDocsURL = ref('');
|
||||||
|
|
||||||
const onCreateApiKey = async () => {
|
const onCreateApiKey = async () => {
|
||||||
telemetry.track('User clicked create API key button');
|
telemetry.track('User clicked create API key button');
|
||||||
|
|
||||||
|
@ -44,6 +49,10 @@ const onCreateApiKey = async () => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
documentTitle.set(i18n.baseText('settings.api'));
|
documentTitle.set(i18n.baseText('settings.api'));
|
||||||
|
|
||||||
|
apiDocsURL.value = isSwaggerUIEnabled
|
||||||
|
? `${baseUrl}${publicApiPath}/v${publicApiLatestVersion}/docs`
|
||||||
|
: `https://${DOCS_DOMAIN}/api/api-reference/`;
|
||||||
|
|
||||||
if (!isPublicApiEnabled) return;
|
if (!isPublicApiEnabled) return;
|
||||||
|
|
||||||
await getApiKeys();
|
await getApiKeys();
|
||||||
|
@ -107,6 +116,28 @@ function onEdit(id: string) {
|
||||||
</span>
|
</span>
|
||||||
</n8n-heading>
|
</n8n-heading>
|
||||||
</div>
|
</div>
|
||||||
|
<p v-if="isPublicApiEnabled && apiKeysSortByCreationDate.length" :class="$style.topHint">
|
||||||
|
<n8n-text>
|
||||||
|
<i18n-t keypath="settings.api.view.info" tag="span">
|
||||||
|
<template #apiAction>
|
||||||
|
<a
|
||||||
|
data-test-id="api-docs-link"
|
||||||
|
href="https://docs.n8n.io/api"
|
||||||
|
target="_blank"
|
||||||
|
v-text="i18n.baseText('settings.api.view.info.api')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #webhookAction>
|
||||||
|
<a
|
||||||
|
data-test-id="webhook-docs-link"
|
||||||
|
href="https://docs.n8n.io/integrations/core-nodes/n8n-nodes-base.webhook/"
|
||||||
|
target="_blank"
|
||||||
|
v-text="i18n.baseText('settings.api.view.info.webhook')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</n8n-text>
|
||||||
|
</p>
|
||||||
<template v-if="apiKeysSortByCreationDate.length">
|
<template v-if="apiKeysSortByCreationDate.length">
|
||||||
<el-row
|
<el-row
|
||||||
v-for="apiKey in apiKeysSortByCreationDate"
|
v-for="apiKey in apiKeysSortByCreationDate"
|
||||||
|
@ -119,6 +150,34 @@ function onEdit(id: string) {
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<div v-if="isPublicApiEnabled && apiKeysSortByCreationDate.length" :class="$style.BottomHint">
|
||||||
|
<N8nText size="small" color="text-light">
|
||||||
|
{{
|
||||||
|
i18n.baseText(
|
||||||
|
`settings.api.view.${settingsStore.isSwaggerUIEnabled ? 'tryapi' : 'more-details'}`,
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</N8nText>
|
||||||
|
{{ ' ' }}
|
||||||
|
<n8n-link
|
||||||
|
v-if="isSwaggerUIEnabled"
|
||||||
|
data-test-id="api-playground-link"
|
||||||
|
:to="apiDocsURL"
|
||||||
|
:new-window="true"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ i18n.baseText('settings.api.view.apiPlayground') }}
|
||||||
|
</n8n-link>
|
||||||
|
<n8n-link
|
||||||
|
v-else
|
||||||
|
data-test-id="api-endpoint-docs-link"
|
||||||
|
:to="apiDocsURL"
|
||||||
|
:new-window="true"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ i18n.baseText(`settings.api.view.external-docs`) }}
|
||||||
|
</n8n-link>
|
||||||
|
</div>
|
||||||
<div class="mt-m text-right">
|
<div class="mt-m text-right">
|
||||||
<n8n-button
|
<n8n-button
|
||||||
size="large"
|
size="large"
|
||||||
|
@ -138,6 +197,7 @@ function onEdit(id: string) {
|
||||||
:button-text="i18n.baseText('settings.api.trial.upgradePlan.cta')"
|
:button-text="i18n.baseText('settings.api.trial.upgradePlan.cta')"
|
||||||
@click:button="onUpgrade"
|
@click:button="onUpgrade"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<n8n-action-box
|
<n8n-action-box
|
||||||
v-if="isPublicApiEnabled && !apiKeysSortByCreationDate.length"
|
v-if="isPublicApiEnabled && !apiKeysSortByCreationDate.length"
|
||||||
:button-text="
|
:button-text="
|
||||||
|
@ -154,7 +214,7 @@ function onEdit(id: string) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin-bottom: var(--spacing-2xl);
|
margin-bottom: var(--spacing-xl);
|
||||||
|
|
||||||
*:first-child {
|
*:first-child {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
@ -176,7 +236,19 @@ function onEdit(id: string) {
|
||||||
right: var(--spacing-s);
|
right: var(--spacing-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hint {
|
.topHint {
|
||||||
|
margin-top: none;
|
||||||
|
margin-bottom: var(--spacing-s);
|
||||||
color: var(--color-text-light);
|
color: var(--color-text-light);
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
line-height: var(--font-line-height-loose);
|
||||||
|
font-weight: var(--font-weight-regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.BottomHint {
|
||||||
|
margin-bottom: var(--spacing-s);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue