hide app section in settings when all apps are disabled

This commit is contained in:
swithek 2026-09-12 17:56:00 +02:00
parent 834c6a5a0f
commit 05f07d82e8
4 changed files with 71 additions and 8 deletions

View File

@ -16,6 +16,7 @@ import {
mockAuthOrganization,
seedAuthAccounts,
seedAuthSession,
seedCapabilities,
t,
teleportedButton,
} from "../test-helpers"
@ -112,6 +113,29 @@ describe("<BaseModal>", { concurrent: false }, () => {
])
})
it.for([{ app: "github" }, { app: "slack" }] as {
app: "github" | "slack"
}[])(
"keeps the apps section while only $app is available",
async ({ app }, { expect }) => {
seedCapabilities({ github: app === "github", slack: app === "slack" })
await mountModal()
expect(dialogText()).toContain(t("settings.apps.title"))
},
)
it("drops the apps section on a deployment with no apps", async ({
expect,
}) => {
seedCapabilities({ github: false, slack: false })
await mountModal()
expect(dialogText()).not.toContain(t("settings.apps.title"))
})
it("gives the deep-linkable sections their anchors", async ({ expect }) => {
await mountModal()

View File

@ -20,6 +20,7 @@ const emit = defineEmits<{
}>()
const { t } = useI18n({ useScope: "global" })
const { isAnyAppEnabled } = useCapabilitiesAPI()
const openAction = ref<
| null
| "email-change"
@ -35,7 +36,7 @@ const openAction = ref<
const actionOpts = ref<OrganizationMember | DataSourceType | DataSource | null>(
null,
)
const sections = [
const sections = computed(() => [
{
title: t("settings.profile.title"),
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- eslint's ts program resolves .vue imports as error typed, vue-tsc accepts this
@ -47,12 +48,16 @@ const sections = [
component: WorkspaceSection,
id: ORG_SECTION_ID,
},
{
title: t("settings.apps.title"),
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- eslint's ts program resolves .vue imports as error typed, vue-tsc accepts this
component: AppsSection,
id: APP_SECTION_ID, // for scrolling into view when opened
},
...(isAnyAppEnabled.value
? [
{
title: t("settings.apps.title"),
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- eslint's ts program resolves .vue imports as error typed, vue-tsc accepts this
component: AppsSection,
id: APP_SECTION_ID, // for scrolling into view when opened
},
]
: []),
{
title: t("settings.mcp.title"),
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- eslint's ts program resolves .vue imports as error typed, vue-tsc accepts this
@ -64,7 +69,7 @@ const sections = [
component: DataSourceSection,
id: DATA_SOURCE_SECTION_ID,
},
]
])
whenever(open, async (val) => {
if (val === "org-members") {

View File

@ -98,6 +98,36 @@ describe("useCapabilitiesAPI", { concurrent: false }, () => {
})
})
describe("isAnyAppEnabled", () => {
const cc: Record<string, { github: boolean; slack: boolean }> = {
"both apps are available": { github: true, slack: true },
"only github is available": { github: true, slack: false },
"only slack is available": { github: false, slack: true },
}
Object.entries(cc).forEach(([name, c]) => {
it(`reports enabled when ${name}`, async ({ expect }) => {
mockEndpoint("GET", "/api/capabilities", () => stubCapabilities(c))
const api = makeCapabilitiesAPI()
await api.fetchCapabilities.refresh()
expect(api.isAnyAppEnabled.value).toBe(true)
})
})
it("reports disabled when neither app is available", async ({ expect }) => {
mockEndpoint("GET", "/api/capabilities", () =>
stubCapabilities({ github: false, slack: false }),
)
const api = makeCapabilitiesAPI()
await api.fetchCapabilities.refresh()
expect(api.isAnyAppEnabled.value).toBe(false)
})
})
describe("isAssistantEnabled", () => {
const cc: Record<string, { status: AssistantStatus; enabled: boolean }> = {
"runs a full-strength model": {

View File

@ -28,6 +28,9 @@ export default function () {
const isGithubEnabled = enabled((c) => c.github)
const isSlackEnabled = enabled((c) => c.slack)
// github and slack are the only connectable apps, so both being off
// leaves nothing for the apps settings section to show
const isAnyAppEnabled = enabled((c) => c.github || c.slack)
const isChangeDetectionEnabled = enabled((c) => c.changeDetection)
const isSearchEnabled = enabled((c) => c.search)
@ -47,6 +50,7 @@ export default function () {
fetchCapabilities,
isGithubEnabled,
isSlackEnabled,
isAnyAppEnabled,
isChangeDetectionEnabled,
isSearchEnabled,
isAssistantEnabled,