{% endif %}
- {% if file_sync_enabled %}
+ {% if sidebar_settings.per_user_semantic_kernel and sidebar_settings.enable_semantic_kernel and sidebar_settings.allow_group_agents %}
+ {% if sidebar_settings.allow_group_plugins %}
+
- {% endif %}
{% if group_workspace_identities_enabled %}
{% endif %}
+ {% if file_sync_enabled %}
-
- {% if settings.allow_group_workflows %}
-
-
{% endif %}
{% if settings.per_user_semantic_kernel and settings.enable_semantic_kernel %}
- {% if settings.allow_group_agents %}
+ {% if settings.enable_semantic_kernel and settings.allow_group_custom_endpoints and settings.enable_multi_model_endpoints %}
-
+ {% endif %}
+ {% if settings.allow_group_agents %}
{% if settings.enable_semantic_kernel and settings.allow_group_plugins %}
{% endif %}
- {% endif %}
- {% if settings.enable_semantic_kernel and settings.allow_group_custom_endpoints and settings.enable_multi_model_endpoints %}
+
{% endif %}
- {% if settings.allow_user_custom_endpoints and settings.enable_multi_model_endpoints %}
-
-
-
- {% endif %}
diff --git a/docs/explanation/features/index.md b/docs/explanation/features/index.md
index 9c2512908..66720f2f2 100644
--- a/docs/explanation/features/index.md
+++ b/docs/explanation/features/index.md
@@ -47,6 +47,7 @@ category: Version History
- [Data Management Durable Backup Jobs](DATA_MANAGEMENT_BACKUP_MIGRATION.md)
- [Data Management Migration Resilience](DATA_MANAGEMENT_MIGRATION_RESILIENCE.md)
- [Migration Provenance](MIGRATION_PROVENANCE.md)
+- [Workspace Section Order](v0.250.211/WORKSPACE_SECTION_ORDER.md)
- [Microsoft Teams App SSO](v0.242.072/TEAMS_APP_SSO.md)
- [Tabular SK Large Result Pagination](v0.242.067/TABULAR_SK_LARGE_RESULT_PAGINATION.md)
- [Model Endpoint Model Icon Picker](v0.242.060/MODEL_ENDPOINT_MODEL_ICON_PICKER.md)
diff --git a/docs/explanation/features/v0.250.211/WORKSPACE_SECTION_ORDER.md b/docs/explanation/features/v0.250.211/WORKSPACE_SECTION_ORDER.md
new file mode 100644
index 000000000..d349d57c4
--- /dev/null
+++ b/docs/explanation/features/v0.250.211/WORKSPACE_SECTION_ORDER.md
@@ -0,0 +1,174 @@
+# Workspace Section Order
+
+## Overview
+
+Workspace sections now render in a single canonical order of operations across every surface
+that lists them. Previously each surface used its own ordering, which made it hard for users and
+admins to see how the pieces relate — that Identities feed both Sync and Actions, that Actions
+belong to Agents, and that Workflows consume Agents.
+
+- **Version implemented:** 0.250.211
+- **Related issue:** [#1255](https://github.com/microsoft/simplechat/issues/1255)
+- **Dependencies:** none — this change is presentation-only and adds no new settings
+
+## Canonical order
+
+Sections still appear only when their existing feature gates are enabled. When a section is
+enabled it always appears in this position relative to the others:
+
+| # | Section | Why it sits here |
+|---|---------|------------------|
+| 1 | **Documents** | The knowledge you bring into the workspace |
+| 2 | **Prompts** | The instructions you reuse against that knowledge |
+| 3 | **Identities** | The credentials both Sync and Actions resolve against |
+| 4 | **Sync** | Uses Identities to pull Documents in automatically |
+| 5 | **Endpoints** | The models that Actions, Agents, and Workflows run on |
+| 6 | **Actions** | Governed tools, built on Identities and Endpoints |
+| 7 | **Agents** | Assemble Documents, Prompts, Actions, and Endpoints |
+| 8 | **Workflows** | Run Agents manually, on a schedule, or on a trigger |
+
+Each entry depends on the ones above it, so reading the tab strip left to right now describes how
+a workspace is actually built up.
+
+## Architecture
+
+### Surfaces kept in sync
+
+Three separate surfaces list workspace sections, and all three now use the canonical order:
+
+| Surface | Personal | Group |
+|---------|----------|-------|
+| Top `nav-tabs` bar | `#workspaceTab` in `templates/workspace.html` | `#groupWorkspaceTab` in `templates/group_workspaces.html` |
+| Collapsed/mobile **Section** dropdown | `#workspace-section-select` | `#group-workspace-section-select` |
+| Left-hand sidebar submenu | `#personal-workspace-submenu` in `templates/_sidebar_nav.html` | `#group-workspace-submenu` in `templates/_sidebar_nav.html` |
+
+`static/js/workspace_section_switcher.js` maps the dropdown's option values onto tab button ids,
+so the dropdown and the tab strip must be edited together — the switcher does not derive one from
+the other.
+
+### Public workspaces
+
+Public workspaces already satisfied the canonical relative order and were left unchanged:
+
+- `templates/public_workspaces.html` lists **Documents** then **Prompts**.
+- `templates/manage_public_workspace.html` lists **Identities** before **Sync** among its
+ management tabs (General, Membership, Stats, Identities, Sync, Settings).
+
+### Tab panes are deliberately not reordered
+
+Bootstrap resolves tab panes by `id` / `data-bs-target`, and inactive panes are hidden, so pane
+DOM order has no visual or accessibility effect. Panes were left in place to keep the change
+reviewable — `group_workspaces.html` alone is roughly 389 KB.
+
+### Gate restructuring
+
+Moving Actions ahead of Agents, and Endpoints ahead of both, required unwinding nested Jinja
+conditionals without changing their effective conditions. For example, the personal workspace
+Actions tab was nested inside the Agents gate:
+
+```jinja
+{% if settings.per_user_semantic_kernel and settings.enable_semantic_kernel %}
+ {% if settings.allow_user_agents %}
+ {% if settings.allow_user_plugins %}
+ {# Actions #}
+ {% endif %}
+ {# Agents #}
+ {% endif %}
+{% endif %}
+```
+
+Actions still requires `per_user_semantic_kernel`, `enable_semantic_kernel`, `allow_user_agents`,
+and `allow_user_plugins` — only its render position changed.
+
+## Navigation gating fixes
+
+The sidebar previously used gates that did not match the tabs they linked to, so a sidebar link
+could point at a tab that was never rendered. Those gates are now aligned:
+
+| Navigation item | Previous gate | Corrected gate |
+|-----------------|---------------|----------------|
+| Personal → Your Agents | `per_user_semantic_kernel and enable_semantic_kernel` | added `allow_user_agents` |
+| Personal → Your Actions | `per_user_semantic_kernel and enable_semantic_kernel` | added `allow_user_agents and allow_user_plugins` |
+| Personal → Identities | `file_sync_enabled or enable_semantic_kernel or enable_multi_model_endpoints` | `file_sync_enabled or enable_semantic_kernel` |
+| Group → Group Agents | `allow_group_agents and enable_semantic_kernel` | added `per_user_semantic_kernel` |
+| Group → Group Actions | `allow_group_agents and enable_semantic_kernel` | added `per_user_semantic_kernel and allow_group_plugins` |
+| Group → Identities | `file_sync_enabled or enable_semantic_kernel or enable_multi_model_endpoints` | `file_sync_enabled or enable_semantic_kernel` |
+| Group → Group Workflows | *link did not exist* | added, gated by `allow_group_workflows` |
+
+The group sidebar had no Workflows entry at all even though the group Workflows tab has shipped
+for some time, so group workflows were unreachable from the left-hand navigation.
+
+## Configuration
+
+No new configuration. The sections that appear continue to be controlled by the existing settings:
+
+| Section | Personal gate | Group gate |
+|---------|---------------|------------|
+| Documents | always | always |
+| Prompts | always | always |
+| Identities | `enable_file_sync*` or `enable_semantic_kernel` | `enable_file_sync*` or `enable_semantic_kernel` |
+| Sync | `enable_file_sync*` | `enable_file_sync*` |
+| Endpoints | `allow_user_custom_endpoints` + `enable_multi_model_endpoints` | `per_user_semantic_kernel` + `enable_semantic_kernel` + `allow_group_custom_endpoints` + `enable_multi_model_endpoints` |
+| Actions | `per_user_semantic_kernel` + `enable_semantic_kernel` + `allow_user_agents` + `allow_user_plugins` | `per_user_semantic_kernel` + `enable_semantic_kernel` + `allow_group_agents` + `allow_group_plugins` |
+| Agents | `per_user_semantic_kernel` + `enable_semantic_kernel` + `allow_user_agents` | `per_user_semantic_kernel` + `enable_semantic_kernel` + `allow_group_agents` |
+| Workflows | `allow_user_workflows` | `allow_group_workflows` |
+
+`enable_file_sync*` is the resolved per-scope File Sync availability computed by
+`is_file_sync_enabled_for_user` / `is_file_sync_enabled_for_group`.
+
+## File structure
+
+| File | Change |
+|------|--------|
+| `application/single_app/templates/workspace.html` | Reordered `#workspaceTab` and `#workspace-section-select` |
+| `application/single_app/templates/group_workspaces.html` | Reordered `#groupWorkspaceTab` and `#group-workspace-section-select` |
+| `application/single_app/templates/_sidebar_nav.html` | Reordered both submenus, added the group Workflows link, aligned gates, refreshed parent tooltips |
+| `application/single_app/config.py` | `VERSION` bumped to `0.250.211` |
+| `functional_tests/test_workspace_section_order.py` | New coverage for the canonical order and gating parity |
+| `functional_tests/test_endpoints_tab_order_visibility.py` | Updated for the new Endpoints → Actions → Agents order |
+
+## Usage
+
+Nothing to enable. Users see the new order the next time they open a workspace page. Sections that
+an admin has disabled remain hidden, and the remaining sections close up while preserving their
+relative positions.
+
+## Testing and validation
+
+`functional_tests/test_workspace_section_order.py` renders each of the six section lists in
+isolation with Jinja and checks:
+
+1. **Canonical order when everything is enabled** — all six surfaces render exactly the eight
+ sections in the canonical order.
+2. **Disabled features only remove sections** — every combination of the eight relevant feature
+ flags (256 per scope) still yields a subsequence of the canonical order, with no duplicates and
+ with Documents and Prompts always leading.
+3. **Gating lockstep** — for every flag combination, the tab strip, the Section dropdown, and the
+ sidebar submenu expose an identical set of sections. This is what guards the navigation gating
+ fixes above.
+4. **Permission markers survive** — the permission-aware group Identities markers
+ (`data-group-identities-tab-nav`, `data-group-identities-sidebar-nav`,
+ `data-group-identities-section-option`) are still present after the reordering.
+5. **Public workspaces** — Documents precedes Prompts, and Identities precedes Sync on the manage
+ page.
+
+The test was verified against the pre-change templates and fails there, confirming it is not
+vacuous.
+
+### Known limitations
+
+- Tab pane DOM order still reflects the historical ordering. This is intentional and has no user
+ impact, but it means pane order and tab order no longer visually correspond when reading the
+ template source.
+- The personal workspace guided tutorial (`static/js/workspace/workspace-tutorial.js`) still walks
+ Documents → Prompts → Agents → Actions. Its selectors are id-based so it functions correctly,
+ but its narrative sequence no longer mirrors the tab order.
+- Section grouping (dividers or group labels such as Content / Connections / Automation) is a
+ possible follow-up; this change establishes the ordering those groups would build on.
+
+## Related documentation
+
+- `docs/explanation/fixes/v0.241.001/ENDPOINTS_TAB_ORDER_VISIBILITY_FIX.md` — earlier work that
+ introduced the endpoints tab gating this change reorders
+- `docs/explanation/features/v0.229.001/LEFT_HAND_NAVIGATION_MENU.md` — the left-hand navigation
+ this change keeps in sync with the tab strip
diff --git a/docs/explanation/release_notes.md b/docs/explanation/release_notes.md
index 6fd25b120..9b7490e80 100644
--- a/docs/explanation/release_notes.md
+++ b/docs/explanation/release_notes.md
@@ -2,6 +2,28 @@
For feature-focused and fix-focused drill-downs by version, see [Features by Version](/explanation/features/) and [Fixes by Version](/explanation/fixes/).
+### **(v0.250.211)**
+
+#### User Interface Enhancements
+
+* **Consistent Workspace Section Order**
+ * Workspace sections now follow a single order of operations everywhere they are listed: Documents, Prompts, Identities, Sync, Endpoints, Actions, Agents, Workflows.
+ * The order reflects how a workspace is actually built up, so it is clearer that Identities feed both Sync and Actions, that Actions belong to Agents, and that Workflows run Agents.
+ * Applied to the tab strip, the collapsed Section dropdown, and the left-hand sidebar submenus for personal and group workspaces. Public workspaces already matched this order and were left unchanged.
+ * Sections that an admin has disabled stay hidden; the remaining sections simply close up while keeping their relative positions.
+ * (Ref: #1255, `workspace.html`, `group_workspaces.html`, `_sidebar_nav.html`, `WORKSPACE_SECTION_ORDER.md`)
+
+#### Bug Fixes
+
+* **Group Workflows Missing From Sidebar Navigation**
+ * Added the missing Group Workflows link to the left-hand group workspace submenu. Group workflows previously had a working tab but no way to reach it from the sidebar.
+ * (Ref: #1255, `_sidebar_nav.html`, group workflows navigation)
+
+* **Sidebar Links Pointing At Unrendered Workspace Tabs**
+ * Fixed left-hand navigation links whose visibility rules did not match the tabs they opened, so a link could appear for a section that was never rendered.
+ * Personal Agents and Actions links now respect the user agent and plugin permissions, group Agents and Actions links now respect per-user Semantic Kernel and group plugin permissions, and both Identities links now match their tab's File Sync and Semantic Kernel conditions.
+ * (Ref: #1255, `_sidebar_nav.html`, `test_workspace_section_order.py`)
+
### **(v0.250.210)**
#### Bug Fixes
diff --git a/functional_tests/test_endpoints_tab_order_visibility.py b/functional_tests/test_endpoints_tab_order_visibility.py
index cde0fd669..90eed4254 100644
--- a/functional_tests/test_endpoints_tab_order_visibility.py
+++ b/functional_tests/test_endpoints_tab_order_visibility.py
@@ -2,13 +2,20 @@
# test_endpoints_tab_order_visibility.py
"""
Functional test for workspace/group endpoints tab order and visibility.
-Version: 0.239.197
+Version: 0.250.211
Implemented in: 0.239.197
+Reordered in: 0.250.211
This test ensures endpoints tabs only render when multi-endpoint management is
enabled, the personal and group admin-controlled toggles stay hidden, and the
admin multi-endpoint toggle is removed after migration while its script keeps
the endpoint editor initialized.
+
+Since 0.250.211 the workspace sections follow a canonical order of operations
+(Documents, Prompts, Identities, Sync, Endpoints, Actions, Agents, Workflows), so
+Endpoints now renders ahead of Actions and Agents. Tab pane DOM order is
+deliberately not asserted: Bootstrap resolves panes by id and hides inactive ones,
+so pane order has no visual or accessibility effect.
"""
import os
@@ -29,20 +36,17 @@ def read_file_text(file_path):
def test_workspace_endpoints_tab_order_visibility():
content = read_file_text(WORKSPACE_TEMPLATE)
- agents_idx = content.find('id="agents-tab-btn"')
- actions_idx = content.find('id="plugins-tab-btn"')
endpoints_idx = content.find('id="endpoints-tab-btn"')
+ actions_idx = content.find('id="plugins-tab-btn"')
+ agents_idx = content.find('id="agents-tab-btn"')
- assert agents_idx != -1, "Agents tab button missing in workspace template."
- assert actions_idx != -1, "Actions tab button missing in workspace template."
assert endpoints_idx != -1, "Endpoints tab button missing in workspace template."
- assert agents_idx < actions_idx < endpoints_idx, "Workspace tab order should be Agents -> Actions -> Endpoints."
+ assert actions_idx != -1, "Actions tab button missing in workspace template."
+ assert agents_idx != -1, "Agents tab button missing in workspace template."
+ assert endpoints_idx < actions_idx < agents_idx, "Workspace tab order should be Endpoints -> Actions -> Agents."
- actions_pane_idx = content.find('id="plugins-tab"')
- endpoints_pane_idx = content.find('id="endpoints-tab"')
- assert actions_pane_idx != -1, "Actions tab pane missing in workspace template."
- assert endpoints_pane_idx != -1, "Endpoints tab pane missing in workspace template."
- assert actions_pane_idx < endpoints_pane_idx, "Endpoints tab pane should appear after actions pane."
+ assert content.find('id="plugins-tab"') != -1, "Actions tab pane missing in workspace template."
+ assert content.find('id="endpoints-tab"') != -1, "Endpoints tab pane missing in workspace template."
expected_gate = "{% if settings.allow_user_custom_endpoints and settings.enable_multi_model_endpoints %}"
assert content.count(expected_gate) >= 2, "Workspace endpoints tab button and pane should share the multi-endpoint gate."
@@ -55,20 +59,17 @@ def test_workspace_endpoints_tab_order_visibility():
def test_group_endpoints_tab_order_visibility():
content = read_file_text(GROUP_TEMPLATE)
- agents_idx = content.find('id="group-agents-tab-btn"')
- actions_idx = content.find('id="group-plugins-tab-btn"')
endpoints_idx = content.find('id="group-endpoints-tab-btn"')
+ actions_idx = content.find('id="group-plugins-tab-btn"')
+ agents_idx = content.find('id="group-agents-tab-btn"')
- assert agents_idx != -1, "Group agents tab button missing in group workspace template."
- assert actions_idx != -1, "Group actions tab button missing in group workspace template."
assert endpoints_idx != -1, "Group endpoints tab button missing in group workspace template."
- assert agents_idx < actions_idx < endpoints_idx, "Group tab order should be Agents -> Actions -> Endpoints."
+ assert actions_idx != -1, "Group actions tab button missing in group workspace template."
+ assert agents_idx != -1, "Group agents tab button missing in group workspace template."
+ assert endpoints_idx < actions_idx < agents_idx, "Group tab order should be Endpoints -> Actions -> Agents."
- actions_pane_idx = content.find('id="group-plugins-tab"')
- endpoints_pane_idx = content.find('id="group-endpoints-tab"')
- assert actions_pane_idx != -1, "Group actions tab pane missing in group workspace template."
- assert endpoints_pane_idx != -1, "Group endpoints tab pane missing in group workspace template."
- assert actions_pane_idx < endpoints_pane_idx, "Group endpoints tab pane should appear after actions pane."
+ assert content.find('id="group-plugins-tab"') != -1, "Group actions tab pane missing in group workspace template."
+ assert content.find('id="group-endpoints-tab"') != -1, "Group endpoints tab pane missing in group workspace template."
expected_gate = "{% if settings.enable_semantic_kernel and settings.allow_group_custom_endpoints and settings.enable_multi_model_endpoints %}"
assert content.count(expected_gate) >= 2, "Group endpoints tab button and pane should share the multi-endpoint gate."
diff --git a/functional_tests/test_workspace_section_order.py b/functional_tests/test_workspace_section_order.py
new file mode 100644
index 000000000..272d5b173
--- /dev/null
+++ b/functional_tests/test_workspace_section_order.py
@@ -0,0 +1,404 @@
+#!/usr/bin/env python3
+# test_workspace_section_order.py
+"""
+Functional test for the canonical workspace section order.
+Version: 0.250.211
+Implemented in: 0.250.211
+
+This test ensures every surface that lists workspace sections renders them in the
+canonical order of operations (Documents, Prompts, Identities, Sync, Endpoints,
+Actions, Agents, Workflows), and that each surface shows exactly the same sections
+for a given set of feature flags so a navigation link can never point at a tab that
+was never rendered.
+"""
+
+import itertools
+import re
+import traceback
+from pathlib import Path
+
+from jinja2 import Environment
+
+from test_support.versioning import assert_app_version_at_least
+
+IMPLEMENTED_VERSION = "0.250.211"
+
+REPO_ROOT = Path(__file__).resolve().parents[1]
+TEMPLATE_DIR = REPO_ROOT / "application" / "single_app" / "templates"
+WORKSPACE_TEMPLATE = TEMPLATE_DIR / "workspace.html"
+GROUP_TEMPLATE = TEMPLATE_DIR / "group_workspaces.html"
+SIDEBAR_TEMPLATE = TEMPLATE_DIR / "_sidebar_nav.html"
+PUBLIC_TEMPLATE = TEMPLATE_DIR / "public_workspaces.html"
+MANAGE_PUBLIC_TEMPLATE = TEMPLATE_DIR / "manage_public_workspace.html"
+
+CANONICAL_ORDER = [
+ "documents",
+ "prompts",
+ "identities",
+ "sync",
+ "endpoints",
+ "actions",
+ "agents",
+ "workflows",
+]
+
+NAV_BUTTON_RE = re.compile(r'\bid="([a-z-]+-tab-btn)"')
+SELECT_OPTION_RE = re.compile(r'