diff --git a/web/src/components/layout/scaffold/Scaffold.vue b/web/src/components/layout/scaffold/Scaffold.vue index ba04c7e6a..16a21f88c 100644 --- a/web/src/components/layout/scaffold/Scaffold.vue +++ b/web/src/components/layout/scaffold/Scaffold.vue @@ -18,8 +18,6 @@ diff --git a/web/src/components/layout/scaffold/Tab.vue b/web/src/components/layout/scaffold/Tab.vue index 23acb9799..3bc833a3e 100644 --- a/web/src/components/layout/scaffold/Tab.vue +++ b/web/src/components/layout/scaffold/Tab.vue @@ -1,38 +1,40 @@ - + diff --git a/web/src/components/layout/scaffold/Tabs.vue b/web/src/components/layout/scaffold/Tabs.vue index d74cdc0f0..090389800 100644 --- a/web/src/components/layout/scaffold/Tabs.vue +++ b/web/src/components/layout/scaffold/Tabs.vue @@ -1,46 +1,27 @@ diff --git a/web/src/compositions/useInjectProvide.ts b/web/src/compositions/useInjectProvide.ts index 5fc7685a8..949950eaa 100644 --- a/web/src/compositions/useInjectProvide.ts +++ b/web/src/compositions/useInjectProvide.ts @@ -1,12 +1,17 @@ import type { InjectionKey, Ref } from 'vue'; import { inject as vueInject, provide as vueProvide } from 'vue'; -import type { Org, OrgPermissions, Repo } from '~/lib/api/types'; +import type { Org, OrgPermissions, Pipeline, PipelineConfig, Repo } from '~/lib/api/types'; + +import type { Tab } from './useTabs'; export interface InjectKeys { repo: Ref; org: Ref; 'org-permissions': Ref; + pipeline: Ref; + 'pipeline-configs': Ref; + tabs: Ref; } export function inject(key: T): InjectKeys[T] { diff --git a/web/src/compositions/useTabs.ts b/web/src/compositions/useTabs.ts index a9538979a..6f8bb626c 100644 --- a/web/src/compositions/useTabs.ts +++ b/web/src/compositions/useTabs.ts @@ -1,49 +1,24 @@ -import { inject, onMounted, provide, ref, type Ref } from 'vue'; -import { useRoute } from 'vue-router'; +import { ref } from 'vue'; +import type { RouteLocationRaw } from 'vue-router'; import type { IconNames } from '~/components/atomic/Icon.vue'; +import { inject, provide } from './useInjectProvide'; + export interface Tab { - id: string; + to: RouteLocationRaw; title: string; icon?: IconNames; iconClass?: string; + matchChildren?: boolean; } -export function useTabsProvider({ - activeTab, - disableUrlHashMode, -}: { - activeTab: Ref; - disableUrlHashMode: Ref; -}) { - const route = useRoute(); - +export function useTabsProvider() { const tabs = ref([]); - provide('tabs', tabs); - provide('disable-url-hash-mode', disableUrlHashMode); - provide('active-tab', activeTab); - - onMounted(() => { - if (activeTab.value !== undefined) { - return; - } - - const hashTab = route.hash.replace(/^#/, ''); - - activeTab.value = hashTab || tabs.value[0].id; - }); } export function useTabsClient() { - const tabs = inject>('tabs'); - const disableUrlHashMode = inject>('disable-url-hash-mode'); - const activeTab = inject>('active-tab'); - - if (activeTab === undefined || tabs === undefined || disableUrlHashMode === undefined) { - throw new Error('Please use this "useTabsClient" composition inside a component running "useTabsProvider".'); - } - - return { activeTab, tabs, disableUrlHashMode }; + const tabs = inject('tabs'); + return { tabs }; } diff --git a/web/src/router.ts b/web/src/router.ts index ad807561b..18d3d1edd 100644 --- a/web/src/router.ts +++ b/web/src/router.ts @@ -42,29 +42,38 @@ const routes: RouteRecordRaw[] = [ }, { path: 'branches', - name: 'repo-branches', - component: (): Component => import('~/views/repo/RepoBranches.vue'), meta: { repoHeader: true }, + children: [ + { + path: '', + name: 'repo-branches', + component: (): Component => import('~/views/repo/RepoBranches.vue'), + }, + { + path: ':branch', + name: 'repo-branch', + component: (): Component => import('~/views/repo/RepoBranch.vue'), + props: (route) => ({ branch: route.params.branch }), + }, + ], }, - { - path: 'branches/:branch', - name: 'repo-branch', - component: (): Component => import('~/views/repo/RepoBranch.vue'), - meta: { repoHeader: true }, - props: (route) => ({ branch: route.params.branch }), - }, + { path: 'pull-requests', - name: 'repo-pull-requests', - component: (): Component => import('~/views/repo/RepoPullRequests.vue'), meta: { repoHeader: true }, - }, - { - path: 'pull-requests/:pullRequest', - name: 'repo-pull-request', - component: (): Component => import('~/views/repo/RepoPullRequest.vue'), - meta: { repoHeader: true }, - props: (route) => ({ pullRequest: route.params.pullRequest }), + children: [ + { + path: '', + name: 'repo-pull-requests', + component: (): Component => import('~/views/repo/RepoPullRequests.vue'), + }, + { + path: ':pullRequest', + name: 'repo-pull-request', + component: (): Component => import('~/views/repo/RepoPullRequest.vue'), + props: (route) => ({ pullRequest: route.params.pullRequest }), + }, + ], }, { path: 'pipeline/:pipelineId', @@ -98,15 +107,53 @@ const routes: RouteRecordRaw[] = [ path: 'debug', name: 'repo-pipeline-debug', component: (): Component => import('~/views/repo/pipeline/PipelineDebug.vue'), + props: true, }, ], }, { path: 'settings', - name: 'repo-settings', - component: (): Component => import('~/views/repo/RepoSettings.vue'), + component: (): Component => import('~/views/repo/settings/RepoSettings.vue'), meta: { authentication: 'required' }, props: true, + children: [ + { + path: '', + name: 'repo-settings', + component: (): Component => import('~/views/repo/settings/General.vue'), + props: true, + }, + { + path: 'secrets', + name: 'repo-settings-secrets', + component: (): Component => import('~/views/repo/settings/Secrets.vue'), + props: true, + }, + { + path: 'registries', + name: 'repo-settings-registries', + component: (): Component => import('~/views/repo/settings/Registries.vue'), + props: true, + }, + { + path: 'crons', + name: 'repo-settings-crons', + component: (): Component => import('~/views/repo/settings/Crons.vue'), + props: true, + }, + { + path: 'badge', + name: 'repo-settings-badge', + component: (): Component => import('~/views/repo/settings/Badge.vue'), + props: true, + }, + { + path: 'actions', + name: 'repo-settings-actions', + component: (): Component => import('~/views/repo/settings/Actions.vue'), + props: true, + }, + ], }, { path: 'manual', @@ -137,9 +184,29 @@ const routes: RouteRecordRaw[] = [ { path: 'settings', name: 'org-settings', - component: (): Component => import('~/views/org/OrgSettings.vue'), + component: (): Component => import('~/views/org/settings/OrgSettingsWrapper.vue'), meta: { authentication: 'required' }, props: true, + children: [ + { + path: 'secrets', + name: 'org-settings-secrets', + component: (): Component => import('~/views/org/settings/OrgSecrets.vue'), + props: true, + }, + { + path: 'registries', + name: 'org-settings-registries', + component: (): Component => import('~/views/org/settings/OrgRegistries.vue'), + props: true, + }, + { + path: 'agents', + name: 'org-settings-agents', + component: (): Component => import('~/views/org/settings/OrgAgents.vue'), + props: true, + }, + ], }, ], }, @@ -150,18 +217,98 @@ const routes: RouteRecordRaw[] = [ }, { path: `${rootPath}/admin`, - name: 'admin-settings', - component: (): Component => import('~/views/admin/AdminSettings.vue'), + component: (): Component => import('~/views/admin/AdminSettingsWrapper.vue'), props: true, meta: { authentication: 'required' }, + children: [ + { + path: '', + name: 'admin-settings', + component: (): Component => import('~/views/admin/AdminInfo.vue'), + props: true, + }, + { + path: 'secrets', + name: 'admin-settings-secrets', + component: (): Component => import('~/views/admin/AdminSecrets.vue'), + props: true, + }, + { + path: 'registries', + name: 'admin-settings-registries', + component: (): Component => import('~/views/admin/AdminRegistries.vue'), + props: true, + }, + { + path: 'repos', + name: 'admin-settings-repos', + component: (): Component => import('~/views/admin/AdminRepos.vue'), + props: true, + }, + { + path: 'users', + name: 'admin-settings-users', + component: (): Component => import('~/views/admin/AdminUsers.vue'), + props: true, + }, + { + path: 'orgs', + name: 'admin-settings-orgs', + component: (): Component => import('~/views/admin/AdminOrgs.vue'), + props: true, + }, + { + path: 'agents', + name: 'admin-settings-agents', + component: (): Component => import('~/views/admin/AdminAgents.vue'), + props: true, + }, + { + path: 'queue', + name: 'admin-settings-queue', + component: (): Component => import('~/views/admin/AdminQueue.vue'), + props: true, + }, + ], }, { path: `${rootPath}/user`, - name: 'user', - component: (): Component => import('~/views/User.vue'), + component: (): Component => import('~/views/user/UserWrapper.vue'), meta: { authentication: 'required' }, props: true, + children: [ + { + path: '', + name: 'user', + component: (): Component => import('~/views/user/UserGeneral.vue'), + props: true, + }, + { + path: 'secrets', + name: 'user-secrets', + component: (): Component => import('~/views/user/UserSecrets.vue'), + props: true, + }, + { + path: 'registries', + name: 'user-registries', + component: (): Component => import('~/views/user/UserRegistries.vue'), + props: true, + }, + { + path: 'cli-and-api', + name: 'user-cli-and-api', + component: (): Component => import('~/views/user/UserCLIAndAPI.vue'), + props: true, + }, + { + path: 'agents', + name: 'user-agents', + component: (): Component => import('~/views/user/UserAgents.vue'), + props: true, + }, + ], }, { path: `${rootPath}/login`, diff --git a/web/src/views/User.vue b/web/src/views/User.vue deleted file mode 100644 index 14a5ad934..000000000 --- a/web/src/views/User.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - diff --git a/web/src/components/admin/settings/AdminAgentsTab.vue b/web/src/views/admin/AdminAgents.vue similarity index 100% rename from web/src/components/admin/settings/AdminAgentsTab.vue rename to web/src/views/admin/AdminAgents.vue diff --git a/web/src/components/admin/settings/AdminInfoTab.vue b/web/src/views/admin/AdminInfo.vue similarity index 100% rename from web/src/components/admin/settings/AdminInfoTab.vue rename to web/src/views/admin/AdminInfo.vue diff --git a/web/src/components/admin/settings/AdminOrgsTab.vue b/web/src/views/admin/AdminOrgs.vue similarity index 100% rename from web/src/components/admin/settings/AdminOrgsTab.vue rename to web/src/views/admin/AdminOrgs.vue diff --git a/web/src/components/admin/settings/AdminQueueTab.vue b/web/src/views/admin/AdminQueue.vue similarity index 98% rename from web/src/components/admin/settings/AdminQueueTab.vue rename to web/src/views/admin/AdminQueue.vue index 4469fb3b0..660fe34c1 100644 --- a/web/src/components/admin/settings/AdminQueueTab.vue +++ b/web/src/views/admin/AdminQueue.vue @@ -78,6 +78,7 @@ import { computed, onBeforeUnmount, onMounted, ref } from 'vue'; import { useI18n } from 'vue-i18n'; +import AdminQueueStats from '~/components/admin/settings/queue/AdminQueueStats.vue'; import Badge from '~/components/atomic/Badge.vue'; import Button from '~/components/atomic/Button.vue'; import Icon from '~/components/atomic/Icon.vue'; @@ -87,8 +88,6 @@ import useApiClient from '~/compositions/useApiClient'; import useNotifications from '~/compositions/useNotifications'; import type { QueueInfo } from '~/lib/api/types'; -import AdminQueueStats from './queue/AdminQueueStats.vue'; - const apiClient = useApiClient(); const notifications = useNotifications(); const { t } = useI18n(); diff --git a/web/src/components/admin/settings/AdminRegistriesTab.vue b/web/src/views/admin/AdminRegistries.vue similarity index 100% rename from web/src/components/admin/settings/AdminRegistriesTab.vue rename to web/src/views/admin/AdminRegistries.vue diff --git a/web/src/components/admin/settings/AdminReposTab.vue b/web/src/views/admin/AdminRepos.vue similarity index 100% rename from web/src/components/admin/settings/AdminReposTab.vue rename to web/src/views/admin/AdminRepos.vue diff --git a/web/src/components/admin/settings/AdminSecretsTab.vue b/web/src/views/admin/AdminSecrets.vue similarity index 100% rename from web/src/components/admin/settings/AdminSecretsTab.vue rename to web/src/views/admin/AdminSecrets.vue diff --git a/web/src/views/admin/AdminSettings.vue b/web/src/views/admin/AdminSettings.vue deleted file mode 100644 index 3ff1d36af..000000000 --- a/web/src/views/admin/AdminSettings.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - diff --git a/web/src/views/admin/AdminSettingsWrapper.vue b/web/src/views/admin/AdminSettingsWrapper.vue new file mode 100644 index 000000000..da9a0c44b --- /dev/null +++ b/web/src/views/admin/AdminSettingsWrapper.vue @@ -0,0 +1,40 @@ + + + diff --git a/web/src/components/admin/settings/AdminUsersTab.vue b/web/src/views/admin/AdminUsers.vue similarity index 100% rename from web/src/components/admin/settings/AdminUsersTab.vue rename to web/src/views/admin/AdminUsers.vue diff --git a/web/src/views/org/OrgRepos.vue b/web/src/views/org/OrgRepos.vue index 84aeec8b9..0c895ac23 100644 --- a/web/src/views/org/OrgRepos.vue +++ b/web/src/views/org/OrgRepos.vue @@ -8,7 +8,7 @@ diff --git a/web/src/views/org/OrgWrapper.vue b/web/src/views/org/OrgWrapper.vue index 3ba7bfc86..a73099603 100644 --- a/web/src/views/org/OrgWrapper.vue +++ b/web/src/views/org/OrgWrapper.vue @@ -7,7 +7,7 @@ - - - + + + - - - - - - - + @@ -32,9 +30,6 @@ import { useRouter } from 'vue-router'; import Scaffold from '~/components/layout/scaffold/Scaffold.vue'; import Tab from '~/components/layout/scaffold/Tab.vue'; -import OrgAgentsTab from '~/components/org/settings/OrgAgentsTab.vue'; -import OrgRegistriesTab from '~/components/org/settings/OrgRegistriesTab.vue'; -import OrgSecretsTab from '~/components/org/settings/OrgSecretsTab.vue'; import useConfig from '~/compositions/useConfig'; import { inject } from '~/compositions/useInjectProvide'; import useNotifications from '~/compositions/useNotifications'; diff --git a/web/src/views/repo/RepoWrapper.vue b/web/src/views/repo/RepoWrapper.vue index a6a798566..522dbe411 100644 --- a/web/src/views/repo/RepoWrapper.vue +++ b/web/src/views/repo/RepoWrapper.vue @@ -1,10 +1,5 @@ @@ -44,12 +34,6 @@ import { useRouter } from 'vue-router'; import Scaffold from '~/components/layout/scaffold/Scaffold.vue'; import Tab from '~/components/layout/scaffold/Tab.vue'; -import ActionsTab from '~/components/repo/settings/ActionsTab.vue'; -import BadgeTab from '~/components/repo/settings/BadgeTab.vue'; -import CronTab from '~/components/repo/settings/CronTab.vue'; -import GeneralTab from '~/components/repo/settings/GeneralTab.vue'; -import RegistriesTab from '~/components/repo/settings/RegistriesTab.vue'; -import SecretsTab from '~/components/repo/settings/SecretsTab.vue'; import useNotifications from '~/compositions/useNotifications'; import { useRouteBack } from '~/compositions/useRouteBack'; import type { Repo, RepoPermissions } from '~/lib/api/types'; diff --git a/web/src/components/repo/settings/SecretsTab.vue b/web/src/views/repo/settings/Secrets.vue similarity index 100% rename from web/src/components/repo/settings/SecretsTab.vue rename to web/src/views/repo/settings/Secrets.vue diff --git a/web/src/components/user/UserAgentsTab.vue b/web/src/views/user/UserAgents.vue similarity index 100% rename from web/src/components/user/UserAgentsTab.vue rename to web/src/views/user/UserAgents.vue diff --git a/web/src/components/user/UserCLIAndAPITab.vue b/web/src/views/user/UserCLIAndAPI.vue similarity index 100% rename from web/src/components/user/UserCLIAndAPITab.vue rename to web/src/views/user/UserCLIAndAPI.vue diff --git a/web/src/components/user/UserGeneralTab.vue b/web/src/views/user/UserGeneral.vue similarity index 100% rename from web/src/components/user/UserGeneralTab.vue rename to web/src/views/user/UserGeneral.vue diff --git a/web/src/components/user/UserRegistriesTab.vue b/web/src/views/user/UserRegistries.vue similarity index 100% rename from web/src/components/user/UserRegistriesTab.vue rename to web/src/views/user/UserRegistries.vue diff --git a/web/src/components/user/UserSecretsTab.vue b/web/src/views/user/UserSecrets.vue similarity index 100% rename from web/src/components/user/UserSecretsTab.vue rename to web/src/views/user/UserSecrets.vue diff --git a/web/src/views/user/UserWrapper.vue b/web/src/views/user/UserWrapper.vue new file mode 100644 index 000000000..43cf4afd2 --- /dev/null +++ b/web/src/views/user/UserWrapper.vue @@ -0,0 +1,27 @@ + + +