mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-09-02 12:13:48 +00:00
Use centrally typed inject provide in Vue (#5113)
Co-authored-by: Robert Kaussow <mail@thegeeklab.de>
This commit is contained in:
parent
cc4b362410
commit
208ac771d4
31 changed files with 123 additions and 320 deletions
|
@ -39,7 +39,7 @@ import TextField from '~/components/form/TextField.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import Popup from '~/components/layout/Popup.vue';
|
import Popup from '~/components/layout/Popup.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { inject } from '~/compositions/useInjectProvide';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -51,7 +51,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const repo = inject('repo');
|
const repo = requiredInject('repo');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const payload = ref<{
|
const payload = ref<{
|
||||||
|
|
|
@ -111,16 +111,16 @@ import { useStorage } from '@vueuse/core';
|
||||||
import { AnsiUp } from 'ansi_up';
|
import { AnsiUp } from 'ansi_up';
|
||||||
import { decode } from 'js-base64';
|
import { decode } from 'js-base64';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { computed, inject, nextTick, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import IconButton from '~/components/atomic/IconButton.vue';
|
import IconButton from '~/components/atomic/IconButton.vue';
|
||||||
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import type { Pipeline, PipelineStep, PipelineWorkflow, Repo, RepoPermissions } from '~/lib/api/types';
|
import type { Pipeline, PipelineStep, PipelineWorkflow } from '~/lib/api/types';
|
||||||
|
|
||||||
interface LogLine {
|
interface LogLine {
|
||||||
index: number;
|
index: number;
|
||||||
|
@ -143,8 +143,8 @@ const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const pipeline = toRef(props, 'pipeline');
|
const pipeline = toRef(props, 'pipeline');
|
||||||
const stepId = toRef(props, 'stepId');
|
const stepId = toRef(props, 'stepId');
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
const repoPermissions = requiredInject('repo-permissions');
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
|
@ -286,10 +286,6 @@ async function loadLogs() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
log.value = undefined;
|
log.value = undefined;
|
||||||
logBuffer.value = [];
|
logBuffer.value = [];
|
||||||
ansiUp.value = new AnsiUp();
|
ansiUp.value = new AnsiUp();
|
||||||
|
|
|
@ -118,17 +118,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, nextTick, ref, toRef, useTemplateRef, watch } from 'vue';
|
import { computed, nextTick, ref, toRef, useTemplateRef, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import Badge from '~/components/atomic/Badge.vue';
|
import Badge from '~/components/atomic/Badge.vue';
|
||||||
import Icon from '~/components/atomic/Icon.vue';
|
import Icon from '~/components/atomic/Icon.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
||||||
import PipelineStepDuration from '~/components/repo/pipeline/PipelineStepDuration.vue';
|
import PipelineStepDuration from '~/components/repo/pipeline/PipelineStepDuration.vue';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import usePipeline from '~/compositions/usePipeline';
|
import usePipeline from '~/compositions/usePipeline';
|
||||||
import { StepType } from '~/lib/api/types';
|
import { StepType } from '~/lib/api/types';
|
||||||
import type { Pipeline, PipelineConfig, PipelineStep } from '~/lib/api/types';
|
import type { Pipeline, PipelineStep } from '~/lib/api/types';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pipeline: Pipeline;
|
pipeline: Pipeline;
|
||||||
|
@ -142,7 +142,7 @@ defineEmits<{
|
||||||
const pipeline = toRef(props, 'pipeline');
|
const pipeline = toRef(props, 'pipeline');
|
||||||
const selectedStepId = toRef(props, 'selectedStepId');
|
const selectedStepId = toRef(props, 'selectedStepId');
|
||||||
const { prettyRef } = usePipeline(pipeline);
|
const { prettyRef } = usePipeline(pipeline);
|
||||||
const pipelineConfigs = inject<Ref<PipelineConfig[]>>('pipeline-configs');
|
const pipelineConfigs = requiredInject('pipeline-configs');
|
||||||
|
|
||||||
const workflowsCollapsed = ref<Record<PipelineStep['id'], boolean>>(
|
const workflowsCollapsed = ref<Record<PipelineStep['id'], boolean>>(
|
||||||
pipeline.value.workflows && pipeline.value.workflows.length > 1
|
pipeline.value.workflows && pipeline.value.workflows.length > 1
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
import type { InjectionKey, Ref } from 'vue';
|
import type { InjectionKey, Ref } from 'vue';
|
||||||
import { inject as vueInject, provide as vueProvide } from 'vue';
|
import { inject as vueInject, provide as vueProvide } from 'vue';
|
||||||
|
|
||||||
import type { Org, OrgPermissions, Pipeline, PipelineConfig, Repo } from '~/lib/api/types';
|
import type { Org, OrgPermissions, Pipeline, PipelineConfig, Repo, RepoPermissions } from '~/lib/api/types';
|
||||||
|
|
||||||
import type { Tab } from './useTabs';
|
import type { Tab } from './useTabs';
|
||||||
|
|
||||||
export interface InjectKeys {
|
export interface InjectKeys {
|
||||||
repo: Ref<Repo>;
|
repo: Ref<Repo>;
|
||||||
org: Ref<Org | undefined>;
|
'repo-permissions': Ref<RepoPermissions>;
|
||||||
'org-permissions': Ref<OrgPermissions | undefined>;
|
org: Ref<Org>;
|
||||||
pipeline: Ref<Pipeline | undefined>;
|
'org-permissions': Ref<OrgPermissions>;
|
||||||
|
pipeline: Ref<Pipeline>;
|
||||||
'pipeline-configs': Ref<PipelineConfig[] | undefined>;
|
'pipeline-configs': Ref<PipelineConfig[] | undefined>;
|
||||||
tabs: Ref<Tab[]>;
|
tabs: Ref<Tab[]>;
|
||||||
|
pipelines: Ref<Pipeline[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inject<T extends keyof InjectKeys>(key: T): InjectKeys[T] {
|
export function requiredInject<T extends keyof InjectKeys>(key: T): InjectKeys[T] {
|
||||||
const value = vueInject<InjectKeys[T]>(key);
|
const value = vueInject<InjectKeys[T]>(key);
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
throw new Error(`Please provide a value for ${key}`);
|
throw new Error(`Unexpected: ${key} should be provided at this place`);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { RouteLocationRaw } from 'vue-router';
|
||||||
|
|
||||||
import type { IconNames } from '~/components/atomic/Icon.vue';
|
import type { IconNames } from '~/components/atomic/Icon.vue';
|
||||||
|
|
||||||
import { inject, provide } from './useInjectProvide';
|
import { provide, requiredInject } from './useInjectProvide';
|
||||||
|
|
||||||
export interface Tab {
|
export interface Tab {
|
||||||
to: RouteLocationRaw;
|
to: RouteLocationRaw;
|
||||||
|
@ -20,6 +20,6 @@ export function useTabsProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useTabsClient() {
|
export function useTabsClient() {
|
||||||
const tabs = inject('tabs');
|
const tabs = requiredInject('tabs');
|
||||||
return { tabs };
|
return { tabs };
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { computed, onMounted, ref } from 'vue';
|
||||||
import IconButton from '~/components/atomic/IconButton.vue';
|
import IconButton from '~/components/atomic/IconButton.vue';
|
||||||
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
||||||
import RepoItem from '~/components/repo/RepoItem.vue';
|
import RepoItem from '~/components/repo/RepoItem.vue';
|
||||||
import { inject } from '~/compositions/useInjectProvide';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useRepos from '~/compositions/useRepos';
|
import useRepos from '~/compositions/useRepos';
|
||||||
import { useRepoSearch } from '~/compositions/useRepoSearch';
|
import { useRepoSearch } from '~/compositions/useRepoSearch';
|
||||||
import { useRepoStore } from '~/store/repos';
|
import { useRepoStore } from '~/store/repos';
|
||||||
|
@ -36,8 +36,8 @@ import { useRepoStore } from '~/store/repos';
|
||||||
const repoStore = useRepoStore();
|
const repoStore = useRepoStore();
|
||||||
const { repoWithLastPipeline, sortReposByLastActivity } = useRepos();
|
const { repoWithLastPipeline, sortReposByLastActivity } = useRepos();
|
||||||
|
|
||||||
const org = inject('org');
|
const org = requiredInject('org');
|
||||||
const orgPermissions = inject('org-permissions');
|
const orgPermissions = requiredInject('org-permissions');
|
||||||
|
|
||||||
const search = ref('');
|
const search = ref('');
|
||||||
const repos = computed(() =>
|
const repos = computed(() =>
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { Ref } from 'vue';
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
@ -38,8 +39,8 @@ const route = useRoute();
|
||||||
|
|
||||||
const org = ref<Org>();
|
const org = ref<Org>();
|
||||||
const orgPermissions = ref<OrgPermissions>();
|
const orgPermissions = ref<OrgPermissions>();
|
||||||
provide('org', org);
|
provide('org', org as Ref<Org>); // can't be undefined because of v-if in template
|
||||||
provide('org-permissions', orgPermissions);
|
provide('org-permissions', orgPermissions as Ref<OrgPermissions>); // can't be undefined because of v-if in template
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
org.value = await apiClient.getOrg(orgId.value);
|
org.value = await apiClient.getOrg(orgId.value);
|
||||||
|
|
|
@ -9,18 +9,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject } from 'vue';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import AgentManager from '~/components/agent/AgentManager.vue';
|
import AgentManager from '~/components/agent/AgentManager.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import type { Agent, Org } from '~/lib/api/types';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
import type { Agent } from '~/lib/api/types';
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const org = inject<Ref<Org>>('org');
|
const org = requiredInject('org');
|
||||||
if (org === undefined) {
|
|
||||||
throw new Error('Unexpected: "org" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadAgents = (page: number) => apiClient.getOrgAgents(org.value.id, { page });
|
const loadAgents = (page: number) => apiClient.getOrgAgents(org.value.id, { page });
|
||||||
const createAgent = (agent: Partial<Agent>) => apiClient.createOrgAgent(org.value.id, agent);
|
const createAgent = (agent: Partial<Agent>) => apiClient.createOrgAgent(org.value.id, agent);
|
||||||
|
|
|
@ -34,8 +34,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
@ -44,9 +43,10 @@ import RegistryEdit from '~/components/registry/RegistryEdit.vue';
|
||||||
import RegistryList from '~/components/registry/RegistryList.vue';
|
import RegistryList from '~/components/registry/RegistryList.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import type { Org, Registry } from '~/lib/api/types';
|
import type { Registry } from '~/lib/api/types';
|
||||||
|
|
||||||
const emptyRegistry: Partial<Registry> = {
|
const emptyRegistry: Partial<Registry> = {
|
||||||
address: '',
|
address: '',
|
||||||
|
@ -58,25 +58,17 @@ const apiClient = useApiClient();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const org = inject<Ref<Org>>('org');
|
const org = requiredInject('org');
|
||||||
const selectedRegistry = ref<Partial<Registry>>();
|
const selectedRegistry = ref<Partial<Registry>>();
|
||||||
const isEditing = computed(() => !!selectedRegistry.value?.id);
|
const isEditing = computed(() => !!selectedRegistry.value?.id);
|
||||||
|
|
||||||
async function loadRegistries(page: number): Promise<Registry[] | null> {
|
async function loadRegistries(page: number): Promise<Registry[] | null> {
|
||||||
if (!org?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load org");
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getOrgRegistryList(org.value.id, { page });
|
return apiClient.getOrgRegistryList(org.value.id, { page });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { resetPage, data: registries } = usePagination(loadRegistries, () => !selectedRegistry.value);
|
const { resetPage, data: registries } = usePagination(loadRegistries, () => !selectedRegistry.value);
|
||||||
|
|
||||||
const { doSubmit: createRegistry, isLoading: isSaving } = useAsyncAction(async () => {
|
const { doSubmit: createRegistry, isLoading: isSaving } = useAsyncAction(async () => {
|
||||||
if (!org?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load org");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedRegistry.value) {
|
if (!selectedRegistry.value) {
|
||||||
throw new Error("Unexpected: Can't get registry");
|
throw new Error("Unexpected: Can't get registry");
|
||||||
}
|
}
|
||||||
|
@ -95,10 +87,6 @@ const { doSubmit: createRegistry, isLoading: isSaving } = useAsyncAction(async (
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deleteRegistry, isLoading: isDeleting } = useAsyncAction(async (_registry: Registry) => {
|
const { doSubmit: deleteRegistry, isLoading: isDeleting } = useAsyncAction(async (_registry: Registry) => {
|
||||||
if (!org?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load org");
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.deleteOrgRegistry(org.value.id, _registry.address);
|
await apiClient.deleteOrgRegistry(org.value.id, _registry.address);
|
||||||
notifications.notify({ title: i18n.t('registries.deleted'), type: 'success' });
|
notifications.notify({ title: i18n.t('registries.deleted'), type: 'success' });
|
||||||
resetPage();
|
resetPage();
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
@ -35,10 +34,11 @@ import SecretEdit from '~/components/secrets/SecretEdit.vue';
|
||||||
import SecretList from '~/components/secrets/SecretList.vue';
|
import SecretList from '~/components/secrets/SecretList.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import { WebhookEvents } from '~/lib/api/types';
|
import { WebhookEvents } from '~/lib/api/types';
|
||||||
import type { Org, Secret } from '~/lib/api/types';
|
import type { Secret } from '~/lib/api/types';
|
||||||
|
|
||||||
const emptySecret: Partial<Secret> = {
|
const emptySecret: Partial<Secret> = {
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -51,25 +51,17 @@ const apiClient = useApiClient();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const org = inject<Ref<Org>>('org');
|
const org = requiredInject('org');
|
||||||
const selectedSecret = ref<Partial<Secret>>();
|
const selectedSecret = ref<Partial<Secret>>();
|
||||||
const isEditingSecret = computed(() => !!selectedSecret.value?.id);
|
const isEditingSecret = computed(() => !!selectedSecret.value?.id);
|
||||||
|
|
||||||
async function loadSecrets(page: number): Promise<Secret[] | null> {
|
async function loadSecrets(page: number): Promise<Secret[] | null> {
|
||||||
if (!org?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load org");
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getOrgSecretList(org.value.id, { page });
|
return apiClient.getOrgSecretList(org.value.id, { page });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { resetPage, data: secrets } = usePagination(loadSecrets, () => !selectedSecret.value);
|
const { resetPage, data: secrets } = usePagination(loadSecrets, () => !selectedSecret.value);
|
||||||
|
|
||||||
const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async () => {
|
const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async () => {
|
||||||
if (!org?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load org");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedSecret.value) {
|
if (!selectedSecret.value) {
|
||||||
throw new Error("Unexpected: Can't get secret");
|
throw new Error("Unexpected: Can't get secret");
|
||||||
}
|
}
|
||||||
|
@ -88,10 +80,6 @@ const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async ()
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (_secret: Secret) => {
|
const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (_secret: Secret) => {
|
||||||
if (!org?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load org");
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.deleteOrgSecret(org.value.id, _secret.name);
|
await apiClient.deleteOrgSecret(org.value.id, _secret.name);
|
||||||
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
||||||
resetPage();
|
resetPage();
|
||||||
|
|
|
@ -32,7 +32,7 @@ import { useRouter } from 'vue-router';
|
||||||
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
||||||
import Tab from '~/components/layout/scaffold/Tab.vue';
|
import Tab from '~/components/layout/scaffold/Tab.vue';
|
||||||
import useConfig from '~/compositions/useConfig';
|
import useConfig from '~/compositions/useConfig';
|
||||||
import { inject } from '~/compositions/useInjectProvide';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { useRouteBack } from '~/compositions/useRouteBack';
|
import { useRouteBack } from '~/compositions/useRouteBack';
|
||||||
|
|
||||||
|
@ -40,8 +40,8 @@ const notifications = useNotifications();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const org = inject('org');
|
const org = requiredInject('org');
|
||||||
const orgPermissions = inject('org-permissions');
|
const orgPermissions = requiredInject('org-permissions');
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!orgPermissions.value?.admin) {
|
if (!orgPermissions.value?.admin) {
|
||||||
|
|
|
@ -6,26 +6,21 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, toRef } from 'vue';
|
import { computed, toRef } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import PipelineList from '~/components/repo/pipeline/PipelineList.vue';
|
import PipelineList from '~/components/repo/pipeline/PipelineList.vue';
|
||||||
import type { Pipeline, Repo, RepoPermissions } from '~/lib/api/types';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
branch: string;
|
branch: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const branch = toRef(props, 'branch');
|
const branch = toRef(props, 'branch');
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
|
||||||
if (!repo || !repoPermissions) {
|
|
||||||
throw new Error('Unexpected: "repo" & "repoPermissions" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const allPipelines = inject<Ref<Pipeline[]>>('pipelines');
|
const allPipelines = requiredInject('pipelines');
|
||||||
const pipelines = computed(() =>
|
const pipelines = computed(() =>
|
||||||
allPipelines?.value.filter(
|
allPipelines.value.filter(
|
||||||
(b) => b.branch === branch.value && b.event !== 'pull_request' && b.event !== 'pull_request_closed',
|
(b) => b.branch === branch.value && b.event !== 'pull_request' && b.event !== 'pull_request_closed',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,29 +21,21 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, watch } from 'vue';
|
import { computed, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import Badge from '~/components/atomic/Badge.vue';
|
import Badge from '~/components/atomic/Badge.vue';
|
||||||
import Icon from '~/components/atomic/Icon.vue';
|
import Icon from '~/components/atomic/Icon.vue';
|
||||||
import ListItem from '~/components/atomic/ListItem.vue';
|
import ListItem from '~/components/atomic/ListItem.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import type { Repo } from '~/lib/api/types';
|
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadBranches(page: number): Promise<string[]> {
|
async function loadBranches(page: number): Promise<string[]> {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getRepoBranches(repo.value.id, { page });
|
return apiClient.getRepoBranches(repo.value.id, { page });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useNotification } from '@kyvg/vue3-notification';
|
import { useNotification } from '@kyvg/vue3-notification';
|
||||||
import type { Ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { computed, onMounted, ref, inject as vueInject } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -38,9 +37,8 @@ import KeyValueEditor from '~/components/form/KeyValueEditor.vue';
|
||||||
import SelectField from '~/components/form/SelectField.vue';
|
import SelectField from '~/components/form/SelectField.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { inject } from '~/compositions/useInjectProvide';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import { usePaginate } from '~/compositions/usePaginate';
|
import { usePaginate } from '~/compositions/usePaginate';
|
||||||
import type { RepoPermissions } from '~/lib/api/types';
|
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -54,11 +52,8 @@ const apiClient = useApiClient();
|
||||||
const notifications = useNotification();
|
const notifications = useNotification();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repo = inject('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = vueInject<Ref<RepoPermissions>>('repo-permissions');
|
const repoPermissions = requiredInject('repo-permissions');
|
||||||
if (!repoPermissions) {
|
|
||||||
throw new Error('Unexpected: "repo" and "repoPermissions" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const branches = ref<{ text: string; value: string }[]>([]);
|
const branches = ref<{ text: string; value: string }[]>([]);
|
||||||
|
|
|
@ -3,17 +3,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject } from 'vue';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import PipelineList from '~/components/repo/pipeline/PipelineList.vue';
|
import PipelineList from '~/components/repo/pipeline/PipelineList.vue';
|
||||||
import type { Pipeline, Repo, RepoPermissions } from '~/lib/api/types';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
const pipelines = requiredInject('pipelines');
|
||||||
if (!repo || !repoPermissions) {
|
|
||||||
throw new Error('Unexpected: "repo" & "repoPermissions" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const pipelines = inject<Ref<Pipeline[]>>('pipelines');
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,28 +6,23 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, toRef } from 'vue';
|
import { computed, toRef } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import PipelineList from '~/components/repo/pipeline/PipelineList.vue';
|
import PipelineList from '~/components/repo/pipeline/PipelineList.vue';
|
||||||
import type { Pipeline, Repo, RepoPermissions } from '~/lib/api/types';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pullRequest: string;
|
pullRequest: string;
|
||||||
}>();
|
}>();
|
||||||
const pullRequest = toRef(props, 'pullRequest');
|
const pullRequest = toRef(props, 'pullRequest');
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
|
||||||
if (!repo || !repoPermissions) {
|
|
||||||
throw new Error('Unexpected: "repo" and "repoPermissions" should be provided at this place');
|
|
||||||
}
|
|
||||||
if (!repo.value.pr_enabled || !repo.value.allow_pr) {
|
if (!repo.value.pr_enabled || !repo.value.allow_pr) {
|
||||||
throw new Error('Unexpected: pull requests are disabled for repo');
|
throw new Error('Unexpected: pull requests are disabled for repo');
|
||||||
}
|
}
|
||||||
|
|
||||||
const allPipelines = inject<Ref<Pipeline[]>>('pipelines');
|
const allPipelines = requiredInject('pipelines');
|
||||||
const pipelines = computed(() =>
|
const pipelines = computed(() =>
|
||||||
allPipelines?.value.filter(
|
allPipelines.value.filter(
|
||||||
(b) =>
|
(b) =>
|
||||||
(b.event === 'pull_request' || b.event === 'pull_request_closed') &&
|
(b.event === 'pull_request' || b.event === 'pull_request_closed') &&
|
||||||
b.ref
|
b.ref
|
||||||
|
|
|
@ -26,31 +26,24 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import Icon from '~/components/atomic/Icon.vue';
|
import Icon from '~/components/atomic/Icon.vue';
|
||||||
import ListItem from '~/components/atomic/ListItem.vue';
|
import ListItem from '~/components/atomic/ListItem.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import type { PullRequest, Repo } from '~/lib/api/types';
|
import type { PullRequest } from '~/lib/api/types';
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
if (!repo.value.pr_enabled || !repo.value.allow_pr) {
|
if (!repo.value.pr_enabled || !repo.value.allow_pr) {
|
||||||
throw new Error('Unexpected: pull requests are disabled for repo');
|
throw new Error('Unexpected: pull requests are disabled for repo');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadPullRequests(page: number): Promise<PullRequest[]> {
|
async function loadPullRequests(page: number): Promise<PullRequest[]> {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getRepoPullRequests(repo.value.id, { page });
|
return apiClient.getRepoPullRequests(repo.value.id, { page });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, provide, ref, toRef, watch } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
import { computed, onMounted, ref, toRef, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -67,9 +68,10 @@ import useApiClient from '~/compositions/useApiClient';
|
||||||
import useAuthentication from '~/compositions/useAuthentication';
|
import useAuthentication from '~/compositions/useAuthentication';
|
||||||
import useConfig from '~/compositions/useConfig';
|
import useConfig from '~/compositions/useConfig';
|
||||||
import { useForgeStore } from '~/compositions/useForgeStore';
|
import { useForgeStore } from '~/compositions/useForgeStore';
|
||||||
|
import { provide } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import useRepos from '~/compositions/useRepos';
|
import useRepos from '~/compositions/useRepos';
|
||||||
import type { Forge, RepoPermissions } from '~/lib/api/types';
|
import type { Forge, Repo, RepoPermissions } from '~/lib/api/types';
|
||||||
import { usePipelineStore } from '~/store/pipelines';
|
import { usePipelineStore } from '~/store/pipelines';
|
||||||
import { useRepoStore } from '~/store/repos';
|
import { useRepoStore } from '~/store/repos';
|
||||||
|
|
||||||
|
@ -94,8 +96,8 @@ const { updateLastAccess } = useRepos();
|
||||||
const repo = repoStore.getRepo(repositoryId);
|
const repo = repoStore.getRepo(repositoryId);
|
||||||
const repoPermissions = ref<RepoPermissions>();
|
const repoPermissions = ref<RepoPermissions>();
|
||||||
const pipelines = pipelineStore.getRepoPipelines(repositoryId);
|
const pipelines = pipelineStore.getRepoPipelines(repositoryId);
|
||||||
provide('repo', repo);
|
provide('repo', repo as Ref<Repo>); // can't be undefined because of v-if in template
|
||||||
provide('repo-permissions', repoPermissions);
|
provide('repo-permissions', repoPermissions as Ref<RepoPermissions>); // can't be undefined because of v-if in template
|
||||||
provide('pipelines', pipelines);
|
provide('pipelines', pipelines);
|
||||||
const forge = ref<Forge>();
|
const forge = ref<Forge>();
|
||||||
const forgeIcon = computed<IconNames>(() => {
|
const forgeIcon = computed<IconNames>(() => {
|
||||||
|
|
|
@ -62,8 +62,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, toRef } from 'vue';
|
import { computed, toRef } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -75,8 +74,9 @@ import PipelineLog from '~/components/repo/pipeline/PipelineLog.vue';
|
||||||
import PipelineStepList from '~/components/repo/pipeline/PipelineStepList.vue';
|
import PipelineStepList from '~/components/repo/pipeline/PipelineStepList.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import type { Pipeline, PipelineStep, Repo, RepoPermissions } from '~/lib/api/types';
|
import type { PipelineStep } from '~/lib/api/types';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
stepId?: string | null;
|
stepId?: string | null;
|
||||||
|
@ -88,12 +88,9 @@ const route = useRoute();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const pipeline = inject<Ref<Pipeline>>('pipeline');
|
const pipeline = requiredInject('pipeline');
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
const repoPermissions = requiredInject('repo-permissions');
|
||||||
if (!repo || !repoPermissions || !pipeline) {
|
|
||||||
throw new Error('Unexpected: "repo", "repoPermissions" & "pipeline" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const stepId = toRef(props, 'stepId');
|
const stepId = toRef(props, 'stepId');
|
||||||
|
|
||||||
|
@ -139,19 +136,11 @@ const selectedStepId = computed({
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: approvePipeline, isLoading: isApprovingPipeline } = useAsyncAction(async () => {
|
const { doSubmit: approvePipeline, isLoading: isApprovingPipeline } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.approvePipeline(repo.value.id, `${pipeline.value.number}`);
|
await apiClient.approvePipeline(repo.value.id, `${pipeline.value.number}`);
|
||||||
notifications.notify({ title: i18n.t('repo.pipeline.protected.approve_success'), type: 'success' });
|
notifications.notify({ title: i18n.t('repo.pipeline.protected.approve_success'), type: 'success' });
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: declinePipeline, isLoading: isDecliningPipeline } = useAsyncAction(async () => {
|
const { doSubmit: declinePipeline, isLoading: isDecliningPipeline } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.declinePipeline(repo.value.id, `${pipeline.value.number}`);
|
await apiClient.declinePipeline(repo.value.id, `${pipeline.value.number}`);
|
||||||
notifications.notify({ title: i18n.t('repo.pipeline.protected.decline_success'), type: 'success' });
|
notifications.notify({ title: i18n.t('repo.pipeline.protected.decline_success'), type: 'success' });
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<Panel>
|
<Panel>
|
||||||
<ul class="w-full list-inside list-disc">
|
<ul class="w-full list-inside list-disc">
|
||||||
<li v-for="file in pipeline!.changed_files" :key="file">{{ file }}</li>
|
<li v-for="file in pipeline.changed_files" :key="file">{{ file }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Panel>
|
</Panel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject } from 'vue';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import type { Pipeline } from '~/lib/api/types';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const pipeline = inject<Ref<Pipeline>>('pipeline');
|
const pipeline = requiredInject('pipeline');
|
||||||
if (!pipeline) {
|
|
||||||
throw new Error('Unexpected: "pipeline" should be provided at this place');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -18,12 +18,9 @@ import { computed } from 'vue';
|
||||||
|
|
||||||
import SyntaxHighlight from '~/components/atomic/SyntaxHighlight';
|
import SyntaxHighlight from '~/components/atomic/SyntaxHighlight';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import { inject } from '~/compositions/useInjectProvide';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const pipelineConfigs = inject('pipeline-configs');
|
const pipelineConfigs = requiredInject('pipeline-configs');
|
||||||
if (!pipelineConfigs) {
|
|
||||||
throw new Error('Unexpected: "pipelineConfigs" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const pipelineConfigsDecoded = computed(
|
const pipelineConfigsDecoded = computed(
|
||||||
() =>
|
() =>
|
||||||
|
|
|
@ -18,24 +18,23 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
import InputField from '~/components/form/InputField.vue';
|
import InputField from '~/components/form/InputField.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import type { Pipeline, Repo, RepoPermissions } from '~/lib/api/types';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const pipeline = inject<Ref<Pipeline>>('pipeline');
|
const pipeline = requiredInject('pipeline');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
const repoPermissions = requiredInject('repo-permissions');
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
|
||||||
|
|
|
@ -48,19 +48,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject } from 'vue';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import DocsLink from '~/components/atomic/DocsLink.vue';
|
import DocsLink from '~/components/atomic/DocsLink.vue';
|
||||||
import Icon from '~/components/atomic/Icon.vue';
|
import Icon from '~/components/atomic/Icon.vue';
|
||||||
import RenderMarkdown from '~/components/atomic/RenderMarkdown.vue';
|
import RenderMarkdown from '~/components/atomic/RenderMarkdown.vue';
|
||||||
import Panel from '~/components/layout/Panel.vue';
|
import Panel from '~/components/layout/Panel.vue';
|
||||||
import type { Pipeline, PipelineError } from '~/lib/api/types';
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
|
import type { PipelineError } from '~/lib/api/types';
|
||||||
|
|
||||||
const pipeline = inject<Ref<Pipeline>>('pipeline');
|
const pipeline = requiredInject('pipeline');
|
||||||
if (!pipeline) {
|
|
||||||
throw new Error('Unexpected: "pipeline" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLinterError(error: PipelineError): error is PipelineError<{ file?: string; field: string }> {
|
function isLinterError(error: PipelineError): error is PipelineError<{ file?: string; field: string }> {
|
||||||
return error.type === 'linter';
|
return error.type === 'linter';
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue';
|
import { computed, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
@ -116,11 +116,11 @@ import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vu
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
import { useFavicon } from '~/compositions/useFavicon';
|
import { useFavicon } from '~/compositions/useFavicon';
|
||||||
import { provide } from '~/compositions/useInjectProvide';
|
import { provide, requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import usePipeline from '~/compositions/usePipeline';
|
import usePipeline from '~/compositions/usePipeline';
|
||||||
import { useRouteBack } from '~/compositions/useRouteBack';
|
import { useRouteBack } from '~/compositions/useRouteBack';
|
||||||
import type { PipelineConfig, Repo, RepoPermissions } from '~/lib/api/types';
|
import type { Pipeline, PipelineConfig } from '~/lib/api/types';
|
||||||
import { usePipelineStore } from '~/store/pipelines';
|
import { usePipelineStore } from '~/store/pipelines';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -139,15 +139,12 @@ const pipelineStore = usePipelineStore();
|
||||||
const pipelineId = toRef(props, 'pipelineId');
|
const pipelineId = toRef(props, 'pipelineId');
|
||||||
const _repoId = toRef(props, 'repoId');
|
const _repoId = toRef(props, 'repoId');
|
||||||
const repositoryId = computed(() => Number.parseInt(_repoId.value, 10));
|
const repositoryId = computed(() => Number.parseInt(_repoId.value, 10));
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
const repoPermissions = requiredInject('repo-permissions');
|
||||||
if (!repo || !repoPermissions) {
|
|
||||||
throw new Error('Unexpected: "repo" & "repoPermissions" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const pipeline = pipelineStore.getPipeline(repositoryId, pipelineId);
|
const pipeline = pipelineStore.getPipeline(repositoryId, pipelineId);
|
||||||
const { since, duration, created, message, shortMessage } = usePipeline(pipeline);
|
const { since, duration, created, message, shortMessage } = usePipeline(pipeline);
|
||||||
provide('pipeline', pipeline);
|
provide('pipeline', pipeline as Ref<Pipeline>); // can't be undefined because of v-if in template
|
||||||
|
|
||||||
const pipelineConfigs = ref<PipelineConfig[]>();
|
const pipelineConfigs = ref<PipelineConfig[]>();
|
||||||
provide('pipeline-configs', pipelineConfigs);
|
provide('pipeline-configs', pipelineConfigs);
|
||||||
|
@ -163,10 +160,6 @@ watch(
|
||||||
const showDeployPipelinePopup = ref(false);
|
const showDeployPipelinePopup = ref(false);
|
||||||
|
|
||||||
async function loadPipeline(): Promise<void> {
|
async function loadPipeline(): Promise<void> {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await pipelineStore.loadPipeline(repo.value.id, Number.parseInt(pipelineId.value, 10));
|
await pipelineStore.loadPipeline(repo.value.id, Number.parseInt(pipelineId.value, 10));
|
||||||
|
|
||||||
if (!pipeline.value?.number) {
|
if (!pipeline.value?.number) {
|
||||||
|
@ -177,10 +170,6 @@ async function loadPipeline(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { doSubmit: cancelPipeline, isLoading: isCancelingPipeline } = useAsyncAction(async () => {
|
const { doSubmit: cancelPipeline, isLoading: isCancelingPipeline } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pipeline.value?.number) {
|
if (!pipeline.value?.number) {
|
||||||
throw new Error('Unexpected: Pipeline number not found');
|
throw new Error('Unexpected: Pipeline number not found');
|
||||||
}
|
}
|
||||||
|
@ -190,10 +179,6 @@ const { doSubmit: cancelPipeline, isLoading: isCancelingPipeline } = useAsyncAct
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: restartPipeline, isLoading: isRestartingPipeline } = useAsyncAction(async () => {
|
const { doSubmit: restartPipeline, isLoading: isRestartingPipeline } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
const newPipeline = await apiClient.restartPipeline(repo.value.id, pipelineId.value, {
|
const newPipeline = await apiClient.restartPipeline(repo.value.id, pipelineId.value, {
|
||||||
fork: true,
|
fork: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,8 +42,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject } from 'vue';
|
import { computed } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -51,30 +50,22 @@ import Button from '~/components/atomic/Button.vue';
|
||||||
import Settings from '~/components/layout/Settings.vue';
|
import Settings from '~/components/layout/Settings.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import type { Repo } from '~/lib/api/types';
|
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
|
|
||||||
const { doSubmit: repairRepo, isLoading: isRepairingRepo } = useAsyncAction(async () => {
|
const { doSubmit: repairRepo, isLoading: isRepairingRepo } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.repairRepo(repo.value.id);
|
await apiClient.repairRepo(repo.value.id);
|
||||||
notifications.notify({ title: i18n.t('repo.settings.actions.repair.success'), type: 'success' });
|
notifications.notify({ title: i18n.t('repo.settings.actions.repair.success'), type: 'success' });
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deleteRepo, isLoading: isDeletingRepo } = useAsyncAction(async () => {
|
const { doSubmit: deleteRepo, isLoading: isDeletingRepo } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use proper dialog
|
// TODO: use proper dialog
|
||||||
// eslint-disable-next-line no-alert
|
// eslint-disable-next-line no-alert
|
||||||
if (!confirm(i18n.t('repo.settings.actions.delete.confirm'))) {
|
if (!confirm(i18n.t('repo.settings.actions.delete.confirm'))) {
|
||||||
|
@ -87,19 +78,11 @@ const { doSubmit: deleteRepo, isLoading: isDeletingRepo } = useAsyncAction(async
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: activateRepo, isLoading: isActivatingRepo } = useAsyncAction(async () => {
|
const { doSubmit: activateRepo, isLoading: isActivatingRepo } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.activateRepo(repo.value.forge_remote_id);
|
await apiClient.activateRepo(repo.value.forge_remote_id);
|
||||||
notifications.notify({ title: i18n.t('repo.settings.actions.enable.success'), type: 'success' });
|
notifications.notify({ title: i18n.t('repo.settings.actions.enable.success'), type: 'success' });
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deactivateRepo, isLoading: isDeactivatingRepo } = useAsyncAction(async () => {
|
const { doSubmit: deactivateRepo, isLoading: isDeactivatingRepo } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.deleteRepo(repo.value.id, false);
|
await apiClient.deleteRepo(repo.value.id, false);
|
||||||
notifications.notify({ title: i18n.t('repo.settings.actions.disable.success'), type: 'success' });
|
notifications.notify({ title: i18n.t('repo.settings.actions.disable.success'), type: 'success' });
|
||||||
await router.replace({ name: 'repos' });
|
await router.replace({ name: 'repos' });
|
||||||
|
|
|
@ -41,8 +41,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { computed, inject, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
import type { SelectOption } from '~/components/form/form.types';
|
import type { SelectOption } from '~/components/form/form.types';
|
||||||
import InputField from '~/components/form/InputField.vue';
|
import InputField from '~/components/form/InputField.vue';
|
||||||
|
@ -50,27 +49,19 @@ import SelectField from '~/components/form/SelectField.vue';
|
||||||
import Settings from '~/components/layout/Settings.vue';
|
import Settings from '~/components/layout/Settings.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import useConfig from '~/compositions/useConfig';
|
import useConfig from '~/compositions/useConfig';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import { usePaginate } from '~/compositions/usePaginate';
|
import { usePaginate } from '~/compositions/usePaginate';
|
||||||
import type { Repo } from '~/lib/api/types';
|
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
|
|
||||||
const badgeType = useStorage('woodpecker:last-badge-type', 'markdown');
|
const badgeType = useStorage('woodpecker:last-badge-type', 'markdown');
|
||||||
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultBranch = computed(() => repo.value.default_branch);
|
const defaultBranch = computed(() => repo.value.default_branch);
|
||||||
const branches = ref<SelectOption[]>([]);
|
const branches = ref<SelectOption[]>([]);
|
||||||
const branch = ref<string>('');
|
const branch = ref<string>('');
|
||||||
|
|
||||||
async function loadBranches() {
|
async function loadBranches() {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
branches.value = (await usePaginate((page) => apiClient.getRepoBranches(repo.value.id, { page })))
|
branches.value = (await usePaginate((page) => apiClient.getRepoBranches(repo.value.id, { page })))
|
||||||
.map((b) => ({
|
.map((b) => ({
|
||||||
value: b,
|
value: b,
|
||||||
|
@ -96,10 +87,6 @@ const repoUrl = computed(
|
||||||
);
|
);
|
||||||
|
|
||||||
const badgeContent = computed(() => {
|
const badgeContent = computed(() => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (badgeType.value === 'url') {
|
if (badgeType.value === 'url') {
|
||||||
return `${baseUrl}${badgeUrl.value}`;
|
return `${baseUrl}${badgeUrl.value}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
@ -118,35 +117,28 @@ import Settings from '~/components/layout/Settings.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
import { useDate } from '~/compositions/useDate';
|
import { useDate } from '~/compositions/useDate';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import type { Cron, Repo } from '~/lib/api/types';
|
import type { Cron } from '~/lib/api/types';
|
||||||
import router from '~/router';
|
import router from '~/router';
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const selectedCron = ref<Partial<Cron>>();
|
const selectedCron = ref<Partial<Cron>>();
|
||||||
const isEditingCron = computed(() => !!selectedCron.value?.id);
|
const isEditingCron = computed(() => !!selectedCron.value?.id);
|
||||||
const date = useDate();
|
const date = useDate();
|
||||||
|
|
||||||
async function loadCrons(page: number): Promise<Cron[] | null> {
|
async function loadCrons(page: number): Promise<Cron[] | null> {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getCronList(repo.value.id, { page });
|
return apiClient.getCronList(repo.value.id, { page });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { resetPage, data: crons } = usePagination(loadCrons, () => !selectedCron.value);
|
const { resetPage, data: crons } = usePagination(loadCrons, () => !selectedCron.value);
|
||||||
|
|
||||||
const { doSubmit: createCron, isLoading: isSaving } = useAsyncAction(async () => {
|
const { doSubmit: createCron, isLoading: isSaving } = useAsyncAction(async () => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedCron.value) {
|
if (!selectedCron.value) {
|
||||||
throw new Error("Unexpected: Can't get cron");
|
throw new Error("Unexpected: Can't get cron");
|
||||||
}
|
}
|
||||||
|
@ -165,20 +157,12 @@ const { doSubmit: createCron, isLoading: isSaving } = useAsyncAction(async () =>
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deleteCron, isLoading: isDeleting } = useAsyncAction(async (_cron: Cron) => {
|
const { doSubmit: deleteCron, isLoading: isDeleting } = useAsyncAction(async (_cron: Cron) => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.deleteCron(repo.value.id, _cron.id);
|
await apiClient.deleteCron(repo.value.id, _cron.id);
|
||||||
notifications.notify({ title: i18n.t('repo.settings.crons.deleted'), type: 'success' });
|
notifications.notify({ title: i18n.t('repo.settings.crons.deleted'), type: 'success' });
|
||||||
resetPage();
|
resetPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: runCron } = useAsyncAction(async (_cron: Cron) => {
|
const { doSubmit: runCron } = useAsyncAction(async (_cron: Cron) => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
const pipeline = await apiClient.runCron(repo.value.id, _cron.id);
|
const pipeline = await apiClient.runCron(repo.value.id, _cron.id);
|
||||||
await router.push({
|
await router.push({
|
||||||
name: 'repo-pipeline',
|
name: 'repo-pipeline',
|
||||||
|
|
|
@ -171,8 +171,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
@ -187,9 +186,10 @@ import Settings from '~/components/layout/Settings.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
import useAuthentication from '~/compositions/useAuthentication';
|
import useAuthentication from '~/compositions/useAuthentication';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { RepoRequireApproval, RepoVisibility, WebhookEvents } from '~/lib/api/types';
|
import { RepoRequireApproval, RepoVisibility, WebhookEvents } from '~/lib/api/types';
|
||||||
import type { Repo, RepoSettings } from '~/lib/api/types';
|
import type { RepoSettings } from '~/lib/api/types';
|
||||||
import { useRepoStore } from '~/store/repos';
|
import { useRepoStore } from '~/store/repos';
|
||||||
|
|
||||||
const apiClient = useApiClient();
|
const apiClient = useApiClient();
|
||||||
|
@ -198,14 +198,10 @@ const { user } = useAuthentication();
|
||||||
const repoStore = useRepoStore();
|
const repoStore = useRepoStore();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const repoSettings = ref<RepoSettings>();
|
const repoSettings = ref<RepoSettings>();
|
||||||
|
|
||||||
function loadRepoSettings() {
|
function loadRepoSettings() {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
repoSettings.value = {
|
repoSettings.value = {
|
||||||
config_file: repo.value.config_file,
|
config_file: repo.value.config_file,
|
||||||
timeout: repo.value.timeout,
|
timeout: repo.value.timeout,
|
||||||
|
@ -221,19 +217,11 @@ function loadRepoSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadRepo() {
|
async function loadRepo() {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
await repoStore.loadRepo(repo.value.id);
|
await repoStore.loadRepo(repo.value.id);
|
||||||
loadRepoSettings();
|
loadRepoSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { doSubmit: saveRepoSettings, isLoading: isSaving } = useAsyncAction(async () => {
|
const { doSubmit: saveRepoSettings, isLoading: isSaving } = useAsyncAction(async () => {
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo should be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!repoSettings.value) {
|
if (!repoSettings.value) {
|
||||||
throw new Error('Unexpected: Repo-Settings should be set');
|
throw new Error('Unexpected: Repo-Settings should be set');
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
@ -40,9 +39,10 @@ import RegistryEdit from '~/components/registry/RegistryEdit.vue';
|
||||||
import RegistryList from '~/components/registry/RegistryList.vue';
|
import RegistryList from '~/components/registry/RegistryList.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import type { Registry, Repo } from '~/lib/api/types';
|
import type { Registry } from '~/lib/api/types';
|
||||||
|
|
||||||
const emptyRegistry: Partial<Registry> = {
|
const emptyRegistry: Partial<Registry> = {
|
||||||
address: '',
|
address: '',
|
||||||
|
@ -54,25 +54,17 @@ const apiClient = useApiClient();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const selectedRegistry = ref<Partial<Registry>>();
|
const selectedRegistry = ref<Partial<Registry>>();
|
||||||
const isEditingRegistry = computed(() => !!selectedRegistry.value?.id);
|
const isEditingRegistry = computed(() => !!selectedRegistry.value?.id);
|
||||||
|
|
||||||
async function loadRegistries(page: number): Promise<Registry[] | null> {
|
async function loadRegistries(page: number): Promise<Registry[] | null> {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getRegistryList(repo.value.id, { page });
|
return apiClient.getRegistryList(repo.value.id, { page });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { resetPage, data: registries } = usePagination(loadRegistries, () => !selectedRegistry.value);
|
const { resetPage, data: registries } = usePagination(loadRegistries, () => !selectedRegistry.value);
|
||||||
|
|
||||||
const { doSubmit: createRegistry, isLoading: isSaving } = useAsyncAction(async () => {
|
const { doSubmit: createRegistry, isLoading: isSaving } = useAsyncAction(async () => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedRegistry.value) {
|
if (!selectedRegistry.value) {
|
||||||
throw new Error("Unexpected: Can't get registry");
|
throw new Error("Unexpected: Can't get registry");
|
||||||
}
|
}
|
||||||
|
@ -91,10 +83,6 @@ const { doSubmit: createRegistry, isLoading: isSaving } = useAsyncAction(async (
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deleteRegistry, isLoading: isDeleting } = useAsyncAction(async (_registry: Registry) => {
|
const { doSubmit: deleteRegistry, isLoading: isDeleting } = useAsyncAction(async (_registry: Registry) => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
const registryAddress = encodeURIComponent(_registry.address);
|
const registryAddress = encodeURIComponent(_registry.address);
|
||||||
await apiClient.deleteRegistry(repo.value.id, registryAddress);
|
await apiClient.deleteRegistry(repo.value.id, registryAddress);
|
||||||
notifications.notify({ title: i18n.t('registries.deleted'), type: 'success' });
|
notifications.notify({ title: i18n.t('registries.deleted'), type: 'success' });
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<Scaffold enable-tabs :go-back="goBack">
|
<Scaffold enable-tabs :go-back="goBack">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>
|
<span>
|
||||||
<router-link :to="{ name: 'org', params: { orgId: repo!.org_id } }" class="hover:underline">{{
|
<router-link :to="{ name: 'org', params: { orgId: repo.org_id } }" class="hover:underline">{{
|
||||||
repo!.owner
|
repo!.owner
|
||||||
/* eslint-disable-next-line @intlify/vue-i18n/no-raw-text */
|
/* eslint-disable-next-line @intlify/vue-i18n/no-raw-text */
|
||||||
}}</router-link>
|
}}</router-link>
|
||||||
|
@ -28,30 +28,22 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
||||||
import Tab from '~/components/layout/scaffold/Tab.vue';
|
import Tab from '~/components/layout/scaffold/Tab.vue';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { useRouteBack } from '~/compositions/useRouteBack';
|
import { useRouteBack } from '~/compositions/useRouteBack';
|
||||||
import type { Repo, RepoPermissions } from '~/lib/api/types';
|
|
||||||
|
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
const repoPermissions = requiredInject('repo-permissions');
|
||||||
if (!repoPermissions) {
|
const repo = requiredInject('repo');
|
||||||
throw new Error('Unexpected: "repoPermissions" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: "repo" should be provided at this place');
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!repoPermissions.value.admin) {
|
if (!repoPermissions.value.admin) {
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { computed, inject, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
@ -35,10 +34,11 @@ import SecretEdit from '~/components/secrets/SecretEdit.vue';
|
||||||
import SecretList from '~/components/secrets/SecretList.vue';
|
import SecretList from '~/components/secrets/SecretList.vue';
|
||||||
import useApiClient from '~/compositions/useApiClient';
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
import { useAsyncAction } from '~/compositions/useAsyncAction';
|
||||||
|
import { requiredInject } from '~/compositions/useInjectProvide';
|
||||||
import useNotifications from '~/compositions/useNotifications';
|
import useNotifications from '~/compositions/useNotifications';
|
||||||
import { usePagination } from '~/compositions/usePaginate';
|
import { usePagination } from '~/compositions/usePaginate';
|
||||||
import { WebhookEvents } from '~/lib/api/types';
|
import { WebhookEvents } from '~/lib/api/types';
|
||||||
import type { Repo, Secret } from '~/lib/api/types';
|
import type { Secret } from '~/lib/api/types';
|
||||||
|
|
||||||
const emptySecret: Partial<Secret> = {
|
const emptySecret: Partial<Secret> = {
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -51,15 +51,11 @@ const apiClient = useApiClient();
|
||||||
const notifications = useNotifications();
|
const notifications = useNotifications();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
const repo = requiredInject('repo');
|
||||||
const selectedSecret = ref<Partial<Secret>>();
|
const selectedSecret = ref<Partial<Secret>>();
|
||||||
const isEditingSecret = computed(() => !!selectedSecret.value?.id);
|
const isEditingSecret = computed(() => !!selectedSecret.value?.id);
|
||||||
|
|
||||||
async function loadSecrets(page: number, level: 'repo' | 'org' | 'global'): Promise<Secret[] | null> {
|
async function loadSecrets(page: number, level: 'repo' | 'org' | 'global'): Promise<Secret[] | null> {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 'repo':
|
case 'repo':
|
||||||
return apiClient.getSecretList(repo.value.id, { page });
|
return apiClient.getSecretList(repo.value.id, { page });
|
||||||
|
@ -103,10 +99,6 @@ const secrets = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async () => {
|
const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async () => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedSecret.value) {
|
if (!selectedSecret.value) {
|
||||||
throw new Error("Unexpected: Can't get secret");
|
throw new Error("Unexpected: Can't get secret");
|
||||||
}
|
}
|
||||||
|
@ -125,10 +117,6 @@ const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async ()
|
||||||
});
|
});
|
||||||
|
|
||||||
const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (_secret: Secret) => {
|
const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (_secret: Secret) => {
|
||||||
if (!repo?.value) {
|
|
||||||
throw new Error("Unexpected: Can't load repo");
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.deleteSecret(repo.value.id, _secret.name);
|
await apiClient.deleteSecret(repo.value.id, _secret.name);
|
||||||
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
||||||
await resetPage();
|
await resetPage();
|
||||||
|
|
Loading…
Reference in a new issue