This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
The following commit(s) were added to refs/heads/main by this push:
new cb92c4f ui: restructure src/ by role — shell / controls / state /
features / layer / render
cb92c4f is described below
commit cb92c4f747e3d549842409eb68e07339ad94c3b9
Author: Wu Sheng <[email protected]>
AuthorDate: Sat May 16 23:41:05 2026 +0800
ui: restructure src/ by role — shell / controls / state / features / layer
/ render
Apply the CLAUDE.md UI-layering principle to the codebase. Feature code
moves WITH its feature (high cohesion); shared keeps only feature-
agnostic primitives + helpers (low coupling).
Top-level layout:
api/ façade + scopes (unchanged)
shell/ AppShell / AppSidebar / AppTopbar / banners /
placeholders + router/index.ts + framework
composables (useLayers, useLandingOrder,
useOapInfo, useAdminFeatures)
controls/ time-range store, auto-refresh ticker +
subscriber, client-id (cross-cutting controls)
state/ auth, setup (global app state)
features/
auth/ LoginView
alarms/ AlarmsView + AlarmDetailPanel
setup/ SetupView + LayerSetupCard
admin/{layer-templates,alert-page}/
operate/{cluster,inspect,dsl,live-debug}/
+ operate/_shared/ (Modal, MonacoYaml, MonacoDiff,
RuleCard, DestructiveConfirm,
grouping — shared by dsl + live-debug)
DSL composable (useRuleEditor) co-located with dsl/;
debug composables co-located with live-debug/
layer/ LayerShell + LayerServiceSelector +
LayerTabPlaceholder + shared layer composables
(useLayerLanding/Endpoints/Instances +
useSelectedService/Instance/Endpoint), with
each tab in its own subfolder:
traces/ LayerTracesView + LayerZipkinTracesView +
NativeTraceWaterfall + TracePopout +
ZipkinTracePopout + useLayerTraces +
useZipkinTraces + useTracePopout +
useZipkinTracePopout
logs/ LayerLogsView + useLayerLogs
service-map/ LayerServiceMapView + useLayerTopology +
useTopologyIcons
endpoint-dependency/ LayerEndpointDependencyView + composable
profiling/ all 5 Layer*ProfilingView + ProfileFlameGraph +
ProfileStackTable + ProfileStackRow +
ProcessTopologyGraph (flame-graph renderers
used only by profiling)
render/ template-driven render layer
overview/ OverviewLanding + OverviewDashboardView +
useOverviewDashboard(s)
layer-dashboard/ LayerDashboardsView + useLayerDashboard
widgets/ AlarmsWidget / K8sSummaryWidget /
KpiTileWidget / MetricWidget /
PilotSummaryWidget / SectionBreak /
ServiceCountWidget / ValueFormat
components/ feature-agnostic shared primitives
primitives/ charts/ icons/
monaco/ utils/ assets/ unchanged
Net: 78 file moves + 182 imports rewritten across 58 files by script.
Empty source dirs (views/, stores/, composables/, components/{shell,
operate,overview,profile,trace}, router/) removed. CLAUDE.md UI-
layering principle updated to describe the landed shape. tsc / vue-tsc
/ license-eye all green. Pure restructure — no behavior changes.
---
CLAUDE.md | 18 +++---
apps/ui/src/{stores => controls}/autoRefresh.ts | 0
.../useClientId.ts => controls/clientId.ts} | 0
apps/ui/src/{stores => controls}/timeRange.ts | 0
.../useAutoRefreshSubscribe.ts | 2 +-
.../admin/alert-page}/AlertPageSetupView.vue | 0
.../layer-templates}/LayerDashboardsAdmin.vue | 0
.../admin/layer-templates}/widget-mock.ts | 0
.../alarms/AlarmDetailPanel.vue | 0
.../src/{views => features}/alarms/AlarmsView.vue | 2 +-
apps/ui/src/{views => features}/auth/LoginView.vue | 2 +-
.../operate/_shared}/DestructiveConfirm.vue | 0
.../operate => features/operate/_shared}/Modal.vue | 0
.../operate/_shared}/MonacoDiff.vue | 2 +-
.../operate/_shared}/MonacoYaml.vue | 2 +-
.../operate/_shared}/RuleCard.vue | 0
.../operate/_shared}/grouping.ts | 0
.../operate/cluster}/ClusterStatusView.vue | 4 +-
.../operate/dsl/DslCatalogView.vue | 6 +-
.../operate/dsl/DslDumpView.vue | 4 +-
.../operate/dsl/DslEditorView.vue | 12 ++--
.../operate/dsl/OalCatalogView.vue | 2 +-
.../operate/dsl/syntaxHighlight.ts | 0
.../operate/dsl}/useRuleEditor.ts | 0
.../operate/inspect}/InspectView.vue | 2 +-
.../operate/live-debug/DebugHistoryView.vue | 2 +-
.../operate/live-debug/DebugLal.vue | 4 +-
.../operate/live-debug/DebugMal.vue | 4 +-
.../operate/live-debug/DebugOal.vue | 4 +-
.../operate/live-debug/DebugView.vue | 0
.../operate/live-debug/LiveDebuggerView.vue | 2 +-
.../operate/live-debug/NodeCoverage.vue | 0
.../operate/live-debug/constants.ts | 0
.../operate/live-debug/oalEntityId.ts | 0
.../operate/live-debug/payload.ts | 0
.../operate/live-debug}/useDebugHistory.ts | 0
.../operate/live-debug}/useDebugSession.ts | 2 +-
.../{views => features}/setup/LayerSetupCard.vue | 2 +-
.../ui/src/{views => features}/setup/SetupView.vue | 2 +-
.../src/{views => }/layer/LayerServiceSelector.vue | 4 +-
apps/ui/src/{views => }/layer/LayerShell.vue | 12 ++--
.../src/{views => }/layer/LayerTabPlaceholder.vue | 2 +-
.../LayerEndpointDependencyView.vue | 14 ++---
.../useLayerEndpointDependency.ts | 2 +-
.../{views/layer => layer/logs}/LayerLogsView.vue | 20 +++----
.../{composables => layer/logs}/useLayerLogs.ts | 2 +-
.../profiling}/LayerAsyncProfilingView.vue | 6 +-
.../profiling}/LayerEBPFProfilingView.vue | 12 ++--
.../profiling}/LayerNetworkProfilingView.vue | 6 +-
.../profiling}/LayerPprofProfilingView.vue | 6 +-
.../profiling}/LayerTraceProfilingView.vue | 16 +++---
.../profiling}/ProcessTopologyGraph.vue | 0
.../profiling}/ProfileFlameGraph.vue | 0
.../profiling}/ProfileStackRow.vue | 0
.../profiling}/ProfileStackTable.vue | 0
.../service-map}/LayerServiceMapView.vue | 10 ++--
.../service-map}/useLayerTopology.ts | 2 +-
.../service-map}/useTopologyIcons.ts | 0
.../layer => layer/traces}/LayerTracesEntry.vue | 2 +-
.../layer => layer/traces}/LayerTracesView.vue | 18 +++---
.../traces}/LayerZipkinTracesView.vue | 4 +-
.../traces}/NativeTraceWaterfall.vue | 2 +-
.../trace => layer/traces}/TracePopout.vue | 6 +-
.../trace => layer/traces}/ZipkinTracePopout.vue | 4 +-
.../traces}/useLayerTraces.ts | 0
.../traces}/useTracePopout.ts | 0
.../traces}/useZipkinTracePopout.ts | 0
.../traces}/useZipkinTraces.ts | 0
.../{composables => layer}/useLayerEndpoints.ts | 0
.../{composables => layer}/useLayerInstances.ts | 0
.../src/{composables => layer}/useLayerLanding.ts | 2 +-
.../{composables => layer}/useSelectedEndpoint.ts | 0
.../{composables => layer}/useSelectedInstance.ts | 0
.../{composables => layer}/useSelectedService.ts | 0
apps/ui/src/main.ts | 4 +-
.../layer-dashboard}/LayerDashboardsView.vue | 20 +++----
.../layer-dashboard}/useLayerDashboard.ts | 2 +-
.../overview/OverviewDashboardView.vue | 18 +++---
.../{views => render}/overview/OverviewLanding.vue | 4 +-
.../overview}/useOverviewDashboard.ts | 0
.../overview}/useOverviewDashboards.ts | 2 +-
.../overview => render}/widgets/AlarmsWidget.vue | 0
.../widgets/K8sSummaryWidget.vue | 2 +-
.../overview => render}/widgets/KpiTileWidget.vue | 0
.../overview => render}/widgets/MetricWidget.vue | 0
.../widgets/PilotSummaryWidget.vue | 2 +-
.../overview => render}/widgets/SectionBreak.vue | 0
.../widgets/ServiceCountWidget.vue | 0
.../overview => render}/widgets/ValueFormat.ts | 0
.../{components => }/shell/AdminFeatureWarning.vue | 2 +-
apps/ui/src/{components => }/shell/AppShell.vue | 4 +-
apps/ui/src/{components => }/shell/AppSidebar.vue | 8 +--
apps/ui/src/{components => }/shell/AppTopbar.vue | 8 +--
.../shell/GlobalConnectivityBanner.vue | 2 +-
.../src/{views/landing => shell}/LandingView.vue | 0
apps/ui/src/{views => shell}/PlaceholderView.vue | 0
apps/ui/src/{ => shell}/router/index.ts | 64 +++++++++++-----------
.../src/{composables => shell}/useAdminFeatures.ts | 2 +-
.../src/{composables => shell}/useLandingOrder.ts | 2 +-
apps/ui/src/{composables => shell}/useLayers.ts | 0
apps/ui/src/{composables => shell}/useOapInfo.ts | 2 +-
apps/ui/src/{stores => state}/auth.ts | 0
apps/ui/src/{stores => state}/setup.ts | 2 +-
.../ui/src/{composables => utils}/metricCatalog.ts | 0
apps/ui/src/{composables => utils}/metricColor.ts | 0
105 files changed, 192 insertions(+), 190 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 183fdbf..f2fa042 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -74,14 +74,16 @@ Design tokens have been lifted into the runtime token CSS —
that copy is canon
- `util/` — pure helpers used anywhere (time formatting, MQE target/catalog
cache, trace-protocol cache).
- `user/` + `rbac/` — session/auth + verb policy, enforced at the http edge.
Don't import `client/` from `http/` directly; route through `logic/` so the
orchestration layer stays the seam.
-- **Layering — UI.** `apps/ui/src/` follows the same role-based grouping. When
adding code, decide which layer it belongs in *before* picking a file name. A
file mixing two layers means it should be split.
- - **Shell / framework** — `components/shell/`, `router/`, `App.vue`. Chrome
that every page lives inside (sidebar, topbar, breadcrumbs, layer-tab strip).
Knows about layers and routes, never about specific feature data.
- - **Cross-cutting state** — `stores/timeRange.ts`, the auto-refresh ticker,
`stores/auth.ts`, `composables/useClientId.ts`. Lives above pages; pages
subscribe, never own.
- - **API client** — `apps/ui/src/api/`. Façade `bff.<scope>.<method>()` is
the only path to the BFF; no `fetch()` calls anywhere else.
- - **Composables** — `composables/`. Reactive data fetchers + business state
(one composable per query family); pages compose them rather than inlining
`useQuery` inside a view.
- - **Static feature pages** — `views/operate/{inspect,dsl,live-debug}/`,
`views/alarms/`, `views/auth/`, `views/setup/`. Bespoke layouts (not
template-driven). Own their page-local components but reuse primitives + charts.
- - **Configurable render** — `views/overview/`, `views/layer/Layer*View.vue`
widget grids. Layout + widget set come from JSON templates served by the BFF;
the page is a generic renderer driven by config. New dashboards mean new
templates, not new Vue files.
- - **Primitives + shared visuals** — `components/primitives/`,
`components/charts/`, `components/icons/`. Stateless, no business logic. If a
primitive needs feature data, it's in the wrong layer.
+- **Layering — UI.** `apps/ui/src/` follows the same role-based grouping. The
guiding rule is **feature code stays cohesive with its feature; shared code is
feature-AGNOSTIC only** (fonts, styles, formatters, generic primitives, charts
wrappers). A component or composable that knows about a feature's data lives
WITH the feature, not in a shared pile. Features don't import from each other.
+ - **`api/`** — façade `bff.<scope>.<method>()` over the BFF. Only path to
HTTP; no `fetch()` calls anywhere else.
+ - **`shell/`** — chrome every page lives in (AppShell / AppSidebar /
AppTopbar / GlobalConnectivityBanner / AdminFeatureWarning / PlaceholderView /
LandingView), plus `router/index.ts` and the framework-level composables the
sidebar/topbar need (`useLayers`, `useLandingOrder`, `useOapInfo`,
`useAdminFeatures`). Knows about layers + routes, never about specific feature
data.
+ - **`controls/`** — cross-cutting controls owned by the topbar / shell. The
time-range store, the auto-refresh ticker + its subscriber, the per-session
client id. Pages subscribe, never own.
+ - **`state/`** — global app state (`auth`, `setup`). Pinia stores that
survive route changes.
+ - **`features/<feature>/`** — static feature pages. Each folder is fully
self-contained: its views, its composables, its feature-specific components.
Operate sub-features (`cluster/`, `inspect/`, `dsl/`, `live-debug/`) share
their cross-cutting bits via `features/operate/_shared/` (Modal / MonacoYaml /
MonacoDiff / RuleCard / DestructiveConfirm / grouping).
+ - **`layer/<tab>/`** — the per-layer drill-down stack. Top-level files are
the shell (`LayerShell`, `LayerServiceSelector`, `LayerTabPlaceholder`) plus
shared layer composables (`useLayerLanding`, `useLayerEndpoints`,
`useLayerInstances`, `useSelectedService/Instance/Endpoint`). Each tab
subfolder owns its view + composables + tab-specific components (e.g.
`layer/traces/` contains `LayerTracesView.vue` + `NativeTraceWaterfall.vue` +
`TracePopout.vue` + `useLayerTraces.ts`).
+ - **`render/`** — template-driven render. `render/overview/` and
`render/layer-dashboard/` are generic renderers driven by JSON templates from
the BFF; `render/widgets/` holds the reusable widget primitives (AlarmsWidget,
MetricWidget, ServiceCountWidget, …). New dashboards mean new templates, not
new Vue files.
+ - **`components/{primitives,charts,icons}/`** — feature-agnostic shared
building blocks. Stateless, no business logic. If a component starts needing
feature data, move it INTO the feature; don't enrich the shared pile.
+ - **`monaco/`, `utils/`, `assets/`** — same shared-is-feature-agnostic rule:
editor setup, formatters, stylesheets, icon SVGs. New helpers land here only if
more than one feature needs them and they don't carry feature semantics.
## Commits & PRs
diff --git a/apps/ui/src/stores/autoRefresh.ts
b/apps/ui/src/controls/autoRefresh.ts
similarity index 100%
rename from apps/ui/src/stores/autoRefresh.ts
rename to apps/ui/src/controls/autoRefresh.ts
diff --git a/apps/ui/src/composables/useClientId.ts
b/apps/ui/src/controls/clientId.ts
similarity index 100%
rename from apps/ui/src/composables/useClientId.ts
rename to apps/ui/src/controls/clientId.ts
diff --git a/apps/ui/src/stores/timeRange.ts b/apps/ui/src/controls/timeRange.ts
similarity index 100%
rename from apps/ui/src/stores/timeRange.ts
rename to apps/ui/src/controls/timeRange.ts
diff --git a/apps/ui/src/composables/useAutoRefreshSubscribe.ts
b/apps/ui/src/controls/useAutoRefreshSubscribe.ts
similarity index 95%
rename from apps/ui/src/composables/useAutoRefreshSubscribe.ts
rename to apps/ui/src/controls/useAutoRefreshSubscribe.ts
index 81eb441..6c7aec9 100644
--- a/apps/ui/src/composables/useAutoRefreshSubscribe.ts
+++ b/apps/ui/src/controls/useAutoRefreshSubscribe.ts
@@ -16,7 +16,7 @@
*/
import { watch } from 'vue';
-import { useAutoRefreshStore } from '@/stores/autoRefresh';
+import { useAutoRefreshStore } from '@/controls/autoRefresh';
/**
* Subscribe a refetch callback to the global auto-refresh ticker.
diff --git a/apps/ui/src/views/admin/AlertPageSetupView.vue
b/apps/ui/src/features/admin/alert-page/AlertPageSetupView.vue
similarity index 100%
rename from apps/ui/src/views/admin/AlertPageSetupView.vue
rename to apps/ui/src/features/admin/alert-page/AlertPageSetupView.vue
diff --git a/apps/ui/src/views/admin/LayerDashboardsAdmin.vue
b/apps/ui/src/features/admin/layer-templates/LayerDashboardsAdmin.vue
similarity index 100%
rename from apps/ui/src/views/admin/LayerDashboardsAdmin.vue
rename to apps/ui/src/features/admin/layer-templates/LayerDashboardsAdmin.vue
diff --git a/apps/ui/src/views/admin/widget-mock.ts
b/apps/ui/src/features/admin/layer-templates/widget-mock.ts
similarity index 100%
rename from apps/ui/src/views/admin/widget-mock.ts
rename to apps/ui/src/features/admin/layer-templates/widget-mock.ts
diff --git a/apps/ui/src/views/alarms/AlarmDetailPanel.vue
b/apps/ui/src/features/alarms/AlarmDetailPanel.vue
similarity index 100%
rename from apps/ui/src/views/alarms/AlarmDetailPanel.vue
rename to apps/ui/src/features/alarms/AlarmDetailPanel.vue
diff --git a/apps/ui/src/views/alarms/AlarmsView.vue
b/apps/ui/src/features/alarms/AlarmsView.vue
similarity index 99%
rename from apps/ui/src/views/alarms/AlarmsView.vue
rename to apps/ui/src/features/alarms/AlarmsView.vue
index 16e09e6..c8301b9 100644
--- a/apps/ui/src/views/alarms/AlarmsView.vue
+++ b/apps/ui/src/features/alarms/AlarmsView.vue
@@ -41,7 +41,7 @@ import {
type AlarmTrafficPoint,
type AlarmTrafficSeries,
} from '@/api/client';
-import { useLayers } from '@/composables/useLayers';
+import { useLayers } from '@/shell/useLayers';
import AlarmsTimeline from '@/components/charts/AlarmsTimeline.vue';
import AlarmDetailPanel from './AlarmDetailPanel.vue';
diff --git a/apps/ui/src/views/auth/LoginView.vue
b/apps/ui/src/features/auth/LoginView.vue
similarity index 99%
rename from apps/ui/src/views/auth/LoginView.vue
rename to apps/ui/src/features/auth/LoginView.vue
index dca2f21..c3d670a 100644
--- a/apps/ui/src/views/auth/LoginView.vue
+++ b/apps/ui/src/features/auth/LoginView.vue
@@ -18,7 +18,7 @@
import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import logoSw from '@/assets/icons/logo-sw.svg?raw';
-import { useAuthStore } from '@/stores/auth';
+import { useAuthStore } from '@/state/auth';
const auth = useAuthStore();
const router = useRouter();
diff --git a/apps/ui/src/components/operate/DestructiveConfirm.vue
b/apps/ui/src/features/operate/_shared/DestructiveConfirm.vue
similarity index 100%
rename from apps/ui/src/components/operate/DestructiveConfirm.vue
rename to apps/ui/src/features/operate/_shared/DestructiveConfirm.vue
diff --git a/apps/ui/src/components/operate/Modal.vue
b/apps/ui/src/features/operate/_shared/Modal.vue
similarity index 100%
rename from apps/ui/src/components/operate/Modal.vue
rename to apps/ui/src/features/operate/_shared/Modal.vue
diff --git a/apps/ui/src/components/operate/MonacoDiff.vue
b/apps/ui/src/features/operate/_shared/MonacoDiff.vue
similarity index 97%
rename from apps/ui/src/components/operate/MonacoDiff.vue
rename to apps/ui/src/features/operate/_shared/MonacoDiff.vue
index a86ac4a..a18f2dc 100644
--- a/apps/ui/src/components/operate/MonacoDiff.vue
+++ b/apps/ui/src/features/operate/_shared/MonacoDiff.vue
@@ -17,7 +17,7 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import * as monaco from 'monaco-editor';
-import { setupMonaco, RR_THEME_NAME } from '../../monaco/setup.js';
+import { setupMonaco, RR_THEME_NAME } from '../../../monaco/setup.js';
const props = defineProps<{
/** "before" — what's currently on the server (or bundled). */
diff --git a/apps/ui/src/components/operate/MonacoYaml.vue
b/apps/ui/src/features/operate/_shared/MonacoYaml.vue
similarity index 99%
rename from apps/ui/src/components/operate/MonacoYaml.vue
rename to apps/ui/src/features/operate/_shared/MonacoYaml.vue
index 7313526..076d70f 100644
--- a/apps/ui/src/components/operate/MonacoYaml.vue
+++ b/apps/ui/src/features/operate/_shared/MonacoYaml.vue
@@ -18,7 +18,7 @@
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import * as monaco from 'monaco-editor';
import type { Catalog } from '@skywalking-horizon-ui/api-client';
-import { setupMonaco, setModelCatalog, RR_THEME_NAME } from
'../../monaco/setup.js';
+import { setupMonaco, setModelCatalog, RR_THEME_NAME } from
'../../../monaco/setup.js';
const props = defineProps<{
modelValue: string;
diff --git a/apps/ui/src/components/operate/RuleCard.vue
b/apps/ui/src/features/operate/_shared/RuleCard.vue
similarity index 100%
rename from apps/ui/src/components/operate/RuleCard.vue
rename to apps/ui/src/features/operate/_shared/RuleCard.vue
diff --git a/apps/ui/src/components/operate/grouping.ts
b/apps/ui/src/features/operate/_shared/grouping.ts
similarity index 100%
rename from apps/ui/src/components/operate/grouping.ts
rename to apps/ui/src/features/operate/_shared/grouping.ts
diff --git a/apps/ui/src/views/operate/ClusterStatusView.vue
b/apps/ui/src/features/operate/cluster/ClusterStatusView.vue
similarity index 99%
rename from apps/ui/src/views/operate/ClusterStatusView.vue
rename to apps/ui/src/features/operate/cluster/ClusterStatusView.vue
index 758496e..5785acc 100644
--- a/apps/ui/src/views/operate/ClusterStatusView.vue
+++ b/apps/ui/src/features/operate/cluster/ClusterStatusView.vue
@@ -16,8 +16,8 @@
-->
<script setup lang="ts">
import { computed } from 'vue';
-import { useOapInfo } from '@/composables/useOapInfo';
-import { useAdminFeatures } from '@/composables/useAdminFeatures';
+import { useOapInfo } from '@/shell/useOapInfo';
+import { useAdminFeatures } from '@/shell/useAdminFeatures';
// Two-pane Cluster Status:
// - Pane A (graphql / :12800): version, server clock, timezone,
diff --git a/apps/ui/src/views/operate/dsl/DslCatalogView.vue
b/apps/ui/src/features/operate/dsl/DslCatalogView.vue
similarity index 98%
rename from apps/ui/src/views/operate/dsl/DslCatalogView.vue
rename to apps/ui/src/features/operate/dsl/DslCatalogView.vue
index 83c8e3c..99938b3 100644
--- a/apps/ui/src/views/operate/dsl/DslCatalogView.vue
+++ b/apps/ui/src/features/operate/dsl/DslCatalogView.vue
@@ -27,11 +27,11 @@ import {
type ListRow,
} from '@skywalking-horizon-ui/api-client';
import { bff } from '@/api/client';
-import { groupRules } from '@/components/operate/grouping';
-import RuleCard from '@/components/operate/RuleCard.vue';
+import { groupRules } from '@/features/operate/_shared/grouping';
+import RuleCard from '@/features/operate/_shared/RuleCard.vue';
import Pill from '@/components/primitives/Pill.vue';
import Btn from '@/components/primitives/Btn.vue';
-import AdminFeatureWarning from '@/components/shell/AdminFeatureWarning.vue';
+import AdminFeatureWarning from '@/shell/AdminFeatureWarning.vue';
const route = useRoute();
const router = useRouter();
diff --git a/apps/ui/src/views/operate/dsl/DslDumpView.vue
b/apps/ui/src/features/operate/dsl/DslDumpView.vue
similarity index 97%
rename from apps/ui/src/views/operate/dsl/DslDumpView.vue
rename to apps/ui/src/features/operate/dsl/DslDumpView.vue
index 518ebfd..490ff81 100644
--- a/apps/ui/src/views/operate/dsl/DslDumpView.vue
+++ b/apps/ui/src/features/operate/dsl/DslDumpView.vue
@@ -16,11 +16,11 @@
-->
<script setup lang="ts">
import { CATALOGS, type Catalog } from '@skywalking-horizon-ui/api-client';
-import { useAuthStore } from '@/stores/auth';
+import { useAuthStore } from '@/state/auth';
import { bff } from '@/api/client';
import Btn from '@/components/primitives/Btn.vue';
import Pill from '@/components/primitives/Pill.vue';
-import AdminFeatureWarning from '@/components/shell/AdminFeatureWarning.vue';
+import AdminFeatureWarning from '@/shell/AdminFeatureWarning.vue';
const auth = useAuthStore();
diff --git a/apps/ui/src/views/operate/dsl/DslEditorView.vue
b/apps/ui/src/features/operate/dsl/DslEditorView.vue
similarity index 97%
rename from apps/ui/src/views/operate/dsl/DslEditorView.vue
rename to apps/ui/src/features/operate/dsl/DslEditorView.vue
index 64e9157..b30d905 100644
--- a/apps/ui/src/views/operate/dsl/DslEditorView.vue
+++ b/apps/ui/src/features/operate/dsl/DslEditorView.vue
@@ -18,14 +18,14 @@
import { computed, ref, shallowRef } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { isCatalog, type Catalog, type RuleResponse } from
'@skywalking-horizon-ui/api-client';
-import { useAuthStore } from '@/stores/auth';
-import { useRuleEditor } from '@/composables/useRuleEditor';
+import { useAuthStore } from '@/state/auth';
+import { useRuleEditor } from '@/features/operate/dsl/useRuleEditor';
import Btn from '@/components/primitives/Btn.vue';
import Pill from '@/components/primitives/Pill.vue';
-import MonacoYaml from '@/components/operate/MonacoYaml.vue';
-import MonacoDiff from '@/components/operate/MonacoDiff.vue';
-import DestructiveConfirm from '@/components/operate/DestructiveConfirm.vue';
-import AdminFeatureWarning from '@/components/shell/AdminFeatureWarning.vue';
+import MonacoYaml from '@/features/operate/_shared/MonacoYaml.vue';
+import MonacoDiff from '@/features/operate/_shared/MonacoDiff.vue';
+import DestructiveConfirm from
'@/features/operate/_shared/DestructiveConfirm.vue';
+import AdminFeatureWarning from '@/shell/AdminFeatureWarning.vue';
const route = useRoute();
const router = useRouter();
diff --git a/apps/ui/src/views/operate/dsl/OalCatalogView.vue
b/apps/ui/src/features/operate/dsl/OalCatalogView.vue
similarity index 99%
rename from apps/ui/src/views/operate/dsl/OalCatalogView.vue
rename to apps/ui/src/features/operate/dsl/OalCatalogView.vue
index c4b1ba9..75d1466 100644
--- a/apps/ui/src/views/operate/dsl/OalCatalogView.vue
+++ b/apps/ui/src/features/operate/dsl/OalCatalogView.vue
@@ -34,7 +34,7 @@ import { bff } from '@/api/client';
import Pill from '@/components/primitives/Pill.vue';
import Btn from '@/components/primitives/Btn.vue';
import { tokenizeLine, type Token } from './syntaxHighlight.js';
-import AdminFeatureWarning from '@/components/shell/AdminFeatureWarning.vue';
+import AdminFeatureWarning from '@/shell/AdminFeatureWarning.vue';
const router = useRouter();
diff --git a/apps/ui/src/views/operate/dsl/syntaxHighlight.ts
b/apps/ui/src/features/operate/dsl/syntaxHighlight.ts
similarity index 100%
rename from apps/ui/src/views/operate/dsl/syntaxHighlight.ts
rename to apps/ui/src/features/operate/dsl/syntaxHighlight.ts
diff --git a/apps/ui/src/composables/useRuleEditor.ts
b/apps/ui/src/features/operate/dsl/useRuleEditor.ts
similarity index 100%
rename from apps/ui/src/composables/useRuleEditor.ts
rename to apps/ui/src/features/operate/dsl/useRuleEditor.ts
diff --git a/apps/ui/src/views/operate/InspectView.vue
b/apps/ui/src/features/operate/inspect/InspectView.vue
similarity index 99%
rename from apps/ui/src/views/operate/InspectView.vue
rename to apps/ui/src/features/operate/inspect/InspectView.vue
index 98e9139..a5be58d 100644
--- a/apps/ui/src/views/operate/InspectView.vue
+++ b/apps/ui/src/features/operate/inspect/InspectView.vue
@@ -48,7 +48,7 @@ import {
import { bff, describeApiError, type InspectCatalogEntry, type
InspectServerTimeResponse } from '@/api/client';
import Btn from '@/components/primitives/Btn.vue';
import Pill from '@/components/primitives/Pill.vue';
-import AdminFeatureWarning from '@/components/shell/AdminFeatureWarning.vue';
+import AdminFeatureWarning from '@/shell/AdminFeatureWarning.vue';
// ─── Types local to the page ────────────────────────────────────────
diff --git a/apps/ui/src/views/operate/live-debug/DebugHistoryView.vue
b/apps/ui/src/features/operate/live-debug/DebugHistoryView.vue
similarity index 99%
rename from apps/ui/src/views/operate/live-debug/DebugHistoryView.vue
rename to apps/ui/src/features/operate/live-debug/DebugHistoryView.vue
index 9adf3ca..24ed3e3 100644
--- a/apps/ui/src/views/operate/live-debug/DebugHistoryView.vue
+++ b/apps/ui/src/features/operate/live-debug/DebugHistoryView.vue
@@ -33,7 +33,7 @@ import {
useDebugHistory,
type DebugWidget,
type HistoryEntry,
-} from '@/composables/useDebugHistory';
+} from '@/features/operate/live-debug/useDebugHistory';
import Pill from '@/components/primitives/Pill.vue';
const router = useRouter();
diff --git a/apps/ui/src/views/operate/live-debug/DebugLal.vue
b/apps/ui/src/features/operate/live-debug/DebugLal.vue
similarity index 99%
rename from apps/ui/src/views/operate/live-debug/DebugLal.vue
rename to apps/ui/src/features/operate/live-debug/DebugLal.vue
index b9708d7..df274c2 100644
--- a/apps/ui/src/views/operate/live-debug/DebugLal.vue
+++ b/apps/ui/src/features/operate/live-debug/DebugLal.vue
@@ -48,8 +48,8 @@ import type {
SessionSample,
} from '@skywalking-horizon-ui/api-client';
import { bff } from '@/api/client';
-import { useDebugSession } from '@/composables/useDebugSession';
-import { useDebugHistory, type HistoryEntry } from
'@/composables/useDebugHistory';
+import { useDebugSession } from
'@/features/operate/live-debug/useDebugSession';
+import { useDebugHistory, type HistoryEntry } from
'@/features/operate/live-debug/useDebugHistory';
import Btn from '@/components/primitives/Btn.vue';
import DebugView from './DebugView.vue';
import { isLalSamplePayload } from './payload.js';
diff --git a/apps/ui/src/views/operate/live-debug/DebugMal.vue
b/apps/ui/src/features/operate/live-debug/DebugMal.vue
similarity index 99%
rename from apps/ui/src/views/operate/live-debug/DebugMal.vue
rename to apps/ui/src/features/operate/live-debug/DebugMal.vue
index 1da7571..f7bea3a 100644
--- a/apps/ui/src/views/operate/live-debug/DebugMal.vue
+++ b/apps/ui/src/features/operate/live-debug/DebugMal.vue
@@ -42,8 +42,8 @@ import type {
SessionSample,
} from '@skywalking-horizon-ui/api-client';
import { bff } from '@/api/client';
-import { useDebugSession } from '@/composables/useDebugSession';
-import { useDebugHistory, type HistoryEntry } from
'@/composables/useDebugHistory';
+import { useDebugSession } from
'@/features/operate/live-debug/useDebugSession';
+import { useDebugHistory, type HistoryEntry } from
'@/features/operate/live-debug/useDebugHistory';
import Btn from '@/components/primitives/Btn.vue';
import DebugView from './DebugView.vue';
import { isMalOutputPayload, isMalSamplesPayload, shortHash } from
'./payload.js';
diff --git a/apps/ui/src/views/operate/live-debug/DebugOal.vue
b/apps/ui/src/features/operate/live-debug/DebugOal.vue
similarity index 99%
rename from apps/ui/src/views/operate/live-debug/DebugOal.vue
rename to apps/ui/src/features/operate/live-debug/DebugOal.vue
index 16adb61..e2f7ba9 100644
--- a/apps/ui/src/views/operate/live-debug/DebugOal.vue
+++ b/apps/ui/src/features/operate/live-debug/DebugOal.vue
@@ -42,8 +42,8 @@ import type {
SessionSample,
} from '@skywalking-horizon-ui/api-client';
import { bff } from '@/api/client';
-import { useDebugSession } from '@/composables/useDebugSession';
-import { useDebugHistory, type HistoryEntry } from
'@/composables/useDebugHistory';
+import { useDebugSession } from
'@/features/operate/live-debug/useDebugSession';
+import { useDebugHistory, type HistoryEntry } from
'@/features/operate/live-debug/useDebugHistory';
import Btn from '@/components/primitives/Btn.vue';
import Pill from '@/components/primitives/Pill.vue';
import DebugView from './DebugView.vue';
diff --git a/apps/ui/src/views/operate/live-debug/DebugView.vue
b/apps/ui/src/features/operate/live-debug/DebugView.vue
similarity index 100%
rename from apps/ui/src/views/operate/live-debug/DebugView.vue
rename to apps/ui/src/features/operate/live-debug/DebugView.vue
diff --git a/apps/ui/src/views/operate/live-debug/LiveDebuggerView.vue
b/apps/ui/src/features/operate/live-debug/LiveDebuggerView.vue
similarity index 98%
rename from apps/ui/src/views/operate/live-debug/LiveDebuggerView.vue
rename to apps/ui/src/features/operate/live-debug/LiveDebuggerView.vue
index f2840cb..5ff7a72 100644
--- a/apps/ui/src/views/operate/live-debug/LiveDebuggerView.vue
+++ b/apps/ui/src/features/operate/live-debug/LiveDebuggerView.vue
@@ -31,7 +31,7 @@ import { useRoute, useRouter } from 'vue-router';
import DebugMal from './DebugMal.vue';
import DebugLal from './DebugLal.vue';
import DebugOal from './DebugOal.vue';
-import AdminFeatureWarning from '@/components/shell/AdminFeatureWarning.vue';
+import AdminFeatureWarning from '@/shell/AdminFeatureWarning.vue';
type Tab = 'mal' | 'lal' | 'oal';
diff --git a/apps/ui/src/views/operate/live-debug/NodeCoverage.vue
b/apps/ui/src/features/operate/live-debug/NodeCoverage.vue
similarity index 100%
rename from apps/ui/src/views/operate/live-debug/NodeCoverage.vue
rename to apps/ui/src/features/operate/live-debug/NodeCoverage.vue
diff --git a/apps/ui/src/views/operate/live-debug/constants.ts
b/apps/ui/src/features/operate/live-debug/constants.ts
similarity index 100%
rename from apps/ui/src/views/operate/live-debug/constants.ts
rename to apps/ui/src/features/operate/live-debug/constants.ts
diff --git a/apps/ui/src/views/operate/live-debug/oalEntityId.ts
b/apps/ui/src/features/operate/live-debug/oalEntityId.ts
similarity index 100%
rename from apps/ui/src/views/operate/live-debug/oalEntityId.ts
rename to apps/ui/src/features/operate/live-debug/oalEntityId.ts
diff --git a/apps/ui/src/views/operate/live-debug/payload.ts
b/apps/ui/src/features/operate/live-debug/payload.ts
similarity index 100%
rename from apps/ui/src/views/operate/live-debug/payload.ts
rename to apps/ui/src/features/operate/live-debug/payload.ts
diff --git a/apps/ui/src/composables/useDebugHistory.ts
b/apps/ui/src/features/operate/live-debug/useDebugHistory.ts
similarity index 100%
rename from apps/ui/src/composables/useDebugHistory.ts
rename to apps/ui/src/features/operate/live-debug/useDebugHistory.ts
diff --git a/apps/ui/src/composables/useDebugSession.ts
b/apps/ui/src/features/operate/live-debug/useDebugSession.ts
similarity index 99%
rename from apps/ui/src/composables/useDebugSession.ts
rename to apps/ui/src/features/operate/live-debug/useDebugSession.ts
index 3e3c888..de5da5e 100644
--- a/apps/ui/src/composables/useDebugSession.ts
+++ b/apps/ui/src/features/operate/live-debug/useDebugSession.ts
@@ -44,7 +44,7 @@ import type {
StartSessionArgs,
} from '@skywalking-horizon-ui/api-client';
import { bff, describeApiError } from '@/api/client';
-import { getClientId } from './useClientId.js';
+import { getClientId } from '../../../controls/clientId.js';
export type DebugWidgetKey = 'mal' | 'lal' | 'oal';
diff --git a/apps/ui/src/views/setup/LayerSetupCard.vue
b/apps/ui/src/features/setup/LayerSetupCard.vue
similarity index 99%
rename from apps/ui/src/views/setup/LayerSetupCard.vue
rename to apps/ui/src/features/setup/LayerSetupCard.vue
index 09e3026..0c0706a 100644
--- a/apps/ui/src/views/setup/LayerSetupCard.vue
+++ b/apps/ui/src/features/setup/LayerSetupCard.vue
@@ -18,7 +18,7 @@
import { computed, ref } from 'vue';
import type { LayerDef } from '@skywalking-horizon-ui/api-client';
import Icon from '@/components/icons/Icon.vue';
-import { useSetupStore, defaultLandingFor } from '@/stores/setup';
+import { useSetupStore, defaultLandingFor } from '@/state/setup';
const props = defineProps<{ layer: LayerDef; expanded?: boolean }>();
const emit = defineEmits<{ (e: 'toggle'): void }>();
diff --git a/apps/ui/src/views/setup/SetupView.vue
b/apps/ui/src/features/setup/SetupView.vue
similarity index 99%
rename from apps/ui/src/views/setup/SetupView.vue
rename to apps/ui/src/features/setup/SetupView.vue
index d23f088..1495fe5 100644
--- a/apps/ui/src/views/setup/SetupView.vue
+++ b/apps/ui/src/features/setup/SetupView.vue
@@ -32,7 +32,7 @@ import { computed, ref, watch } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import type { OverviewDashboard, OverviewWidget } from
'@skywalking-horizon-ui/api-client';
import { bffClient } from '@/api/client';
-import { useOverviewDashboards } from '@/composables/useOverviewDashboards';
+import { useOverviewDashboards } from
'@/render/overview/useOverviewDashboards';
const { isLoading, all, publicOverviews, operateOverviews } =
useOverviewDashboards();
diff --git a/apps/ui/src/views/layer/LayerServiceSelector.vue
b/apps/ui/src/layer/LayerServiceSelector.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerServiceSelector.vue
rename to apps/ui/src/layer/LayerServiceSelector.vue
index 9f5d2dc..17de248 100644
--- a/apps/ui/src/views/layer/LayerServiceSelector.vue
+++ b/apps/ui/src/layer/LayerServiceSelector.vue
@@ -25,8 +25,8 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import type { LandingColumn, LandingServiceRow } from
'@skywalking-horizon-ui/api-client';
-import { metricMeta } from '@/composables/metricCatalog';
-import { statusForMetrics, thresholdColor } from '@/composables/metricColor';
+import { metricMeta } from '@/utils/metricCatalog';
+import { statusForMetrics, thresholdColor } from '@/utils/metricColor';
import { fmtMetric } from '@/utils/formatters';
import { resolveServiceIdentity } from '@/utils/serviceName';
import type { ServiceNamingRule } from '@skywalking-horizon-ui/api-client';
diff --git a/apps/ui/src/views/layer/LayerShell.vue
b/apps/ui/src/layer/LayerShell.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerShell.vue
rename to apps/ui/src/layer/LayerShell.vue
index ee2c84f..f568b00 100644
--- a/apps/ui/src/views/layer/LayerShell.vue
+++ b/apps/ui/src/layer/LayerShell.vue
@@ -32,12 +32,12 @@ import type { LayerDef } from
'@skywalking-horizon-ui/api-client';
import Icon from '@/components/icons/Icon.vue';
import Sparkline from '@/components/charts/Sparkline.vue';
import LayerServiceSelector from './LayerServiceSelector.vue';
-import { metricMeta } from '@/composables/metricCatalog';
-import { colorForMetric } from '@/composables/metricColor';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useLayers, firstLayerTab } from '@/composables/useLayers';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useSetupStore } from '@/stores/setup';
+import { metricMeta } from '@/utils/metricCatalog';
+import { colorForMetric } from '@/utils/metricColor';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useLayers, firstLayerTab } from '@/shell/useLayers';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useSetupStore } from '@/state/setup';
import { fmtMetric } from '@/utils/formatters';
import { parseServiceName } from '@/utils/serviceName';
diff --git a/apps/ui/src/views/layer/LayerTabPlaceholder.vue
b/apps/ui/src/layer/LayerTabPlaceholder.vue
similarity index 97%
rename from apps/ui/src/views/layer/LayerTabPlaceholder.vue
rename to apps/ui/src/layer/LayerTabPlaceholder.vue
index d9f0bed..dbbf887 100644
--- a/apps/ui/src/views/layer/LayerTabPlaceholder.vue
+++ b/apps/ui/src/layer/LayerTabPlaceholder.vue
@@ -23,7 +23,7 @@
-->
<script setup lang="ts">
import { computed } from 'vue';
-import { useSelectedService } from '@/composables/useSelectedService';
+import { useSelectedService } from '@/layer/useSelectedService';
defineProps<{ title: string; phase: string; note?: string }>();
diff --git a/apps/ui/src/views/layer/LayerEndpointDependencyView.vue
b/apps/ui/src/layer/endpoint-dependency/LayerEndpointDependencyView.vue
similarity index 99%
rename from apps/ui/src/views/layer/LayerEndpointDependencyView.vue
rename to apps/ui/src/layer/endpoint-dependency/LayerEndpointDependencyView.vue
index f225ca7..90a72d6 100644
--- a/apps/ui/src/views/layer/LayerEndpointDependencyView.vue
+++ b/apps/ui/src/layer/endpoint-dependency/LayerEndpointDependencyView.vue
@@ -41,13 +41,13 @@ import type {
TopologyMetricDef,
} from '@/api/client';
import { bffClient } from '@/api/client';
-import { useLayerEndpointDependency } from
'@/composables/useLayerEndpointDependency';
-import { useLayerEndpoints } from '@/composables/useLayerEndpoints';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useLayers } from '@/composables/useLayers';
-import { useSelectedEndpoint } from '@/composables/useSelectedEndpoint';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useSetupStore } from '@/stores/setup';
+import { useLayerEndpointDependency } from
'@/layer/endpoint-dependency/useLayerEndpointDependency';
+import { useLayerEndpoints } from '@/layer/useLayerEndpoints';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useLayers } from '@/shell/useLayers';
+import { useSelectedEndpoint } from '@/layer/useSelectedEndpoint';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useSetupStore } from '@/state/setup';
import { fmtMetric } from '@/utils/formatters';
import { resolveServiceIdentity, type ServiceIdentity } from
'@/utils/serviceName';
import { watch } from 'vue';
diff --git a/apps/ui/src/composables/useLayerEndpointDependency.ts
b/apps/ui/src/layer/endpoint-dependency/useLayerEndpointDependency.ts
similarity index 95%
rename from apps/ui/src/composables/useLayerEndpointDependency.ts
rename to apps/ui/src/layer/endpoint-dependency/useLayerEndpointDependency.ts
index 47bfcfd..0116444 100644
--- a/apps/ui/src/composables/useLayerEndpointDependency.ts
+++ b/apps/ui/src/layer/endpoint-dependency/useLayerEndpointDependency.ts
@@ -23,7 +23,7 @@
import { computed, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from
'../../controls/useAutoRefreshSubscribe';
import { bffClient } from '@/api/client';
export function useLayerEndpointDependency(
diff --git a/apps/ui/src/views/layer/LayerLogsView.vue
b/apps/ui/src/layer/logs/LayerLogsView.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerLogsView.vue
rename to apps/ui/src/layer/logs/LayerLogsView.vue
index 3fe9b8d..7b18f66 100644
--- a/apps/ui/src/views/layer/LayerLogsView.vue
+++ b/apps/ui/src/layer/logs/LayerLogsView.vue
@@ -28,17 +28,17 @@
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { LayerDef, LogRow, LogTagFilter } from '@/api/client';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useLayerLogs, useLayerLogFacets } from '@/composables/useLayerLogs';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useLayerLogs, useLayerLogFacets } from '@/layer/logs/useLayerLogs';
import { bffClient } from '@/api/client';
-import { useLayerInstances } from '@/composables/useLayerInstances';
-import { useLayerEndpoints } from '@/composables/useLayerEndpoints';
-import { useLayers } from '@/composables/useLayers';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useSelectedInstance } from '@/composables/useSelectedInstance';
-import { useSelectedEndpoint } from '@/composables/useSelectedEndpoint';
-import { useSetupStore } from '@/stores/setup';
-import { useTracePopout } from '@/composables/useTracePopout';
+import { useLayerInstances } from '@/layer/useLayerInstances';
+import { useLayerEndpoints } from '@/layer/useLayerEndpoints';
+import { useLayers } from '@/shell/useLayers';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useSelectedInstance } from '@/layer/useSelectedInstance';
+import { useSelectedEndpoint } from '@/layer/useSelectedEndpoint';
+import { useSetupStore } from '@/state/setup';
+import { useTracePopout } from '@/layer/traces/useTracePopout';
import { parseServiceName } from '@/utils/serviceName';
const route = useRoute();
diff --git a/apps/ui/src/composables/useLayerLogs.ts
b/apps/ui/src/layer/logs/useLayerLogs.ts
similarity index 98%
rename from apps/ui/src/composables/useLayerLogs.ts
rename to apps/ui/src/layer/logs/useLayerLogs.ts
index 7358adf..4c03312 100644
--- a/apps/ui/src/composables/useLayerLogs.ts
+++ b/apps/ui/src/layer/logs/useLayerLogs.ts
@@ -17,7 +17,7 @@
import { computed, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from
'../../controls/useAutoRefreshSubscribe';
import { bffClient } from '@/api/client';
import type { LogFacetsResponse, LogsResponse, LogTagFilter } from
'@/api/client';
diff --git a/apps/ui/src/views/layer/LayerAsyncProfilingView.vue
b/apps/ui/src/layer/profiling/LayerAsyncProfilingView.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerAsyncProfilingView.vue
rename to apps/ui/src/layer/profiling/LayerAsyncProfilingView.vue
index 83890f6..a3b6193 100644
--- a/apps/ui/src/views/layer/LayerAsyncProfilingView.vue
+++ b/apps/ui/src/layer/profiling/LayerAsyncProfilingView.vue
@@ -26,8 +26,8 @@
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
-import { useLayerInstances } from '@/composables/useLayerInstances';
-import { useSelectedService } from '@/composables/useSelectedService';
+import { useLayerInstances } from '@/layer/useLayerInstances';
+import { useSelectedService } from '@/layer/useSelectedService';
import { bffClient } from '@/api/client';
import type {
AsyncProfilingEvent,
@@ -35,7 +35,7 @@ import type {
AsyncProfilingTree,
ProfileAnalyzationTree,
} from '@/api/client';
-import ProfileFlameGraph from '@/components/profile/ProfileFlameGraph.vue';
+import ProfileFlameGraph from '@/layer/profiling/ProfileFlameGraph.vue';
const route = useRoute();
const layerKey = computed(() => String(route.params.layerKey ?? ''));
diff --git a/apps/ui/src/views/layer/LayerEBPFProfilingView.vue
b/apps/ui/src/layer/profiling/LayerEBPFProfilingView.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerEBPFProfilingView.vue
rename to apps/ui/src/layer/profiling/LayerEBPFProfilingView.vue
index c681a61..5e0bf0c 100644
--- a/apps/ui/src/views/layer/LayerEBPFProfilingView.vue
+++ b/apps/ui/src/layer/profiling/LayerEBPFProfilingView.vue
@@ -30,10 +30,10 @@
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
-import { useLayers } from '@/composables/useLayers';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useSetupStore } from '@/stores/setup';
+import { useLayers } from '@/shell/useLayers';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useSetupStore } from '@/state/setup';
import { bffClient } from '@/api/client';
import type {
EBPFAnalysisTree,
@@ -44,8 +44,8 @@ import type {
LayerDef,
ProfileAnalyzationTree,
} from '@/api/client';
-import ProfileFlameGraph from '@/components/profile/ProfileFlameGraph.vue';
-import ProfileStackTable from '@/components/profile/ProfileStackTable.vue';
+import ProfileFlameGraph from '@/layer/profiling/ProfileFlameGraph.vue';
+import ProfileStackTable from '@/layer/profiling/ProfileStackTable.vue';
const route = useRoute();
const layerKey = computed(() => String(route.params.layerKey ?? ''));
diff --git a/apps/ui/src/views/layer/LayerNetworkProfilingView.vue
b/apps/ui/src/layer/profiling/LayerNetworkProfilingView.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerNetworkProfilingView.vue
rename to apps/ui/src/layer/profiling/LayerNetworkProfilingView.vue
index 476e984..32f46c6 100644
--- a/apps/ui/src/views/layer/LayerNetworkProfilingView.vue
+++ b/apps/ui/src/layer/profiling/LayerNetworkProfilingView.vue
@@ -33,8 +33,8 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
-import { useLayerInstances } from '@/composables/useLayerInstances';
-import { useSelectedService } from '@/composables/useSelectedService';
+import { useLayerInstances } from '@/layer/useLayerInstances';
+import { useSelectedService } from '@/layer/useSelectedService';
import { bffClient } from '@/api/client';
import type {
EBPFTask,
@@ -42,7 +42,7 @@ import type {
ProcessCall,
ProcessNode,
} from '@/api/client';
-import ProcessTopologyGraph from
'@/components/profile/ProcessTopologyGraph.vue';
+import ProcessTopologyGraph from '@/layer/profiling/ProcessTopologyGraph.vue';
const route = useRoute();
const layerKey = computed(() => String(route.params.layerKey ?? ''));
diff --git a/apps/ui/src/views/layer/LayerPprofProfilingView.vue
b/apps/ui/src/layer/profiling/LayerPprofProfilingView.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerPprofProfilingView.vue
rename to apps/ui/src/layer/profiling/LayerPprofProfilingView.vue
index 7dbc754..5018848 100644
--- a/apps/ui/src/views/layer/LayerPprofProfilingView.vue
+++ b/apps/ui/src/layer/profiling/LayerPprofProfilingView.vue
@@ -26,11 +26,11 @@
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
-import { useLayerInstances } from '@/composables/useLayerInstances';
-import { useSelectedService } from '@/composables/useSelectedService';
+import { useLayerInstances } from '@/layer/useLayerInstances';
+import { useSelectedService } from '@/layer/useSelectedService';
import { bffClient } from '@/api/client';
import type { PprofTask, PprofTree, ProfileAnalyzationTree } from
'@/api/client';
-import ProfileFlameGraph from '@/components/profile/ProfileFlameGraph.vue';
+import ProfileFlameGraph from '@/layer/profiling/ProfileFlameGraph.vue';
const route = useRoute();
const layerKey = computed(() => String(route.params.layerKey ?? ''));
diff --git a/apps/ui/src/views/layer/LayerTraceProfilingView.vue
b/apps/ui/src/layer/profiling/LayerTraceProfilingView.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerTraceProfilingView.vue
rename to apps/ui/src/layer/profiling/LayerTraceProfilingView.vue
index 821fa00..e67f041 100644
--- a/apps/ui/src/views/layer/LayerTraceProfilingView.vue
+++ b/apps/ui/src/layer/profiling/LayerTraceProfilingView.vue
@@ -36,11 +36,11 @@
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
-import { useLayers } from '@/composables/useLayers';
-import { useLayerEndpoints } from '@/composables/useLayerEndpoints';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useSetupStore } from '@/stores/setup';
+import { useLayers } from '@/shell/useLayers';
+import { useLayerEndpoints } from '@/layer/useLayerEndpoints';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useSetupStore } from '@/state/setup';
import { bffClient } from '@/api/client';
import type {
LayerDef,
@@ -52,9 +52,9 @@ import type {
ProfileTaskLog,
ProfileTimeRange,
} from '@/api/client';
-import ProfileStackTable from '@/components/profile/ProfileStackTable.vue';
-import ProfileFlameGraph from '@/components/profile/ProfileFlameGraph.vue';
-import NativeTraceWaterfall from '@/components/trace/NativeTraceWaterfall.vue';
+import ProfileStackTable from '@/layer/profiling/ProfileStackTable.vue';
+import ProfileFlameGraph from '@/layer/profiling/ProfileFlameGraph.vue';
+import NativeTraceWaterfall from '@/layer/traces/NativeTraceWaterfall.vue';
const route = useRoute();
const layerKey = computed(() => String(route.params.layerKey ?? ''));
diff --git a/apps/ui/src/components/profile/ProcessTopologyGraph.vue
b/apps/ui/src/layer/profiling/ProcessTopologyGraph.vue
similarity index 100%
rename from apps/ui/src/components/profile/ProcessTopologyGraph.vue
rename to apps/ui/src/layer/profiling/ProcessTopologyGraph.vue
diff --git a/apps/ui/src/components/profile/ProfileFlameGraph.vue
b/apps/ui/src/layer/profiling/ProfileFlameGraph.vue
similarity index 100%
rename from apps/ui/src/components/profile/ProfileFlameGraph.vue
rename to apps/ui/src/layer/profiling/ProfileFlameGraph.vue
diff --git a/apps/ui/src/components/profile/ProfileStackRow.vue
b/apps/ui/src/layer/profiling/ProfileStackRow.vue
similarity index 100%
rename from apps/ui/src/components/profile/ProfileStackRow.vue
rename to apps/ui/src/layer/profiling/ProfileStackRow.vue
diff --git a/apps/ui/src/components/profile/ProfileStackTable.vue
b/apps/ui/src/layer/profiling/ProfileStackTable.vue
similarity index 100%
rename from apps/ui/src/components/profile/ProfileStackTable.vue
rename to apps/ui/src/layer/profiling/ProfileStackTable.vue
diff --git a/apps/ui/src/views/layer/LayerServiceMapView.vue
b/apps/ui/src/layer/service-map/LayerServiceMapView.vue
similarity index 99%
rename from apps/ui/src/views/layer/LayerServiceMapView.vue
rename to apps/ui/src/layer/service-map/LayerServiceMapView.vue
index 8929fa4..a6123a5 100644
--- a/apps/ui/src/views/layer/LayerServiceMapView.vue
+++ b/apps/ui/src/layer/service-map/LayerServiceMapView.vue
@@ -60,17 +60,17 @@ import type {
TopologyMetricDef,
TopologyNode,
} from '@/api/client';
-import { useLayerTopology } from '@/composables/useLayerTopology';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useLayers } from '@/composables/useLayers';
-import { useSetupStore } from '@/stores/setup';
+import { useLayerTopology } from '@/layer/service-map/useLayerTopology';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useLayers } from '@/shell/useLayers';
+import { useSetupStore } from '@/state/setup';
import { fmtMetric } from '@/utils/formatters';
import {
resolveServiceIdentity,
type ServiceIdentity,
} from '@/utils/serviceName';
import Sparkline from '@/components/charts/Sparkline.vue';
-import { isUserNode } from '@/composables/useTopologyIcons';
+import { isUserNode } from '@/layer/service-map/useTopologyIcons';
/** When embedded as a widget (e.g. inside the Services / Mesh overview
* dashboards) the host passes the layer key directly and asks for the
diff --git a/apps/ui/src/composables/useLayerTopology.ts
b/apps/ui/src/layer/service-map/useLayerTopology.ts
similarity index 95%
rename from apps/ui/src/composables/useLayerTopology.ts
rename to apps/ui/src/layer/service-map/useLayerTopology.ts
index 0add8ad..a9d1944 100644
--- a/apps/ui/src/composables/useLayerTopology.ts
+++ b/apps/ui/src/layer/service-map/useLayerTopology.ts
@@ -23,7 +23,7 @@
import { computed, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from
'../../controls/useAutoRefreshSubscribe';
import { bffClient } from '@/api/client';
export function useLayerTopology(
diff --git a/apps/ui/src/composables/useTopologyIcons.ts
b/apps/ui/src/layer/service-map/useTopologyIcons.ts
similarity index 100%
rename from apps/ui/src/composables/useTopologyIcons.ts
rename to apps/ui/src/layer/service-map/useTopologyIcons.ts
diff --git a/apps/ui/src/views/layer/LayerTracesEntry.vue
b/apps/ui/src/layer/traces/LayerTracesEntry.vue
similarity index 98%
rename from apps/ui/src/views/layer/LayerTracesEntry.vue
rename to apps/ui/src/layer/traces/LayerTracesEntry.vue
index 98ba7a8..e5dcca6 100644
--- a/apps/ui/src/views/layer/LayerTracesEntry.vue
+++ b/apps/ui/src/layer/traces/LayerTracesEntry.vue
@@ -30,7 +30,7 @@
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { LayerDef } from '@skywalking-horizon-ui/api-client';
-import { useLayers } from '@/composables/useLayers';
+import { useLayers } from '@/shell/useLayers';
import LayerTracesView from './LayerTracesView.vue';
import LayerZipkinTracesView from './LayerZipkinTracesView.vue';
diff --git a/apps/ui/src/views/layer/LayerTracesView.vue
b/apps/ui/src/layer/traces/LayerTracesView.vue
similarity index 99%
rename from apps/ui/src/views/layer/LayerTracesView.vue
rename to apps/ui/src/layer/traces/LayerTracesView.vue
index 48f96c8..d3ee54a 100644
--- a/apps/ui/src/views/layer/LayerTracesView.vue
+++ b/apps/ui/src/layer/traces/LayerTracesView.vue
@@ -44,15 +44,15 @@ import type {
TraceQueryOrder,
TraceQueryState,
} from '@/api/client';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useLayers } from '@/composables/useLayers';
-import { useLayerTraces, useTraceDetail } from '@/composables/useLayerTraces';
-import { useLayerInstances } from '@/composables/useLayerInstances';
-import { useLayerEndpoints } from '@/composables/useLayerEndpoints';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useSetupStore } from '@/stores/setup';
-import { useTracePopout } from '@/composables/useTracePopout';
-import { componentIconOrNull } from '@/composables/useTopologyIcons';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useLayers } from '@/shell/useLayers';
+import { useLayerTraces, useTraceDetail } from '@/layer/traces/useLayerTraces';
+import { useLayerInstances } from '@/layer/useLayerInstances';
+import { useLayerEndpoints } from '@/layer/useLayerEndpoints';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useSetupStore } from '@/state/setup';
+import { useTracePopout } from '@/layer/traces/useTracePopout';
+import { componentIconOrNull } from '@/layer/service-map/useTopologyIcons';
import { fmtMetric } from '@/utils/formatters';
import { bffClient } from '@/api/client';
import * as d3 from 'd3';
diff --git a/apps/ui/src/views/layer/LayerZipkinTracesView.vue
b/apps/ui/src/layer/traces/LayerZipkinTracesView.vue
similarity index 99%
rename from apps/ui/src/views/layer/LayerZipkinTracesView.vue
rename to apps/ui/src/layer/traces/LayerZipkinTracesView.vue
index 1227e20..36fa459 100644
--- a/apps/ui/src/views/layer/LayerZipkinTracesView.vue
+++ b/apps/ui/src/layer/traces/LayerZipkinTracesView.vue
@@ -25,8 +25,8 @@
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { ZipkinTraceListRow } from '@skywalking-horizon-ui/api-client';
-import { useLayerZipkinTraces, useZipkinTrace } from
'@/composables/useZipkinTraces';
-import { useZipkinTracePopout } from '@/composables/useZipkinTracePopout';
+import { useLayerZipkinTraces, useZipkinTrace } from
'@/layer/traces/useZipkinTraces';
+import { useZipkinTracePopout } from '@/layer/traces/useZipkinTracePopout';
import { bffClient } from '@/api/client';
// Zipkin trace data is keyed by its own service universe (the names
diff --git a/apps/ui/src/components/trace/NativeTraceWaterfall.vue
b/apps/ui/src/layer/traces/NativeTraceWaterfall.vue
similarity index 99%
rename from apps/ui/src/components/trace/NativeTraceWaterfall.vue
rename to apps/ui/src/layer/traces/NativeTraceWaterfall.vue
index c49d41b..ecfbebd 100644
--- a/apps/ui/src/components/trace/NativeTraceWaterfall.vue
+++ b/apps/ui/src/layer/traces/NativeTraceWaterfall.vue
@@ -32,7 +32,7 @@
-->
<script setup lang="ts">
import { computed } from 'vue';
-import { componentIconOrNull } from '@/composables/useTopologyIcons';
+import { componentIconOrNull } from '@/layer/service-map/useTopologyIcons';
import { fmtMetric } from '@/utils/formatters';
/** Structural type covering both NativeSpan (from /trace) and
diff --git a/apps/ui/src/components/trace/TracePopout.vue
b/apps/ui/src/layer/traces/TracePopout.vue
similarity index 99%
rename from apps/ui/src/components/trace/TracePopout.vue
rename to apps/ui/src/layer/traces/TracePopout.vue
index 40fb6c4..ae6c4c3 100644
--- a/apps/ui/src/components/trace/TracePopout.vue
+++ b/apps/ui/src/layer/traces/TracePopout.vue
@@ -31,9 +31,9 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import type { NativeSpan, TraceAttachedEvent, TraceLogEntry } from
'@/api/client';
-import { useTraceDetail } from '@/composables/useLayerTraces';
-import { useTracePopout } from '@/composables/useTracePopout';
-import { componentIconOrNull } from '@/composables/useTopologyIcons';
+import { useTraceDetail } from '@/layer/traces/useLayerTraces';
+import { useTracePopout } from '@/layer/traces/useTracePopout';
+import { componentIconOrNull } from '@/layer/service-map/useTopologyIcons';
import { fmtMetric } from '@/utils/formatters';
const { openTraceId, openTrace, closeTrace } = useTracePopout();
diff --git a/apps/ui/src/components/trace/ZipkinTracePopout.vue
b/apps/ui/src/layer/traces/ZipkinTracePopout.vue
similarity index 99%
rename from apps/ui/src/components/trace/ZipkinTracePopout.vue
rename to apps/ui/src/layer/traces/ZipkinTracePopout.vue
index a6bba11..e601bf9 100644
--- a/apps/ui/src/components/trace/ZipkinTracePopout.vue
+++ b/apps/ui/src/layer/traces/ZipkinTracePopout.vue
@@ -31,8 +31,8 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import type { ZipkinSpan } from '@skywalking-horizon-ui/api-client';
-import { useZipkinTracePopout } from '@/composables/useZipkinTracePopout';
-import { useZipkinTrace } from '@/composables/useZipkinTraces';
+import { useZipkinTracePopout } from '@/layer/traces/useZipkinTracePopout';
+import { useZipkinTrace } from '@/layer/traces/useZipkinTraces';
const { openTraceId, closeTrace } = useZipkinTracePopout();
const traceIdRef = computed(() => openTraceId.value);
diff --git a/apps/ui/src/composables/useLayerTraces.ts
b/apps/ui/src/layer/traces/useLayerTraces.ts
similarity index 100%
rename from apps/ui/src/composables/useLayerTraces.ts
rename to apps/ui/src/layer/traces/useLayerTraces.ts
diff --git a/apps/ui/src/composables/useTracePopout.ts
b/apps/ui/src/layer/traces/useTracePopout.ts
similarity index 100%
rename from apps/ui/src/composables/useTracePopout.ts
rename to apps/ui/src/layer/traces/useTracePopout.ts
diff --git a/apps/ui/src/composables/useZipkinTracePopout.ts
b/apps/ui/src/layer/traces/useZipkinTracePopout.ts
similarity index 100%
rename from apps/ui/src/composables/useZipkinTracePopout.ts
rename to apps/ui/src/layer/traces/useZipkinTracePopout.ts
diff --git a/apps/ui/src/composables/useZipkinTraces.ts
b/apps/ui/src/layer/traces/useZipkinTraces.ts
similarity index 100%
rename from apps/ui/src/composables/useZipkinTraces.ts
rename to apps/ui/src/layer/traces/useZipkinTraces.ts
diff --git a/apps/ui/src/composables/useLayerEndpoints.ts
b/apps/ui/src/layer/useLayerEndpoints.ts
similarity index 100%
rename from apps/ui/src/composables/useLayerEndpoints.ts
rename to apps/ui/src/layer/useLayerEndpoints.ts
diff --git a/apps/ui/src/composables/useLayerInstances.ts
b/apps/ui/src/layer/useLayerInstances.ts
similarity index 100%
rename from apps/ui/src/composables/useLayerInstances.ts
rename to apps/ui/src/layer/useLayerInstances.ts
diff --git a/apps/ui/src/composables/useLayerLanding.ts
b/apps/ui/src/layer/useLayerLanding.ts
similarity index 97%
rename from apps/ui/src/composables/useLayerLanding.ts
rename to apps/ui/src/layer/useLayerLanding.ts
index 054f6da..b22b199 100644
--- a/apps/ui/src/composables/useLayerLanding.ts
+++ b/apps/ui/src/layer/useLayerLanding.ts
@@ -17,7 +17,7 @@
import { computed, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from '../controls/useAutoRefreshSubscribe';
import type { LandingConfig, LandingResponse, LayerDef } from
'@skywalking-horizon-ui/api-client';
import { bffClient } from '@/api/client';
diff --git a/apps/ui/src/composables/useSelectedEndpoint.ts
b/apps/ui/src/layer/useSelectedEndpoint.ts
similarity index 100%
rename from apps/ui/src/composables/useSelectedEndpoint.ts
rename to apps/ui/src/layer/useSelectedEndpoint.ts
diff --git a/apps/ui/src/composables/useSelectedInstance.ts
b/apps/ui/src/layer/useSelectedInstance.ts
similarity index 100%
rename from apps/ui/src/composables/useSelectedInstance.ts
rename to apps/ui/src/layer/useSelectedInstance.ts
diff --git a/apps/ui/src/composables/useSelectedService.ts
b/apps/ui/src/layer/useSelectedService.ts
similarity index 100%
rename from apps/ui/src/composables/useSelectedService.ts
rename to apps/ui/src/layer/useSelectedService.ts
diff --git a/apps/ui/src/main.ts b/apps/ui/src/main.ts
index 0025101..d999315 100644
--- a/apps/ui/src/main.ts
+++ b/apps/ui/src/main.ts
@@ -19,9 +19,9 @@ import { createPinia } from 'pinia';
import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query';
import App from './App.vue';
-import router from './router';
+import router from './shell/router/index';
import { bffClient } from './api/client';
-import { useAuthStore } from './stores/auth';
+import { useAuthStore } from './state/auth';
import '@skywalking-horizon-ui/design-tokens/tokens.css';
import './assets/styles/global.css';
diff --git a/apps/ui/src/views/layer/LayerDashboardsView.vue
b/apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
similarity index 97%
rename from apps/ui/src/views/layer/LayerDashboardsView.vue
rename to apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
index 2d54ca9..800ab83 100644
--- a/apps/ui/src/views/layer/LayerDashboardsView.vue
+++ b/apps/ui/src/render/layer-dashboard/LayerDashboardsView.vue
@@ -31,16 +31,16 @@ import { useRoute } from 'vue-router';
import type { LayerDef } from '@skywalking-horizon-ui/api-client';
import TimeChart from '@/components/charts/TimeChart.vue';
import TopList from '@/components/charts/TopList.vue';
-import { colorForMetric } from '@/composables/metricColor';
-import { useLayerDashboard, useLayerDashboardConfig } from
'@/composables/useLayerDashboard';
-import { useLayerEndpoints } from '@/composables/useLayerEndpoints';
-import { useLayerInstances } from '@/composables/useLayerInstances';
-import { useLayerLanding } from '@/composables/useLayerLanding';
-import { useLayers } from '@/composables/useLayers';
-import { useSelectedEndpoint } from '@/composables/useSelectedEndpoint';
-import { useSelectedInstance } from '@/composables/useSelectedInstance';
-import { useSelectedService } from '@/composables/useSelectedService';
-import { useSetupStore } from '@/stores/setup';
+import { colorForMetric } from '@/utils/metricColor';
+import { useLayerDashboard, useLayerDashboardConfig } from
'@/render/layer-dashboard/useLayerDashboard';
+import { useLayerEndpoints } from '@/layer/useLayerEndpoints';
+import { useLayerInstances } from '@/layer/useLayerInstances';
+import { useLayerLanding } from '@/layer/useLayerLanding';
+import { useLayers } from '@/shell/useLayers';
+import { useSelectedEndpoint } from '@/layer/useSelectedEndpoint';
+import { useSelectedInstance } from '@/layer/useSelectedInstance';
+import { useSelectedService } from '@/layer/useSelectedService';
+import { useSetupStore } from '@/state/setup';
import { fmtMetricAs } from '@/utils/formatters';
import { ref, watch, watchEffect } from 'vue';
diff --git a/apps/ui/src/composables/useLayerDashboard.ts
b/apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
similarity index 98%
rename from apps/ui/src/composables/useLayerDashboard.ts
rename to apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
index 7c17a55..0c6f449 100644
--- a/apps/ui/src/composables/useLayerDashboard.ts
+++ b/apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
@@ -29,7 +29,7 @@
import { computed, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from
'../../controls/useAutoRefreshSubscribe';
import { bffClient } from '@/api/client';
export function useLayerDashboardConfig(layerKey: Ref<string>, scope?:
Ref<string>) {
diff --git a/apps/ui/src/views/overview/OverviewDashboardView.vue
b/apps/ui/src/render/overview/OverviewDashboardView.vue
similarity index 90%
rename from apps/ui/src/views/overview/OverviewDashboardView.vue
rename to apps/ui/src/render/overview/OverviewDashboardView.vue
index 7d2512b..7e4cc47 100644
--- a/apps/ui/src/views/overview/OverviewDashboardView.vue
+++ b/apps/ui/src/render/overview/OverviewDashboardView.vue
@@ -29,15 +29,15 @@
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import type { OverviewWidget } from '@skywalking-horizon-ui/api-client';
-import { useOverviewDashboard } from '@/composables/useOverviewDashboard';
-import SectionBreak from '@/components/overview/widgets/SectionBreak.vue';
-import ServiceCountWidget from
'@/components/overview/widgets/ServiceCountWidget.vue';
-import MetricWidget from '@/components/overview/widgets/MetricWidget.vue';
-import KpiTileWidget from '@/components/overview/widgets/KpiTileWidget.vue';
-import AlarmsWidget from '@/components/overview/widgets/AlarmsWidget.vue';
-import K8sSummaryWidget from
'@/components/overview/widgets/K8sSummaryWidget.vue';
-import PilotSummaryWidget from
'@/components/overview/widgets/PilotSummaryWidget.vue';
-import LayerServiceMapView from '@/views/layer/LayerServiceMapView.vue';
+import { useOverviewDashboard } from '@/render/overview/useOverviewDashboard';
+import SectionBreak from '@/render/widgets/SectionBreak.vue';
+import ServiceCountWidget from '@/render/widgets/ServiceCountWidget.vue';
+import MetricWidget from '@/render/widgets/MetricWidget.vue';
+import KpiTileWidget from '@/render/widgets/KpiTileWidget.vue';
+import AlarmsWidget from '@/render/widgets/AlarmsWidget.vue';
+import K8sSummaryWidget from '@/render/widgets/K8sSummaryWidget.vue';
+import PilotSummaryWidget from '@/render/widgets/PilotSummaryWidget.vue';
+import LayerServiceMapView from '@/layer/service-map/LayerServiceMapView.vue';
const route = useRoute();
const dashId = computed(() => String(route.params.id ?? ''));
diff --git a/apps/ui/src/views/overview/OverviewLanding.vue
b/apps/ui/src/render/overview/OverviewLanding.vue
similarity index 96%
rename from apps/ui/src/views/overview/OverviewLanding.vue
rename to apps/ui/src/render/overview/OverviewLanding.vue
index 3e679a6..7ddbb78 100644
--- a/apps/ui/src/views/overview/OverviewLanding.vue
+++ b/apps/ui/src/render/overview/OverviewLanding.vue
@@ -23,8 +23,8 @@
<script setup lang="ts">
import { watchEffect } from 'vue';
import { RouterLink, useRouter } from 'vue-router';
-import { useOverviewDashboards } from '@/composables/useOverviewDashboards';
-import { useLayers } from '@/composables/useLayers';
+import { useOverviewDashboards } from
'@/render/overview/useOverviewDashboards';
+import { useLayers } from '@/shell/useLayers';
const router = useRouter();
const { publicOverviews, isLoading } = useOverviewDashboards();
diff --git a/apps/ui/src/composables/useOverviewDashboard.ts
b/apps/ui/src/render/overview/useOverviewDashboard.ts
similarity index 100%
rename from apps/ui/src/composables/useOverviewDashboard.ts
rename to apps/ui/src/render/overview/useOverviewDashboard.ts
diff --git a/apps/ui/src/composables/useOverviewDashboards.ts
b/apps/ui/src/render/overview/useOverviewDashboards.ts
similarity index 97%
rename from apps/ui/src/composables/useOverviewDashboards.ts
rename to apps/ui/src/render/overview/useOverviewDashboards.ts
index 4fc87fc..e0fe988 100644
--- a/apps/ui/src/composables/useOverviewDashboards.ts
+++ b/apps/ui/src/render/overview/useOverviewDashboards.ts
@@ -18,7 +18,7 @@
import { computed } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import { bffClient } from '@/api/client';
-import { useLayers } from './useLayers';
+import { useLayers } from '../../shell/useLayers';
/**
* Overview-dashboard list driver. Fetches the BFF's bundled list, then
diff --git a/apps/ui/src/components/overview/widgets/AlarmsWidget.vue
b/apps/ui/src/render/widgets/AlarmsWidget.vue
similarity index 100%
rename from apps/ui/src/components/overview/widgets/AlarmsWidget.vue
rename to apps/ui/src/render/widgets/AlarmsWidget.vue
diff --git a/apps/ui/src/components/overview/widgets/K8sSummaryWidget.vue
b/apps/ui/src/render/widgets/K8sSummaryWidget.vue
similarity index 98%
rename from apps/ui/src/components/overview/widgets/K8sSummaryWidget.vue
rename to apps/ui/src/render/widgets/K8sSummaryWidget.vue
index ecdcb21..4e1b65f 100644
--- a/apps/ui/src/components/overview/widgets/K8sSummaryWidget.vue
+++ b/apps/ui/src/render/widgets/K8sSummaryWidget.vue
@@ -25,7 +25,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { RouterLink } from 'vue-router';
-import { K8S_SUMMARY_KPIS } from '@/composables/useOverviewDashboard';
+import { K8S_SUMMARY_KPIS } from '@/render/overview/useOverviewDashboard';
import { formatValue } from './ValueFormat';
const props = defineProps<{
diff --git a/apps/ui/src/components/overview/widgets/KpiTileWidget.vue
b/apps/ui/src/render/widgets/KpiTileWidget.vue
similarity index 100%
rename from apps/ui/src/components/overview/widgets/KpiTileWidget.vue
rename to apps/ui/src/render/widgets/KpiTileWidget.vue
diff --git a/apps/ui/src/components/overview/widgets/MetricWidget.vue
b/apps/ui/src/render/widgets/MetricWidget.vue
similarity index 100%
rename from apps/ui/src/components/overview/widgets/MetricWidget.vue
rename to apps/ui/src/render/widgets/MetricWidget.vue
diff --git a/apps/ui/src/components/overview/widgets/PilotSummaryWidget.vue
b/apps/ui/src/render/widgets/PilotSummaryWidget.vue
similarity index 97%
rename from apps/ui/src/components/overview/widgets/PilotSummaryWidget.vue
rename to apps/ui/src/render/widgets/PilotSummaryWidget.vue
index 0ff0c3a..3bb358e 100644
--- a/apps/ui/src/components/overview/widgets/PilotSummaryWidget.vue
+++ b/apps/ui/src/render/widgets/PilotSummaryWidget.vue
@@ -23,7 +23,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { RouterLink } from 'vue-router';
-import { PILOT_SUMMARY_KPIS } from '@/composables/useOverviewDashboard';
+import { PILOT_SUMMARY_KPIS } from '@/render/overview/useOverviewDashboard';
import { formatValue } from './ValueFormat';
const props = defineProps<{
diff --git a/apps/ui/src/components/overview/widgets/SectionBreak.vue
b/apps/ui/src/render/widgets/SectionBreak.vue
similarity index 100%
rename from apps/ui/src/components/overview/widgets/SectionBreak.vue
rename to apps/ui/src/render/widgets/SectionBreak.vue
diff --git a/apps/ui/src/components/overview/widgets/ServiceCountWidget.vue
b/apps/ui/src/render/widgets/ServiceCountWidget.vue
similarity index 100%
rename from apps/ui/src/components/overview/widgets/ServiceCountWidget.vue
rename to apps/ui/src/render/widgets/ServiceCountWidget.vue
diff --git a/apps/ui/src/components/overview/widgets/ValueFormat.ts
b/apps/ui/src/render/widgets/ValueFormat.ts
similarity index 100%
rename from apps/ui/src/components/overview/widgets/ValueFormat.ts
rename to apps/ui/src/render/widgets/ValueFormat.ts
diff --git a/apps/ui/src/components/shell/AdminFeatureWarning.vue
b/apps/ui/src/shell/AdminFeatureWarning.vue
similarity index 99%
rename from apps/ui/src/components/shell/AdminFeatureWarning.vue
rename to apps/ui/src/shell/AdminFeatureWarning.vue
index 977ca7b..d6f089f 100644
--- a/apps/ui/src/components/shell/AdminFeatureWarning.vue
+++ b/apps/ui/src/shell/AdminFeatureWarning.vue
@@ -32,7 +32,7 @@
* `useAdminFeatures()` state and the `module` prop.
*/
import { computed } from 'vue';
-import { useAdminFeatures } from '@/composables/useAdminFeatures';
+import { useAdminFeatures } from '@/shell/useAdminFeatures';
import Icon from '@/components/icons/Icon.vue';
const props = defineProps<{
diff --git a/apps/ui/src/components/shell/AppShell.vue
b/apps/ui/src/shell/AppShell.vue
similarity index 93%
rename from apps/ui/src/components/shell/AppShell.vue
rename to apps/ui/src/shell/AppShell.vue
index 67551f7..0c78599 100644
--- a/apps/ui/src/components/shell/AppShell.vue
+++ b/apps/ui/src/shell/AppShell.vue
@@ -19,8 +19,8 @@ import { RouterView } from 'vue-router';
import AppSidebar from './AppSidebar.vue';
import AppTopbar from './AppTopbar.vue';
import GlobalConnectivityBanner from './GlobalConnectivityBanner.vue';
-import TracePopout from '@/components/trace/TracePopout.vue';
-import ZipkinTracePopout from '@/components/trace/ZipkinTracePopout.vue';
+import TracePopout from '@/layer/traces/TracePopout.vue';
+import ZipkinTracePopout from '@/layer/traces/ZipkinTracePopout.vue';
</script>
<template>
diff --git a/apps/ui/src/components/shell/AppSidebar.vue
b/apps/ui/src/shell/AppSidebar.vue
similarity index 99%
rename from apps/ui/src/components/shell/AppSidebar.vue
rename to apps/ui/src/shell/AppSidebar.vue
index 380bfdc..669fdf4 100644
--- a/apps/ui/src/components/shell/AppSidebar.vue
+++ b/apps/ui/src/shell/AppSidebar.vue
@@ -19,10 +19,10 @@ import { computed, ref, watch } from 'vue';
import { RouterLink, useRoute, useRouter } from 'vue-router';
import Icon, { type IconName } from '@/components/icons/Icon.vue';
import logoSw from '@/assets/icons/logo-sw.svg?raw';
-import { useAuthStore } from '@/stores/auth';
-import { useLayers, firstLayerTab } from '@/composables/useLayers';
-import { useLandingOrder } from '@/composables/useLandingOrder';
-import { useOverviewDashboards } from '@/composables/useOverviewDashboards';
+import { useAuthStore } from '@/state/auth';
+import { useLayers, firstLayerTab } from '@/shell/useLayers';
+import { useLandingOrder } from '@/shell/useLandingOrder';
+import { useOverviewDashboards } from
'@/render/overview/useOverviewDashboards';
const auth = useAuthStore();
const router = useRouter();
diff --git a/apps/ui/src/components/shell/AppTopbar.vue
b/apps/ui/src/shell/AppTopbar.vue
similarity index 99%
rename from apps/ui/src/components/shell/AppTopbar.vue
rename to apps/ui/src/shell/AppTopbar.vue
index 0f9b640..6db97c3 100644
--- a/apps/ui/src/components/shell/AppTopbar.vue
+++ b/apps/ui/src/shell/AppTopbar.vue
@@ -18,10 +18,10 @@
import { computed, ref, watch } from 'vue';
import { RouterLink, useRoute } from 'vue-router';
import Icon from '@/components/icons/Icon.vue';
-import { useOapInfo } from '@/composables/useOapInfo';
-import { useLayers } from '@/composables/useLayers';
-import { useAutoRefreshStore } from '@/stores/autoRefresh';
-import { useTimeRangeStore, TIME_PRESETS, STEP_LIMITS, isValidRange, type
TimeStep } from '@/stores/timeRange';
+import { useOapInfo } from '@/shell/useOapInfo';
+import { useLayers } from '@/shell/useLayers';
+import { useAutoRefreshStore } from '@/controls/autoRefresh';
+import { useTimeRangeStore, TIME_PRESETS, STEP_LIMITS, isValidRange, type
TimeStep } from '@/controls/timeRange';
const route = useRoute();
const { layers } = useLayers();
diff --git a/apps/ui/src/components/shell/GlobalConnectivityBanner.vue
b/apps/ui/src/shell/GlobalConnectivityBanner.vue
similarity index 99%
rename from apps/ui/src/components/shell/GlobalConnectivityBanner.vue
rename to apps/ui/src/shell/GlobalConnectivityBanner.vue
index 6a6ce8e..b3dae94 100644
--- a/apps/ui/src/components/shell/GlobalConnectivityBanner.vue
+++ b/apps/ui/src/shell/GlobalConnectivityBanner.vue
@@ -34,7 +34,7 @@
*/
import { computed, onBeforeUnmount, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
-import { useOapInfo } from '@/composables/useOapInfo';
+import { useOapInfo } from '@/shell/useOapInfo';
import Icon from '@/components/icons/Icon.vue';
type RetryChoice = 'off' | '5' | '15' | '60';
diff --git a/apps/ui/src/views/landing/LandingView.vue
b/apps/ui/src/shell/LandingView.vue
similarity index 100%
rename from apps/ui/src/views/landing/LandingView.vue
rename to apps/ui/src/shell/LandingView.vue
diff --git a/apps/ui/src/views/PlaceholderView.vue
b/apps/ui/src/shell/PlaceholderView.vue
similarity index 100%
rename from apps/ui/src/views/PlaceholderView.vue
rename to apps/ui/src/shell/PlaceholderView.vue
diff --git a/apps/ui/src/router/index.ts b/apps/ui/src/shell/router/index.ts
similarity index 73%
rename from apps/ui/src/router/index.ts
rename to apps/ui/src/shell/router/index.ts
index 503e1c2..7a36580 100644
--- a/apps/ui/src/router/index.ts
+++ b/apps/ui/src/shell/router/index.ts
@@ -15,9 +15,9 @@
* limitations under the License.
*/
import { createRouter, createWebHistory, type RouteRecordRaw } from
'vue-router';
-import { useAuthStore } from '@/stores/auth';
+import { useAuthStore } from '@/state/auth';
-const placeholder = () => import('@/views/PlaceholderView.vue');
+const placeholder = () => import('@/shell/PlaceholderView.vue');
function humanKey(k: string): string {
return k.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
@@ -38,7 +38,7 @@ function layerRoute(): RouteRecordRaw {
const placeholderTabs: { path: string; label: string; phase: string }[] = [];
return {
path: 'layer/:layerKey',
- component: () => import('@/views/layer/LayerShell.vue'),
+ component: () => import('@/layer/LayerShell.vue'),
children: [
// Bare /layer/:layerKey lands on the Service view — the per-layer
// widget grid driven by the dashboard config.
@@ -46,19 +46,19 @@ function layerRoute(): RouteRecordRaw {
// Per-scope dashboards. Same view component, scope inferred from
// the URL — widget set differs per scope via the JSON template's
// `dashboards.<scope>` array.
- { path: 'service', component: () =>
import('@/views/layer/LayerDashboardsView.vue') },
- { path: 'instance', component: () =>
import('@/views/layer/LayerDashboardsView.vue') },
- { path: 'endpoint', component: () =>
import('@/views/layer/LayerDashboardsView.vue') },
+ { path: 'service', component: () =>
import('@/render/layer-dashboard/LayerDashboardsView.vue') },
+ { path: 'instance', component: () =>
import('@/render/layer-dashboard/LayerDashboardsView.vue') },
+ { path: 'endpoint', component: () =>
import('@/render/layer-dashboard/LayerDashboardsView.vue') },
{
path: 'topology',
- component: () => import('@/views/layer/LayerServiceMapView.vue'),
+ component: () => import('@/layer/service-map/LayerServiceMapView.vue'),
// The topology page ships its own in-box service-focus selector
// (the map is layer-wide by default). Declaring it here keeps
// the LayerShell's header picker hidden for this route — no
// route-string sniffing in the shell.
meta: { ownsServiceSelector: true },
},
- { path: 'dependency', component: () =>
import('@/views/layer/LayerEndpointDependencyView.vue') },
+ { path: 'dependency', component: () =>
import('@/layer/endpoint-dependency/LayerEndpointDependencyView.vue') },
// `LayerTracesEntry` is a runtime dispatcher: it inspects the
// layer template's `traces.source` and renders either the native
// trace view or the Zipkin one. Mesh / k8s layers land on Zipkin.
@@ -67,13 +67,13 @@ function layerRoute(): RouteRecordRaw {
// own service input, and Zipkin's service universe is decoupled
// from SkyWalking's anyway (different name index, no `normal`
// flag, queried via `/api/v2/services`).
- { path: 'trace', component: () =>
import('@/views/layer/LayerTracesEntry.vue'), meta: { ownsServiceSelector: true
} },
- { path: 'logs', component: () =>
import('@/views/layer/LayerLogsView.vue') },
- { path: 'trace-profiling', component: () =>
import('@/views/layer/LayerTraceProfilingView.vue') },
- { path: 'ebpf-profiling', component: () =>
import('@/views/layer/LayerEBPFProfilingView.vue') },
- { path: 'async-profiling', component: () =>
import('@/views/layer/LayerAsyncProfilingView.vue') },
- { path: 'network-profiling', component: () =>
import('@/views/layer/LayerNetworkProfilingView.vue') },
- { path: 'pprof', component: () =>
import('@/views/layer/LayerPprofProfilingView.vue') },
+ { path: 'trace', component: () =>
import('@/layer/traces/LayerTracesEntry.vue'), meta: { ownsServiceSelector:
true } },
+ { path: 'logs', component: () =>
import('@/layer/logs/LayerLogsView.vue') },
+ { path: 'trace-profiling', component: () =>
import('@/layer/profiling/LayerTraceProfilingView.vue') },
+ { path: 'ebpf-profiling', component: () =>
import('@/layer/profiling/LayerEBPFProfilingView.vue') },
+ { path: 'async-profiling', component: () =>
import('@/layer/profiling/LayerAsyncProfilingView.vue') },
+ { path: 'network-profiling', component: () =>
import('@/layer/profiling/LayerNetworkProfilingView.vue') },
+ { path: 'pprof', component: () =>
import('@/layer/profiling/LayerPprofProfilingView.vue') },
// Old single-profiling URL → redirect to the trace-profiling page
// for back-compat with bookmarks taken before the split.
{
@@ -110,7 +110,7 @@ function layerRoute(): RouteRecordRaw {
},
...placeholderTabs.map<RouteRecordRaw>((f) => ({
path: f.path,
- component: () => import('@/views/layer/LayerTabPlaceholder.vue'),
+ component: () => import('@/layer/LayerTabPlaceholder.vue'),
props: (r) => ({
title: `${humanKey(String(r.params.layerKey))} · ${f.label}`,
phase: f.phase,
@@ -121,20 +121,20 @@ function layerRoute(): RouteRecordRaw {
}
const shellRoutes: RouteRecordRaw[] = [
- { path: '', name: 'overview', component: () =>
import('@/views/overview/OverviewLanding.vue') },
+ { path: '', name: 'overview', component: () =>
import('@/render/overview/OverviewLanding.vue') },
{
path: 'overview/:id',
name: 'overview-dashboard',
- component: () => import('@/views/overview/OverviewDashboardView.vue'),
+ component: () => import('@/render/overview/OverviewDashboardView.vue'),
},
- { path: 'setup', name: 'setup', component: () =>
import('@/views/setup/SetupView.vue') },
+ { path: 'setup', name: 'setup', component: () =>
import('@/features/setup/SetupView.vue') },
layerRoute(),
// Alarms — independent page (not a layer template / overview).
// OAP `getAlarm` proxy + background-traffic timeline + per-layer
// grouping. Read-only; OAP auto-recovers, no acknowledge / silence.
- { path: 'alarms', name: 'alarms', component: () =>
import('@/views/alarms/AlarmsView.vue') },
+ { path: 'alarms', name: 'alarms', component: () =>
import('@/features/alarms/AlarmsView.vue') },
// Cluster
- { path: 'operate/cluster', component: () =>
import('@/views/operate/ClusterStatusView.vue') },
+ { path: 'operate/cluster', component: () =>
import('@/features/operate/cluster/ClusterStatusView.vue') },
// ── DSL Management ─────────────────────────────────────────────────
// Static sub-routes are declared first so they aren't shadowed by
// the catalog alternation regex (which would otherwise grab `edit`
@@ -143,23 +143,23 @@ const shellRoutes: RouteRecordRaw[] = [
{
path: 'operate/dsl/edit',
name: 'edit',
- component: () => import('@/views/operate/dsl/DslEditorView.vue'),
+ component: () => import('@/features/operate/dsl/DslEditorView.vue'),
},
{
path: 'operate/dsl/dump',
name: 'dump',
- component: () => import('@/views/operate/dsl/DslDumpView.vue'),
+ component: () => import('@/features/operate/dsl/DslDumpView.vue'),
},
{
path: 'operate/dsl/:catalog(otel-rules|telegraf-rules|lal|log-mal-rules)',
name: 'catalog',
- component: () => import('@/views/operate/dsl/DslCatalogView.vue'),
+ component: () => import('@/features/operate/dsl/DslCatalogView.vue'),
props: true,
},
{
path: 'operate/oal',
name: 'oal-catalog',
- component: () => import('@/views/operate/dsl/OalCatalogView.vue'),
+ component: () => import('@/features/operate/dsl/OalCatalogView.vue'),
},
// Inspect — gated on the `inspect` module (and `receiver-runtime-rule`
// for rule attribution; degrades cleanly to "unknown" attribution
@@ -167,7 +167,7 @@ const shellRoutes: RouteRecordRaw[] = [
{
path: 'operate/inspect',
name: 'inspect',
- component: () => import('@/views/operate/InspectView.vue'),
+ component: () => import('@/features/operate/inspect/InspectView.vue'),
},
// Live debugger — gated on `dsl-debugging`. History is local-only
// (browser localStorage) so it stays useful even when admin is down.
@@ -175,24 +175,24 @@ const shellRoutes: RouteRecordRaw[] = [
{
path: 'operate/live-debug/history',
name: 'debug-history',
- component: () => import('@/views/operate/live-debug/DebugHistoryView.vue'),
+ component: () =>
import('@/features/operate/live-debug/DebugHistoryView.vue'),
},
{
path: 'operate/live-debug/:tab(mal|lal|oal)?',
name: 'live-debugger',
- component: () => import('@/views/operate/live-debug/LiveDebuggerView.vue'),
+ component: () =>
import('@/features/operate/live-debug/LiveDebuggerView.vue'),
},
// Admin
{
path: 'admin/layer-dashboards',
- component: () => import('@/views/admin/LayerDashboardsAdmin.vue'),
+ component: () =>
import('@/features/admin/layer-templates/LayerDashboardsAdmin.vue'),
},
// Alert page setup — sits under Dashboard setup in the sidebar but
// routes off the admin tree since it's an operator-only config view.
{
path: 'admin/alert-page-setup',
name: 'alert-page-setup',
- component: () => import('@/views/admin/AlertPageSetupView.vue'),
+ component: () =>
import('@/features/admin/alert-page/AlertPageSetupView.vue'),
},
{ path: 'admin/users', component: placeholder, props: { title: 'Users',
phase: 'Phase 7' } },
{ path: 'admin/roles', component: placeholder, props: { title: 'Roles &
permissions', phase: 'Phase 7' } },
@@ -204,12 +204,12 @@ const router = createRouter({
{
path: '/login',
name: 'login',
- component: () => import('@/views/auth/LoginView.vue'),
+ component: () => import('@/features/auth/LoginView.vue'),
meta: { public: true },
},
{
path: '/',
- component: () => import('@/components/shell/AppShell.vue'),
+ component: () => import('@/shell/AppShell.vue'),
children: shellRoutes,
},
{
diff --git a/apps/ui/src/composables/useAdminFeatures.ts
b/apps/ui/src/shell/useAdminFeatures.ts
similarity index 97%
rename from apps/ui/src/composables/useAdminFeatures.ts
rename to apps/ui/src/shell/useAdminFeatures.ts
index 7550b5d..8034a67 100644
--- a/apps/ui/src/composables/useAdminFeatures.ts
+++ b/apps/ui/src/shell/useAdminFeatures.ts
@@ -19,7 +19,7 @@ import { computed } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import type { PreflightResult } from '@skywalking-horizon-ui/api-client';
import { bffClient } from '@/api/client';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from '../controls/useAutoRefreshSubscribe';
/**
* Admin-port preflight — interrogates OAP's `/debugging/config/dump`
diff --git a/apps/ui/src/composables/useLandingOrder.ts
b/apps/ui/src/shell/useLandingOrder.ts
similarity index 97%
rename from apps/ui/src/composables/useLandingOrder.ts
rename to apps/ui/src/shell/useLandingOrder.ts
index 5a1fafe..d1994be 100644
--- a/apps/ui/src/composables/useLandingOrder.ts
+++ b/apps/ui/src/shell/useLandingOrder.ts
@@ -17,7 +17,7 @@
import { computed, type ComputedRef } from 'vue';
import type { LayerDef } from '@skywalking-horizon-ui/api-client';
-import { useSetupStore } from '@/stores/setup';
+import { useSetupStore } from '@/state/setup';
/**
* Sort layers by `landing.priority` (lower first). Ties break by the OAP
diff --git a/apps/ui/src/composables/useLayers.ts
b/apps/ui/src/shell/useLayers.ts
similarity index 100%
rename from apps/ui/src/composables/useLayers.ts
rename to apps/ui/src/shell/useLayers.ts
diff --git a/apps/ui/src/composables/useOapInfo.ts
b/apps/ui/src/shell/useOapInfo.ts
similarity index 98%
rename from apps/ui/src/composables/useOapInfo.ts
rename to apps/ui/src/shell/useOapInfo.ts
index a233c54..32690f6 100644
--- a/apps/ui/src/composables/useOapInfo.ts
+++ b/apps/ui/src/shell/useOapInfo.ts
@@ -17,7 +17,7 @@
import { computed } from 'vue';
import { useQuery } from '@tanstack/vue-query';
-import { useAutoRefreshSubscribe } from './useAutoRefreshSubscribe';
+import { useAutoRefreshSubscribe } from '../controls/useAutoRefreshSubscribe';
import { parseOapTimezoneMinutes, type OapInfo } from
'@skywalking-horizon-ui/api-client';
import { bffClient } from '@/api/client';
diff --git a/apps/ui/src/stores/auth.ts b/apps/ui/src/state/auth.ts
similarity index 100%
rename from apps/ui/src/stores/auth.ts
rename to apps/ui/src/state/auth.ts
diff --git a/apps/ui/src/stores/setup.ts b/apps/ui/src/state/setup.ts
similarity index 99%
rename from apps/ui/src/stores/setup.ts
rename to apps/ui/src/state/setup.ts
index e0b1183..a37313c 100644
--- a/apps/ui/src/stores/setup.ts
+++ b/apps/ui/src/state/setup.ts
@@ -30,7 +30,7 @@ import { bffClient } from '@/api/client';
import {
defaultColumnsForLayer,
defaultOrderByForLayer,
-} from '@/composables/metricCatalog';
+} from '@/utils/metricCatalog';
export type { LayerConfig, LandingConfig };
diff --git a/apps/ui/src/composables/metricCatalog.ts
b/apps/ui/src/utils/metricCatalog.ts
similarity index 100%
rename from apps/ui/src/composables/metricCatalog.ts
rename to apps/ui/src/utils/metricCatalog.ts
diff --git a/apps/ui/src/composables/metricColor.ts
b/apps/ui/src/utils/metricColor.ts
similarity index 100%
rename from apps/ui/src/composables/metricColor.ts
rename to apps/ui/src/utils/metricColor.ts