mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 00:59:28 -04:00
fix(ci): repair master failures in CLI bind test, addons UI build and e2e (#12876)
* test(cli): use a globally routable IPv6 address in the public bind spec 2001:db8::/32 is the IPv6 documentation prefix and is now classed as non-public, so the bind is trusted and the spec failed. Use a public address from 2606:4700:4700::/48 instead. * fix(addons): rename installFlow.js so it no longer clashes with InstallFlow.jsx installFlow.js and InstallFlow.jsx differ only by case. On a case-insensitive filesystem the bundler can resolve `import FlowStatus from './InstallFlow'` to the .js module, which has no default export, and the macOS build fails with MISSING_EXPORT. Rename the module to installAndTurnOn.js, after its main export, and update its two importers. No code changes. Assisted-by: Claude Code:claude-sonnet-5-5 * fix(addons): keep Reload on the page of an add-on that is turned off The clearer empty states for a stopped add-on dropped the Reload button from the unavailable page, so a user who turned the add-on back on had no way to mount it again without leaving the page. Render the button in the actions of the off state, next to Turn on. * test(ui): serve the Voice add-on in the diarization profiles spec The remembered voices link now opens the page of the Voice add-on, which the core build no longer draws. Install the built Voice bundle next to Studio, as the other specs do for their add-ons, and build it in the global setup. --------- Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
1 parent
795d9dac7b
commit
994d3acd4d
7 files changed
+11
-9
No files matched your search
@@ -88,7 +88,7 @@ var _ = Describe("requireAuthOrTrustedBind", func() {
|
||||
})
|
||||
|
||||
It("rejects public IPv6", func() {
|
||||
Expect(requireAuthOrTrustedBind("[2001:db8::1]:8080", false, false)).To(HaveOccurred())
|
||||
Expect(requireAuthOrTrustedBind("[2606:4700:4700::1111]:8080", false, false)).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -27,8 +27,9 @@ async function setup(page, permission = true, diarizationPermission = true) {
|
||||
return route.fulfill({ json: data })
|
||||
})
|
||||
await page.route('**/v1/audio/diarization', route => route.fulfill({ json: result }))
|
||||
// Studio is an add-on. Installed after the catch-all above, so its routes win.
|
||||
await installStudioAddons(page, { ids: ['studio'] })
|
||||
// Studio and Voice are add-ons. Installed after the catch-all above, so their routes win.
|
||||
// The remembered-voices link opens the Voice add-on page.
|
||||
await installStudioAddons(page, { ids: ['studio', 'voice'] })
|
||||
await page.goto('/app/diarization')
|
||||
if (!diarizationPermission) return
|
||||
await expect(page.getByRole('button', { name: 'diarizer', exact: true })).toBeVisible()
|
||||
|
||||
+4
-4
@@ -24,9 +24,9 @@ export async function buildAddonBundles(ids) {
|
||||
for (const id of ids) await import(path.join(addons, id, 'ui/build.mjs')).then(m => m.build())
|
||||
}
|
||||
|
||||
// The add-ons the specs serve from their build output: Studio and Talk through
|
||||
// installStudioAddons, Face and Fine-tuning through their own routes.
|
||||
export async function buildStudioAddons(ids = ['studio', 'talk', 'face', 'fine-tuning']) {
|
||||
// The add-ons the specs serve from their build output: Studio, Talk and Voice
|
||||
// through installStudioAddons, Face and Fine-tuning through their own routes.
|
||||
export async function buildStudioAddons(ids = ['studio', 'talk', 'voice', 'face', 'fine-tuning']) {
|
||||
await buildAddonBundles(ids)
|
||||
process.env[BUILT] = '1'
|
||||
}
|
||||
@@ -55,7 +55,7 @@ export function packagedApp(id, over = {}) {
|
||||
// Returns the state of mockAddons.
|
||||
export async function installStudioAddons(page, { ids = ['studio', 'talk'], ...options } = {}) {
|
||||
const dirs = await Promise.all(ids.map(build))
|
||||
await page.route(/\/api\/addons\/(studio|talk)\/assets\//, route => {
|
||||
await page.route(/\/api\/addons\/(studio|talk|voice)\/assets\//, route => {
|
||||
const parts = new URL(route.request().url()).pathname.split('/')
|
||||
const id = parts[3]
|
||||
const file = parts.slice(6).join('/')
|
||||
|
||||
@@ -181,6 +181,7 @@ export default function AddonRoute() {
|
||||
<Icon name={working ? 'spinner' : 'toggle-on'} spin={working} /> {t('apps.start')}
|
||||
</button>
|
||||
)}
|
||||
{extra}
|
||||
{outcome && outcome.outcome && describeOutcome(outcome.outcome, t, outcome.error) && (
|
||||
<span className="ad-card__note" data-tone="error" role="alert">{describeOutcome(outcome.outcome, t, outcome.error)}</span>
|
||||
)}
|
||||
|
||||
File renamed without changes.
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { createActionBook, effectOutcome } from './actionBook'
|
||||
import { runLifecycle, settleOperation } from './lifecycleFlow'
|
||||
import { runInstallAndTurnOn } from './installFlow'
|
||||
import { runInstallAndTurnOn } from './installAndTurnOn'
|
||||
|
||||
// Runs user actions that change an add-on, one operation identity per action.
|
||||
//
|
||||
|
||||
@@ -17,7 +17,7 @@ import { runLifecycle, settleOperation } from '../../src/components/addons/lifec
|
||||
import { createActionBook, effectOutcome } from '../../src/components/addons/actionBook.js'
|
||||
import { describeError, describeOutcome } from '../../src/components/addons/errors.js'
|
||||
import { backendState, libraryOrigin, shortDigest as shortBackendDigest } from '../../src/utils/backendRows.js'
|
||||
import { runInstallAndTurnOn } from '../../src/components/addons/installFlow.js'
|
||||
import { runInstallAndTurnOn } from '../../src/components/addons/installAndTurnOn.js'
|
||||
import { installSteps, STEP_ORDER } from '../../src/components/addons/installSteps.js'
|
||||
|
||||
const json = (status, body) => ({ ok: status >= 200 && status < 300, status, json: async () => body })
|
||||
|
||||
Reference in new issue
Block a user