Commit 8feaef63 authored by Anna Vovchenko's avatar Anna Vovchenko Committed by Natalia Tepluhina

Agent Activity Information - Frontend

parent 4831b598
<script>
import { GlLoadingIcon, GlEmptyState, GlLink, GlIcon, GlAlert } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { n__, s__, __ } from '~/locale';
import { formatDate, getDayDifference, isToday } from '~/lib/utils/datetime_utility';
import { EVENTS_STORED_DAYS } from '../constants';
import getAgentActivityEventsQuery from '../graphql/queries/get_agent_activity_events.query.graphql';
import ActivityHistoryItem from './activity_history_item.vue';
export default {
components: {
GlLoadingIcon,
GlEmptyState,
GlAlert,
GlLink,
GlIcon,
ActivityHistoryItem,
},
i18n: {
emptyText: s__(
'ClusterAgents|See Agent activity updates such as tokens created or revoked and clusters connected or not connected.',
),
error: s__(
'ClusterAgents|An error occurred while retrieving GitLab Agent activity. Reload the page to try again.',
),
today: __('Today'),
yesterday: __('Yesterday'),
},
emptyHelpLink: helpPagePath('user/clusters/agent/install/index', {
anchor: 'view-agent-activity',
}),
borderClasses: 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100',
apollo: {
agentEvents: {
query: getAgentActivityEventsQuery,
variables() {
return {
agentName: this.agentName,
projectPath: this.projectPath,
};
},
update: (data) => data?.project?.clusterAgent?.activityEvents?.nodes,
error() {
this.isError = true;
},
},
},
inject: ['agentName', 'projectPath', 'activityEmptyStateImage'],
data() {
return {
isError: false,
};
},
computed: {
isLoading() {
return this.$apollo.queries.agentEvents?.loading;
},
emptyStateTitle() {
return n__(
"ClusterAgents|There's no activity from the past day",
"ClusterAgents|There's no activity from the past %d days",
EVENTS_STORED_DAYS,
);
},
eventsList() {
const list = this.agentEvents;
const listByDates = {};
if (!list?.length) {
return listByDates;
}
list.forEach((event) => {
const dateName = this.getFormattedDate(event.recordedAt);
if (!listByDates[dateName]) {
listByDates[dateName] = [];
}
listByDates[dateName].push(event);
});
return listByDates;
},
hasEvents() {
return Object.keys(this.eventsList).length;
},
},
methods: {
isYesterday(date) {
const today = new Date();
return getDayDifference(today, date) === -1;
},
getFormattedDate(dateString) {
const date = new Date(dateString);
let dateName;
if (isToday(date)) {
dateName = this.$options.i18n.today;
} else if (this.isYesterday(date)) {
dateName = this.$options.i18n.yesterday;
} else {
dateName = formatDate(date, 'yyyy-mm-dd');
}
return dateName;
},
isLast(dateEvents, idx) {
return idx === dateEvents.length - 1;
},
getBodyClasses(dateEvents, idx) {
return !this.isLast(dateEvents, idx) ? this.$options.borderClasses : '';
},
},
};
</script>
<template>
<div>
<gl-loading-icon v-if="isLoading" size="md" />
<div v-else-if="hasEvents">
<div
v-for="(dateEvents, key) in eventsList"
:key="key"
class="agent-activity-list issuable-discussion"
>
<h4
class="gl-pb-4 gl-ml-5"
:class="$options.borderClasses"
data-testid="activity-section-title"
>
{{ key }}
</h4>
<ul class="notes main-notes-list timeline">
<activity-history-item
v-for="(event, idx) in dateEvents"
:key="idx"
:event="event"
:body-class="getBodyClasses(dateEvents, idx)"
/>
</ul>
</div>
</div>
<gl-alert v-else-if="isError" variant="danger" :dismissible="false" class="gl-mt-3">
{{ $options.i18n.error }}
</gl-alert>
<gl-empty-state
v-else
:title="emptyStateTitle"
:svg-path="activityEmptyStateImage"
:svg-height="150"
>
<template #description>
<div>
<span>{{ $options.i18n.emptyText }}</span>
<gl-link :href="$options.emptyHelpLink"><gl-icon name="question" :size="14" /></gl-link>
</div>
</template>
</gl-empty-state>
</div>
</template>
<script>
import { GlLink, GlIcon, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
import { EVENT_DETAILS, DEFAULT_ICON } from '../constants';
export default {
i18n: {
defaultBodyText: s__('ClusterAgents|Event occurred'),
},
components: {
GlLink,
GlIcon,
GlSprintf,
TimeAgoTooltip,
HistoryItem,
},
props: {
event: {
required: true,
type: Object,
},
bodyClass: {
required: false,
default: '',
type: String,
},
},
computed: {
eventDetails() {
const defaultEvent = {
eventTypeIcon: DEFAULT_ICON,
title: this.event.kind,
body: this.$options.i18n.defaultBodyText,
};
const eventDetails = EVENT_DETAILS[this.event.kind] || defaultEvent;
const { eventTypeIcon, title, body, titleIcon } = eventDetails;
const resultEvent = { ...this.event, eventTypeIcon, title, body, titleIcon };
return resultEvent;
},
},
};
</script>
<template>
<history-item :icon="eventDetails.eventTypeIcon" class="gl-my-0! gl-pr-0!">
<strong>
<gl-sprintf :message="eventDetails.title"
><template v-if="eventDetails.titleIcon" #titleIcon
><gl-icon
class="gl-mr-2"
:name="eventDetails.titleIcon.name"
:size="12"
:class="eventDetails.titleIcon.class"
/>
</template>
<template #tokenName>{{ eventDetails.agentToken.name }}</template></gl-sprintf
>
</strong>
<template #body>
<p class="gl-mt-2 gl-mb-0 gl-pb-2" :class="bodyClass">
<gl-sprintf :message="eventDetails.body">
<template #userName>
<strong>{{ eventDetails.user.name }}</strong>
<gl-link :href="eventDetails.user.webUrl">@{{ eventDetails.user.username }}</gl-link>
</template>
<template #strong="{ content }">
<strong> {{ content }} </strong>
</template>
</gl-sprintf>
<time-ago-tooltip :time="eventDetails.recordedAt" />
</p>
</template>
</history-item>
</template>
......@@ -8,11 +8,12 @@ import {
GlTab,
GlTabs,
} from '@gitlab/ui';
import { s__ } from '~/locale';
import { s__, __ } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { MAX_LIST_COUNT } from '../constants';
import getClusterAgentQuery from '../graphql/queries/get_cluster_agent.query.graphql';
import TokenTable from './token_table.vue';
import ActivityEvents from './activity_events_list.vue';
export default {
i18n: {
......@@ -20,6 +21,7 @@ export default {
loadingError: s__('ClusterAgents|An error occurred while loading your agent'),
tokens: s__('ClusterAgents|Access tokens'),
unknownUser: s__('ClusterAgents|Unknown user'),
activity: __('Activity'),
},
apollo: {
clusterAgent: {
......@@ -47,6 +49,7 @@ export default {
GlTabs,
TimeAgoTooltip,
TokenTable,
ActivityEvents,
},
props: {
agentName: {
......@@ -127,9 +130,14 @@ export default {
</gl-sprintf>
</p>
<gl-tabs>
<gl-tabs sync-active-tab-with-query-params lazy>
<gl-tab :title="$options.i18n.activity" query-param-value="activity">
<activity-events :agent-name="agentName" :project-path="projectPath" />
</gl-tab>
<slot name="ee-security-tab"></slot>
<gl-tab>
<gl-tab query-param-value="tokens">
<template #title>
<span data-testid="cluster-agent-token-count">
{{ $options.i18n.tokens }}
......@@ -143,7 +151,7 @@ export default {
<gl-loading-icon v-if="isLoading" size="md" class="gl-m-3" />
<div v-else>
<TokenTable :tokens="tokens" />
<token-table :tokens="tokens" />
<div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5">
<gl-keyset-pagination v-bind="tokenPageInfo" @prev="prevPage" @next="nextPage" />
......
......@@ -83,7 +83,14 @@ export default {
</gl-link>
</div>
<gl-table :items="tokens" :fields="fields" fixed stacked="md">
<gl-table
:items="tokens"
:fields="fields"
fixed
stacked="md"
head-variant="white"
thead-class="gl-border-b-solid gl-border-b-2 gl-border-b-gray-100"
>
<template #cell(lastUsed)="{ item }">
<time-ago-tooltip v-if="item.lastUsedAt" :time="item.lastUsedAt" />
<span v-else>{{ $options.i18n.neverUsed }}</span>
......
import { s__ } from '~/locale';
export const MAX_LIST_COUNT = 25;
export const EVENTS_STORED_DAYS = 7;
export const EVENT_DETAILS = {
token_created: {
eventTypeIcon: 'token',
title: s__('ClusterAgents|%{tokenName} created'),
body: s__('ClusterAgents|Token created by %{userName}'),
},
token_revoked: {
eventTypeIcon: 'token',
title: s__('ClusterAgents|%{tokenName} revoked'),
body: s__('ClusterAgents|Token revoked by %{userName}'),
},
agent_connected: {
eventTypeIcon: 'connected',
title: s__('ClusterAgents|%{titleIcon}Connected'),
body: s__('ClusterAgents|Agent %{strongStart}connected%{strongEnd}'),
titleIcon: {
name: 'status-success',
class: 'text-success-500',
},
},
agent_disconnected: {
eventTypeIcon: 'connected',
title: s__('ClusterAgents|%{titleIcon}Not connected'),
body: s__('ClusterAgents|Agent %{strongStart}disconnected%{strongEnd}'),
titleIcon: {
name: 'severity-critical',
class: 'text-danger-800',
},
},
};
export const DEFAULT_ICON = 'token';
query getAgentActivityEvents($projectPath: ID!, $agentName: String!) {
project(fullPath: $projectPath) {
id
clusterAgent(name: $agentName) {
id
activityEvents {
nodes {
kind
level
recordedAt
agentToken {
id
name
}
user {
id
name
username
webUrl
}
}
}
}
}
}
......@@ -13,11 +13,12 @@ export default () => {
}
const defaultClient = createDefaultClient();
const { agentName, projectPath } = el.dataset;
const { agentName, projectPath, activityEmptyStateImage } = el.dataset;
return new Vue({
el,
apolloProvider: new VueApollo({ defaultClient }),
provide: { agentName, projectPath, activityEmptyStateImage },
render(createElement) {
return createElement(AgentShowPage, {
props: {
......
......@@ -26,3 +26,15 @@
}
}
}
.agent-activity-list {
.system-note .timeline-entry-inner {
.timeline-icon {
@include gl-mt-1;
}
}
&.issuable-discussion .main-notes-list::before {
@include gl-top-3;
}
}
......@@ -4,7 +4,8 @@ module Projects::ClusterAgentsHelper
def js_cluster_agent_details_data(agent_name, project)
{
agent_name: agent_name,
project_path: project.full_path
project_path: project.full_path,
activity_empty_state_image: image_path('illustrations/empty-state/empty-state-agents.svg')
}
end
end
......@@ -354,6 +354,32 @@ and the configuration directory for each agent:
Additional management interfaces are planned for the GitLab Agent.
[Provide more feedback in the related epic](https://gitlab.com/groups/gitlab-org/-/epics/4739).
## View Agent activity information
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/277323) in GitLab 14.6.
Users with at least the [Developer](../../../permissions.md) can view the Agent's activity events.
The activity logs help you to identify problems and get the information you need for troubleshooting.
You can see events from a week before the current date.
To access an agent's activity:
1. Go to your agent's configuration repository.
1. From the sidebar, select **Infrastructure > Kubernetes clusters**.
1. Select the **Agent** tab.
1. Select the agent you want to see the activity.
You can see the following events on the activity list:
- Agent registration:
- When a new token is **created**.
- Connection events:
- When an agent is successfully **connected** to a cluster.
Note that the connection status is logged when you connect an agent for the first time
or after more than an hour of inactivity.
![GitLab Agent activity events UI](../../img/gitlab_agent_activity_events_v14_6.png)
## Upgrades and version compatibility
The Agent is comprised of two major components: `agentk` and `kas`.
......
......@@ -7452,6 +7452,18 @@ msgstr ""
msgid "ClusterAgents|%{number} of %{total} clusters connected through cluster certificates"
msgstr ""
msgid "ClusterAgents|%{titleIcon}Connected"
msgstr ""
msgid "ClusterAgents|%{titleIcon}Not connected"
msgstr ""
msgid "ClusterAgents|%{tokenName} created"
msgstr ""
msgid "ClusterAgents|%{tokenName} revoked"
msgstr ""
msgid "ClusterAgents|Access tokens"
msgstr ""
......@@ -7464,6 +7476,12 @@ msgstr ""
msgid "ClusterAgents|Agent"
msgstr ""
msgid "ClusterAgents|Agent %{strongStart}connected%{strongEnd}"
msgstr ""
msgid "ClusterAgents|Agent %{strongStart}disconnected%{strongEnd}"
msgstr ""
msgid "ClusterAgents|Agent might not be connected to GitLab"
msgstr ""
......@@ -7479,6 +7497,9 @@ msgstr ""
msgid "ClusterAgents|An error occurred while loading your agent"
msgstr ""
msgid "ClusterAgents|An error occurred while retrieving GitLab Agent activity. Reload the page to try again."
msgstr ""
msgid "ClusterAgents|An unknown error occurred. Please try again."
msgstr ""
......@@ -7533,6 +7554,9 @@ msgstr ""
msgid "ClusterAgents|Description"
msgstr ""
msgid "ClusterAgents|Event occurred"
msgstr ""
msgid "ClusterAgents|Failed to register an agent"
msgstr ""
......@@ -7608,6 +7632,9 @@ msgstr ""
msgid "ClusterAgents|Security"
msgstr ""
msgid "ClusterAgents|See Agent activity updates such as tokens created or revoked and clusters connected or not connected."
msgstr ""
msgid "ClusterAgents|Select an agent"
msgstr ""
......@@ -7626,12 +7653,23 @@ msgstr ""
msgid "ClusterAgents|The registration token will be used to connect the agent on your cluster to GitLab. %{linkStart}What are registration tokens?%{linkEnd}"
msgstr ""
msgid "ClusterAgents|There's no activity from the past day"
msgid_plural "ClusterAgents|There's no activity from the past %d days"
msgstr[0] ""
msgstr[1] ""
msgid "ClusterAgents|This agent has no tokens"
msgstr ""
msgid "ClusterAgents|To install a new agent, first add the agent's configuration file to this repository. %{linkStart}What's the agent's configuration file?%{linkEnd}"
msgstr ""
msgid "ClusterAgents|Token created by %{userName}"
msgstr ""
msgid "ClusterAgents|Token revoked by %{userName}"
msgstr ""
msgid "ClusterAgents|Unknown user"
msgstr ""
......
......@@ -44,8 +44,17 @@ RSpec.describe 'ClusterAgents', :js do
visit project_cluster_agent_path(project, agent.name)
end
it 'displays agent and token information', :aggregate_failures do
it 'displays agent information', :aggregate_failures do
expect(page).to have_content(agent.name)
end
it 'displays agent activity tab', :aggregate_failures do
expect(page).to have_content('Activity')
end
it 'displays agent tokens tab', :aggregate_failures do
expect(page).to have_content('Access tokens')
click_link 'Access tokens'
expect(page).to have_content(token.description)
end
end
......
import { GlLoadingIcon, GlAlert, GlEmptyState } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { useFakeDate } from 'helpers/fake_date';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import ActivityEvents from '~/clusters/agents/components/activity_events_list.vue';
import ActivityHistoryItem from '~/clusters/agents/components/activity_history_item.vue';
import getAgentActivityEventsQuery from '~/clusters/agents/graphql/queries/get_agent_activity_events.query.graphql';
import { mockResponse, mockEmptyResponse } from '../../mock_data';
const activityEmptyStateImage = '/path/to/image';
const projectPath = 'path/to/project';
const agentName = 'cluster-agent';
Vue.use(VueApollo);
describe('ActivityEvents', () => {
let wrapper;
useFakeDate([2021, 12, 3]);
const provideData = {
agentName,
projectPath,
activityEmptyStateImage,
};
const createWrapper = ({ queryResponse = null } = {}) => {
const agentEventsQueryResponse = queryResponse || jest.fn().mockResolvedValue(mockResponse);
const apolloProvider = createMockApollo([
[getAgentActivityEventsQuery, agentEventsQueryResponse],
]);
wrapper = shallowMountExtended(ActivityEvents, {
apolloProvider,
provide: provideData,
});
};
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findAlert = () => wrapper.findComponent(GlAlert);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findAllActivityHistoryItems = () => wrapper.findAllComponents(ActivityHistoryItem);
const findSectionTitle = (at) => wrapper.findAllByTestId('activity-section-title').at(at);
afterEach(() => {
wrapper.destroy();
});
describe('while the agentEvents query is loading', () => {
it('displays a loading icon', async () => {
createWrapper();
expect(findLoadingIcon().exists()).toBe(true);
await waitForPromises();
expect(findLoadingIcon().exists()).toBe(false);
});
});
describe('when the agentEvents query has errored', () => {
beforeEach(() => {
createWrapper({ queryResponse: jest.fn().mockRejectedValue() });
return waitForPromises();
});
it('displays an alert message', () => {
expect(findAlert().exists()).toBe(true);
});
});
describe('when there are no agentEvents', () => {
beforeEach(() => {
createWrapper({ queryResponse: jest.fn().mockResolvedValue(mockEmptyResponse) });
});
it('displays an empty state with the correct illustration', () => {
expect(findEmptyState().exists()).toBe(true);
expect(findEmptyState().props('svgPath')).toBe(activityEmptyStateImage);
});
});
describe('when the agentEvents are present', () => {
const length = mockResponse.data?.project?.clusterAgent?.activityEvents?.nodes?.length;
beforeEach(() => {
createWrapper();
});
it('renders an activity-history-item components for every event', () => {
expect(findAllActivityHistoryItems()).toHaveLength(length);
});
it.each`
recordedAt | date | lineNumber
${'2021-12-03T01:06:56Z'} | ${'Today'} | ${0}
${'2021-12-02T19:26:56Z'} | ${'Yesterday'} | ${1}
${'2021-11-22T19:26:56Z'} | ${'2021-11-22'} | ${2}
`('renders correct titles for different days', ({ date, lineNumber }) => {
expect(findSectionTitle(lineNumber).text()).toBe(date);
});
});
});
import { GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { sprintf } from '~/locale';
import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import ActivityHistoryItem from '~/clusters/agents/components/activity_history_item.vue';
import { EVENT_DETAILS, DEFAULT_ICON } from '~/clusters/agents/constants';
import { mockAgentHistoryActivityItems } from '../../mock_data';
const agentName = 'cluster-agent';
describe('ActivityHistoryItem', () => {
let wrapper;
const createWrapper = ({ event = {} }) => {
wrapper = shallowMount(ActivityHistoryItem, {
propsData: { event },
stubs: {
HistoryItem,
GlSprintf,
},
});
};
const findHistoryItem = () => wrapper.findComponent(HistoryItem);
const findTimeAgo = () => wrapper.find(TimeAgoTooltip);
afterEach(() => {
wrapper.destroy();
});
describe.each`
kind | icon | title | lineNumber
${'token_created'} | ${EVENT_DETAILS.token_created.eventTypeIcon} | ${sprintf(EVENT_DETAILS.token_created.title, { tokenName: agentName })} | ${0}
${'token_revoked'} | ${EVENT_DETAILS.token_revoked.eventTypeIcon} | ${sprintf(EVENT_DETAILS.token_revoked.title, { tokenName: agentName })} | ${1}
${'agent_connected'} | ${EVENT_DETAILS.agent_connected.eventTypeIcon} | ${sprintf(EVENT_DETAILS.agent_connected.title, { titleIcon: '' })} | ${2}
${'agent_disconnected'} | ${EVENT_DETAILS.agent_disconnected.eventTypeIcon} | ${sprintf(EVENT_DETAILS.agent_disconnected.title, { titleIcon: '' })} | ${3}
${'agent_connected'} | ${EVENT_DETAILS.agent_connected.eventTypeIcon} | ${sprintf(EVENT_DETAILS.agent_connected.title, { titleIcon: '' })} | ${4}
${'unknown_agent'} | ${DEFAULT_ICON} | ${'unknown_agent Event occurred'} | ${5}
`('when the event type is $kind event', ({ icon, title, lineNumber }) => {
beforeEach(() => {
const event = mockAgentHistoryActivityItems[lineNumber];
createWrapper({ event });
});
it('renders the correct icon', () => {
expect(findHistoryItem().props('icon')).toBe(icon);
});
it('renders the correct title', () => {
expect(findHistoryItem().text()).toContain(title);
});
it('renders the correct time-ago tooltip', () => {
const activityEvents = mockAgentHistoryActivityItems;
expect(findTimeAgo().props('time')).toBe(activityEvents[lineNumber].recordedAt);
});
});
});
......@@ -5,6 +5,7 @@ import VueApollo from 'vue-apollo';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ClusterAgentShow from '~/clusters/agents/components/show.vue';
import TokenTable from '~/clusters/agents/components/token_table.vue';
import ActivityEvents from '~/clusters/agents/components/activity_events_list.vue';
import getAgentQuery from '~/clusters/agents/graphql/queries/get_cluster_agent.query.graphql';
import { useFakeDate } from 'helpers/fake_date';
import createMockApollo from 'helpers/mock_apollo_helper';
......@@ -72,6 +73,7 @@ describe('ClusterAgentShow', () => {
const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination);
const findTokenCount = () => wrapper.findByTestId('cluster-agent-token-count').text();
const findEESecurityTabSlot = () => wrapper.findByTestId('ee-security-tab');
const findActivity = () => wrapper.findComponent(ActivityEvents);
afterEach(() => {
wrapper.destroy();
......@@ -103,6 +105,10 @@ describe('ClusterAgentShow', () => {
it('should not render pagination buttons when there are no additional pages', () => {
expect(findPaginationButtons().exists()).toBe(false);
});
it('renders activity events list', () => {
expect(findActivity().exists()).toBe(true);
});
});
describe('when create user is unknown', () => {
......
const user = {
id: 1,
name: 'Administrator',
username: 'root',
webUrl: 'http://172.31.0.1:3000/root',
};
const agentToken = {
id: 1,
name: 'cluster-agent',
};
export const defaultActivityEvent = {
kind: 'unknown_agent',
level: 'info',
recordedAt: '2021-11-22T19:26:56Z',
agentToken,
user,
};
export const mockAgentActivityEvents = [
{
kind: 'token_created',
level: 'info',
recordedAt: '2021-12-03T01:06:56Z',
agentToken,
user,
},
{
kind: 'token_revoked',
level: 'info',
recordedAt: '2021-12-03T00:26:56Z',
agentToken,
user,
},
{
kind: 'agent_connected',
level: 'info',
recordedAt: '2021-12-02T19:26:56Z',
agentToken,
user,
},
{
kind: 'agent_disconnected',
level: 'info',
recordedAt: '2021-12-02T19:26:56Z',
agentToken,
user,
},
{
kind: 'agent_connected',
level: 'info',
recordedAt: '2021-11-22T19:26:56Z',
agentToken,
user,
},
{
kind: 'unknown_agent',
level: 'info',
recordedAt: '2021-11-22T19:26:56Z',
agentToken,
user,
},
];
export const mockResponse = {
data: {
project: {
id: 'project-1',
clusterAgent: {
id: 'cluster-agent',
activityEvents: {
nodes: mockAgentActivityEvents,
},
},
},
},
};
export const mockEmptyResponse = {
data: {
project: {
id: 'project-1',
clusterAgent: {
id: 'cluster-agent',
activityEvents: {
nodes: [],
},
},
},
},
};
export const mockAgentHistoryActivityItems = [
{
kind: 'token_created',
level: 'info',
recordedAt: '2021-12-03T01:06:56Z',
agentToken,
user,
eventTypeIcon: 'token',
title: 'cluster-agent created',
body: 'Token created by Administrator',
},
{
kind: 'token_revoked',
level: 'info',
recordedAt: '2021-12-03T00:26:56Z',
agentToken,
user,
eventTypeIcon: 'token',
title: 'cluster-agent revoked',
body: 'Token revoked by Administrator',
},
{
kind: 'agent_connected',
level: 'info',
recordedAt: '2021-12-02T19:26:56Z',
agentToken,
user,
eventTypeIcon: 'connected',
title: 'Connected',
body: 'Agent Connected',
},
{
kind: 'agent_disconnected',
level: 'info',
recordedAt: '2021-12-02T19:26:56Z',
agentToken,
user,
eventTypeIcon: 'connected',
title: 'Not connected',
body: 'Agent Not connected',
},
{
kind: 'agent_connected',
level: 'info',
recordedAt: '2021-11-22T19:26:56Z',
agentToken,
user,
eventTypeIcon: 'connected',
title: 'Connected',
body: 'Agent Connected',
},
{
kind: 'unknown_agent',
level: 'info',
recordedAt: '2021-11-22T19:26:56Z',
agentToken,
user,
eventTypeIcon: 'token',
title: 'unknown_agent',
body: 'Event occurred',
},
];
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment