mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2026-02-21 21:58:47 +00:00
enhance
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
|
||||
export function useInterval(fn: () => void | Promise<void>, ms: number): void {
|
||||
const id = ref<number>();
|
||||
export function useInterval(fn: () => void | Promise<void>, ms: number, options?: { immediate?: boolean }): void {
|
||||
const id = ref<number | null>(null);
|
||||
|
||||
onMounted(async () => {
|
||||
await fn(); // run once immediately
|
||||
if ((options?.immediate ?? true) === true) {
|
||||
await fn(); // run once immediately
|
||||
}
|
||||
id.value = window.setInterval(() => {
|
||||
void fn();
|
||||
}, ms);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (id.value != null) {
|
||||
if (id.value !== null) {
|
||||
window.clearInterval(id.value);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -342,12 +342,12 @@ export default class WoodpeckerClient extends ApiClient {
|
||||
return this._post(`/api/orgs/${orgId}/agents`, agent) as Promise<Agent>;
|
||||
}
|
||||
|
||||
async updateOrgAgent(orgId: number, agentId: number, agent: Partial<Agent>): Promise<Agent> {
|
||||
return this._patch(`/api/orgs/${orgId}/agents/${agentId}`, agent) as Promise<Agent>;
|
||||
async updateOrgAgent(orgId: number, agent: Agent): Promise<Agent> {
|
||||
return this._patch(`/api/orgs/${orgId}/agents/${agent.id}`, agent) as Promise<Agent>;
|
||||
}
|
||||
|
||||
async deleteOrgAgent(orgId: number, agentId: number): Promise<unknown> {
|
||||
return this._delete(`/api/orgs/${orgId}/agents/${agentId}`);
|
||||
async deleteOrgAgent(orgId: number, agent: Agent): Promise<unknown> {
|
||||
return this._delete(`/api/orgs/${orgId}/agents/${agent.id}`);
|
||||
}
|
||||
|
||||
async getForges(opts?: PaginationOptions): Promise<Forge[] | null> {
|
||||
|
||||
@@ -213,9 +213,24 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
{
|
||||
path: 'agents',
|
||||
name: 'org-settings-agents',
|
||||
component: (): Component => import('~/views/org/settings/OrgAgents.vue'),
|
||||
props: true,
|
||||
component: (): Component => import('~/components/layout/RouteWrapper.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'org-settings-agents',
|
||||
component: (): Component => import('~/views/org/settings/agents/OrgAgents.vue'),
|
||||
},
|
||||
{
|
||||
path: ':agentId',
|
||||
name: 'org-settings-agent',
|
||||
component: (): Component => import('~/views/org/settings/agents/OrgAgent.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'org-settings-agent-create',
|
||||
component: (): Component => import('~/views/org/settings/agents/OrgAgentCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -277,7 +292,7 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'admin-settings-agents-create',
|
||||
name: 'admin-settings-agent-create',
|
||||
component: (): Component => import('~/views/admin/agents/AdminAgentCreate.vue'),
|
||||
},
|
||||
],
|
||||
@@ -344,9 +359,24 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
{
|
||||
path: 'agents',
|
||||
name: 'user-agents',
|
||||
component: (): Component => import('~/views/user/UserAgents.vue'),
|
||||
props: true,
|
||||
component: (): Component => import('~/components/layout/RouteWrapper.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'user-agents',
|
||||
component: (): Component => import('~/views/user/agents/UserAgents.vue'),
|
||||
},
|
||||
{
|
||||
path: ':agentId',
|
||||
name: 'user-agent',
|
||||
component: (): Component => import('~/views/user/agents/UserAgent.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'user-agent-create',
|
||||
component: (): Component => import('~/views/user/agents/UserAgentCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" @click="$router.back()" />
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" :to="{ name: 'admin-settings-agents' }" />
|
||||
</template>
|
||||
|
||||
<AgentForm
|
||||
@@ -10,26 +10,28 @@
|
||||
is-editing
|
||||
:is-saving="isSaving"
|
||||
@save="saveAgent"
|
||||
@cancel="$router.back()"
|
||||
@cancel="$router.replace({ name: 'admin-settings-agents' })"
|
||||
/>
|
||||
<div v-else class="flex">
|
||||
<div v-else class="flex justify-center">
|
||||
<Icon name="spinner" class="animate-spin" />
|
||||
</div>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import AgentForm from '~/components/agent/AgentForm.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Icon from '~/components/atomic/Icon.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction, useAsyncData } from '~/compositions/useAsyncAction';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
@@ -38,7 +40,17 @@ const route = useRoute();
|
||||
|
||||
const agentId = computed(() => Number.parseInt(route.params.agentId.toString(), 10));
|
||||
|
||||
const { data: agent, refetch: reloadAgent } = useAsyncData(computed(() => () => apiClient.getAgent(agentId.value)));
|
||||
const agent = ref<Agent | null>(null);
|
||||
|
||||
const { data: dbAgent, refetch: reloadAgent } = useAsyncData(computed(() => () => apiClient.getAgent(agentId.value)));
|
||||
|
||||
watch(
|
||||
dbAgent,
|
||||
(newAgent) => {
|
||||
agent.value = newAgent;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const { doSubmit: saveAgent, isLoading: isSaving } = useAsyncAction(async () => {
|
||||
if (!agent.value) {
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" :to="{ name: 'admin-settings-agents' }" />
|
||||
</template>
|
||||
|
||||
<AgentForm v-model="agent" :is-saving="isSaving" @save="createAgent" @cancel="$router.back()" />
|
||||
<AgentForm
|
||||
v-model="agent"
|
||||
:is-saving="isSaving"
|
||||
@save="createAgent"
|
||||
@cancel="$router.replace({ name: 'admin-settings-agents' })"
|
||||
/>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
@@ -44,7 +49,7 @@ const { doSubmit: createAgent, isLoading: isSaving } = useAsyncAction(async () =
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
await router.push({ name: 'admin-settings-agent', params: { agentId: createdAgent.id } });
|
||||
await router.replace({ name: 'admin-settings-agent', params: { agentId: createdAgent.id } });
|
||||
});
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings'), t('create')]));
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button
|
||||
:text="$t('admin.settings.agents.add')"
|
||||
start-icon="plus"
|
||||
@click="$router.push({ name: 'admin-settings-agent-create' })"
|
||||
/>
|
||||
<Button :text="$t('admin.settings.agents.add')" start-icon="plus" :to="{ name: 'admin-settings-agent-create' }" />
|
||||
</template>
|
||||
|
||||
<AgentList
|
||||
@@ -51,7 +47,7 @@ const { doSubmit: deleteAgent, isLoading: isDeleting } = useAsyncAction(async (a
|
||||
await resetPage();
|
||||
});
|
||||
|
||||
useInterval(resetPage, 5 * 1000); // refresh every 5s
|
||||
useInterval(resetPage, 5 * 1000, { immediate: false });
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings')]));
|
||||
</script>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<AgentManager
|
||||
:description="$t('org.settings.agents.desc')"
|
||||
:load-agents="loadAgents"
|
||||
:create-agent="createAgent"
|
||||
:update-agent="updateAgent"
|
||||
:delete-agent="deleteAgent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import AgentManager from '~/components/agent/AgentManager.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const apiClient = useApiClient();
|
||||
const org = requiredInject('org');
|
||||
|
||||
const loadAgents = (page: number) => apiClient.getOrgAgents(org.value.id, { page });
|
||||
const createAgent = (agent: Partial<Agent>) => apiClient.createOrgAgent(org.value.id, agent);
|
||||
const updateAgent = (agent: Agent) => apiClient.updateOrgAgent(org.value.id, agent.id, agent);
|
||||
const deleteAgent = (agent: Agent) => apiClient.deleteOrgAgent(org.value.id, agent.id);
|
||||
|
||||
const { t } = useI18n();
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), org.value.name]));
|
||||
</script>
|
||||
74
web/src/views/org/settings/agents/OrgAgent.vue
Normal file
74
web/src/views/org/settings/agents/OrgAgent.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" :to="{ name: 'org-settings-agents' }" />
|
||||
</template>
|
||||
|
||||
<AgentForm
|
||||
v-if="agent"
|
||||
v-model="agent"
|
||||
is-editing
|
||||
:is-saving="isSaving"
|
||||
@save="saveAgent"
|
||||
@cancel="$router.push({ name: 'org-settings-agents' })"
|
||||
/>
|
||||
<div v-else class="flex justify-center">
|
||||
<Icon name="spinner" class="animate-spin" />
|
||||
</div>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import AgentForm from '~/components/agent/AgentForm.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Icon from '~/components/atomic/Icon.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction, useAsyncData } from '~/compositions/useAsyncAction';
|
||||
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
const apiClient = useApiClient();
|
||||
const route = useRoute();
|
||||
|
||||
const org = requiredInject('org');
|
||||
|
||||
const agentId = computed(() => Number.parseInt(route.params.agentId.toString(), 10));
|
||||
|
||||
const agent = ref<Agent | null>(null);
|
||||
|
||||
const { data: dbAgent, refetch: reloadAgent } = useAsyncData(computed(() => () => apiClient.getAgent(agentId.value)));
|
||||
|
||||
watch(
|
||||
dbAgent,
|
||||
(newAgent) => {
|
||||
agent.value = newAgent;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const { doSubmit: saveAgent, isLoading: isSaving } = useAsyncAction(async () => {
|
||||
if (!agent.value) {
|
||||
throw new Error("Unexpected: Can't get agent");
|
||||
}
|
||||
|
||||
await apiClient.updateOrgAgent(org.value.id, agent.value);
|
||||
|
||||
notifications.notify({
|
||||
title: t('admin.settings.agents.saved'),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
await reloadAgent();
|
||||
});
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings'), agent.value?.name ?? '']));
|
||||
</script>
|
||||
59
web/src/views/org/settings/agents/OrgAgentCreate.vue
Normal file
59
web/src/views/org/settings/agents/OrgAgentCreate.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" :to="{ name: 'org-settings-agents' }" />
|
||||
</template>
|
||||
|
||||
<AgentForm
|
||||
v-model="agent"
|
||||
:is-saving="isSaving"
|
||||
@save="createAgent"
|
||||
@cancel="$router.replace({ name: 'org-settings-agents' })"
|
||||
/>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import AgentForm from '~/components/agent/AgentForm.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
const apiClient = useApiClient();
|
||||
const router = useRouter();
|
||||
|
||||
const agent = ref<Partial<Agent>>({
|
||||
name: '',
|
||||
no_schedule: false,
|
||||
});
|
||||
|
||||
const org = requiredInject('org');
|
||||
|
||||
const { doSubmit: createAgent, isLoading: isSaving } = useAsyncAction(async () => {
|
||||
if (!agent.value) {
|
||||
throw new Error("Unexpected: Can't get agent");
|
||||
}
|
||||
|
||||
const createdAgent = await apiClient.createOrgAgent(org.value.id, agent.value);
|
||||
|
||||
notifications.notify({
|
||||
title: t('admin.settings.agents.created'),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
await router.replace({ name: 'org-settings-agent', params: { agentId: createdAgent.id } });
|
||||
});
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings'), t('create')]));
|
||||
</script>
|
||||
60
web/src/views/org/settings/agents/OrgAgents.vue
Normal file
60
web/src/views/org/settings/agents/OrgAgents.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.add')" start-icon="plus" :to="{ name: 'org-settings-agent-create' }" />
|
||||
</template>
|
||||
|
||||
<AgentList
|
||||
:loading="loading"
|
||||
:agents="agents"
|
||||
:is-deleting="isDeleting"
|
||||
is-admin
|
||||
@edit="$router.push({ name: 'org-settings-agent', params: { agentId: $event.id } })"
|
||||
@delete="deleteAgent"
|
||||
/>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import AgentList from '~/components/agent/AgentList.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||
import { useInterval } from '~/compositions/useInterval';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { usePagination } from '~/compositions/usePaginate';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
const apiClient = useApiClient();
|
||||
|
||||
const org = requiredInject('org');
|
||||
|
||||
const {
|
||||
resetPage,
|
||||
data: agents,
|
||||
loading,
|
||||
} = usePagination((page: number) => apiClient.getOrgAgents(org.value.id, { page }));
|
||||
|
||||
const { doSubmit: deleteAgent, isLoading: isDeleting } = useAsyncAction(async (agent: Agent) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (!confirm(t('admin.settings.agents.delete_confirm'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
await apiClient.deleteOrgAgent(org.value.id, agent);
|
||||
notifications.notify({ title: t('admin.settings.agents.deleted'), type: 'success' });
|
||||
await resetPage();
|
||||
});
|
||||
|
||||
useInterval(resetPage, 5 * 1000, { immediate: false });
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings')]));
|
||||
</script>
|
||||
@@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<AgentManager
|
||||
:description="$t('user.settings.agents.desc')"
|
||||
:load-agents="loadAgents"
|
||||
:create-agent="createAgent"
|
||||
:update-agent="updateAgent"
|
||||
:delete-agent="deleteAgent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import AgentManager from '~/components/agent/AgentManager.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import useAuthentication from '~/compositions/useAuthentication';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const apiClient = useApiClient();
|
||||
const { user } = useAuthentication();
|
||||
|
||||
if (!user) {
|
||||
throw new Error('Unexpected: User should be authenticated');
|
||||
}
|
||||
|
||||
const loadAgents = (page: number) => apiClient.getOrgAgents(user.org_id, { page });
|
||||
const createAgent = (agent: Partial<Agent>) => apiClient.createOrgAgent(user.org_id, agent);
|
||||
const updateAgent = (agent: Agent) => apiClient.updateOrgAgent(user.org_id, agent.id, agent);
|
||||
const deleteAgent = (agent: Agent) => apiClient.deleteOrgAgent(user.org_id, agent.id);
|
||||
|
||||
const { t } = useI18n();
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('user.settings.settings')]));
|
||||
</script>
|
||||
77
web/src/views/user/agents/UserAgent.vue
Normal file
77
web/src/views/user/agents/UserAgent.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" :to="{ name: 'user-settings-agents' }" />
|
||||
</template>
|
||||
|
||||
<AgentForm
|
||||
v-if="agent"
|
||||
v-model="agent"
|
||||
is-editing
|
||||
:is-saving="isSaving"
|
||||
@save="saveAgent"
|
||||
@cancel="$router.replace({ name: 'user-settings-agents' })"
|
||||
/>
|
||||
<div v-else class="flex justify-center">
|
||||
<Icon name="spinner" class="animate-spin" />
|
||||
</div>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import AgentForm from '~/components/agent/AgentForm.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Icon from '~/components/atomic/Icon.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction, useAsyncData } from '~/compositions/useAsyncAction';
|
||||
import useAuthentication from '~/compositions/useAuthentication';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
const apiClient = useApiClient();
|
||||
const route = useRoute();
|
||||
const { user } = useAuthentication();
|
||||
|
||||
if (!user) {
|
||||
throw new Error('Unexpected: User should be authenticated');
|
||||
}
|
||||
|
||||
const agentId = computed(() => Number.parseInt(route.params.agentId.toString(), 10));
|
||||
|
||||
const agent = ref<Agent | null>(null);
|
||||
|
||||
const { data: dbAgent, refetch: reloadAgent } = useAsyncData(computed(() => () => apiClient.getAgent(agentId.value)));
|
||||
|
||||
watch(
|
||||
dbAgent,
|
||||
(newAgent) => {
|
||||
agent.value = newAgent;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const { doSubmit: saveAgent, isLoading: isSaving } = useAsyncAction(async () => {
|
||||
if (!agent.value) {
|
||||
throw new Error("Unexpected: Can't get agent");
|
||||
}
|
||||
|
||||
await apiClient.updateOrgAgent(user.org_id, agent.value);
|
||||
|
||||
notifications.notify({
|
||||
title: t('admin.settings.agents.saved'),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
await reloadAgent();
|
||||
});
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings'), agent.value?.name ?? '']));
|
||||
</script>
|
||||
62
web/src/views/user/agents/UserAgentCreate.vue
Normal file
62
web/src/views/user/agents/UserAgentCreate.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.show')" start-icon="back" :to="{ name: 'user-settings-agents' }" />
|
||||
</template>
|
||||
|
||||
<AgentForm
|
||||
v-model="agent"
|
||||
:is-saving="isSaving"
|
||||
@save="createAgent"
|
||||
@cancel="$router.replace({ name: 'user-settings-agents' })"
|
||||
/>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import AgentForm from '~/components/agent/AgentForm.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||
import useAuthentication from '~/compositions/useAuthentication';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
const apiClient = useApiClient();
|
||||
const router = useRouter();
|
||||
const { user } = useAuthentication();
|
||||
|
||||
if (!user) {
|
||||
throw new Error('Unexpected: User should be authenticated');
|
||||
}
|
||||
|
||||
const agent = ref<Partial<Agent>>({
|
||||
name: '',
|
||||
no_schedule: false,
|
||||
});
|
||||
|
||||
const { doSubmit: createAgent, isLoading: isSaving } = useAsyncAction(async () => {
|
||||
if (!agent.value) {
|
||||
throw new Error("Unexpected: Can't get agent");
|
||||
}
|
||||
|
||||
const createdAgent = await apiClient.createOrgAgent(user.org_id, agent.value);
|
||||
|
||||
notifications.notify({
|
||||
title: t('admin.settings.agents.created'),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
await router.push({ name: 'user-settings-agent', params: { agentId: createdAgent.id } });
|
||||
});
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings'), t('create')]));
|
||||
</script>
|
||||
63
web/src/views/user/agents/UserAgents.vue
Normal file
63
web/src/views/user/agents/UserAgents.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<Settings :title="$t('admin.settings.agents.agents')" :description="$t('admin.settings.agents.desc')">
|
||||
<template #headerActions>
|
||||
<Button :text="$t('admin.settings.agents.add')" start-icon="plus" :to="{ name: 'user-settings-agent-create' }" />
|
||||
</template>
|
||||
|
||||
<AgentList
|
||||
:loading="loading"
|
||||
:agents="agents"
|
||||
:is-deleting="isDeleting"
|
||||
is-admin
|
||||
@edit="$router.push({ name: 'org-settings-agent', params: { agentId: $event.id } })"
|
||||
@delete="deleteAgent"
|
||||
/>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import AgentList from '~/components/agent/AgentList.vue';
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||
import useAuthentication from '~/compositions/useAuthentication';
|
||||
import { useInterval } from '~/compositions/useInterval';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import { usePagination } from '~/compositions/usePaginate';
|
||||
import { useWPTitle } from '~/compositions/useWPTitle';
|
||||
import type { Agent } from '~/lib/api/types';
|
||||
|
||||
const notifications = useNotifications();
|
||||
const { t } = useI18n();
|
||||
const apiClient = useApiClient();
|
||||
const { user } = useAuthentication();
|
||||
|
||||
if (!user) {
|
||||
throw new Error('Unexpected: User should be authenticated');
|
||||
}
|
||||
|
||||
const {
|
||||
resetPage,
|
||||
data: agents,
|
||||
loading,
|
||||
} = usePagination((page: number) => apiClient.getOrgAgents(user.org_id, { page }));
|
||||
|
||||
const { doSubmit: deleteAgent, isLoading: isDeleting } = useAsyncAction(async (agent: Agent) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (!confirm(t('admin.settings.agents.delete_confirm'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
await apiClient.deleteOrgAgent(user.org_id, agent);
|
||||
notifications.notify({ title: t('admin.settings.agents.deleted'), type: 'success' });
|
||||
await resetPage();
|
||||
});
|
||||
|
||||
useInterval(resetPage, 5 * 1000, { immediate: false });
|
||||
|
||||
useWPTitle(computed(() => [t('admin.settings.agents.agents'), t('admin.settings.settings')]));
|
||||
</script>
|
||||
Reference in New Issue
Block a user