Commit Graph
685 Commits
Author SHA1 Message Date
nocobase[bot] aad64cf39a chore: release 2026-10-09.1 [skip ci]
current app-template-default version: 1.0.0-beta.57
@nocobase/app-plugin-scheduler@1.0.0-beta.14 @nocobase/db-sqlite@0.1.0-beta.4 @nocobase/app-plugin-authz-default-access@1.0.0-beta.10 @nocobase/app-plugin-authz-restriction-rules@1.0.0-beta.9 @nocobase/app-plugin-authz-sharing-rules@1.0.0-beta.10 @nocobase/app-plugin-cli-example@0.1.0-beta.4 @nocobase/app-plugin-database-example@0.1.0-beta.7 @nocobase/app-plugin-database-explorer@1.0.0-beta.11 @nocobase/app-plugin-departments-example@1.0.0-beta.5 @nocobase/app-plugin-file-example@1.0.0-beta.16 @nocobase/app-plugin-file@1.0.0-beta.20 @nocobase/app-plugin-hub@2.0.0-beta.1 @nocobase/app-plugin-i18n@1.0.0-beta.13 @nocobase/app-plugin-jobs-example@1.0.0-beta.4 @nocobase/app-plugin-knowledge@0.1.0-beta.0 @nocobase/app-plugin-lifecycle-example@0.1.0-beta.0 @nocobase/app-plugin-mail-example@1.0.0-beta.2 @nocobase/app-plugin-notification-example@1.0.0-beta.5 @nocobase/app-plugin-notification-in-app@1.0.0-beta.22 @nocobase/app-plugin-notification@1.0.0-beta.24 @nocobase/app-plugin-office-flows-example@0.1.0-beta.0 @nocobase/app-plugin-projects@0.1.0-beta.1 @nocobase/app-plugin-queue-example@1.0.0-beta.10 @nocobase/app-plugin-realtime-example@0.1.0-beta.7 @nocobase/app-plugin-registry-example@0.0.2-beta.7 @nocobase/app-plugin-releases@0.1.0-beta.0 @nocobase/app-plugin-repository-example@1.0.0-beta.19 @nocobase/app-plugin-routes-example@1.0.0-beta.18 @nocobase/app-host@0.1.0-beta.14 @nocobase/app-plugin-service-provider-example@1.0.0-beta.7 @nocobase/app-plugin-skills-example@1.0.0-beta.6 @nocobase/app-plugin-template-print-example@1.0.0-beta.3 @nocobase/app-plugin-authentication@2.0.0-beta.2 @nocobase/app-plugin-users@2.0.0-beta.1 @nocobase/app-plugin-workflow@2.0.0-beta.1 @nocobase/app-server@2.0.0-beta.1 @nocobase/app-plugin-authorization-example@1.0.0-beta.13 @nocobase/app-template-default@1.0.0-beta.57 @nocobase/app-template-examples@1.0.0-beta.39 @nocobase/app-template-hub@1.0.0-beta.47 @nocobase/app-testing@0.1.0-beta.1 @nocobase/app-host-docker@0.1.0-beta.0 @nocobase/authorization@1.0.0-beta.12 @nocobase/app-plugin-authorization@1.0.0-beta.25 @nocobase/ai-employee@0.2.0-beta.8 @nocobase/app-cli@1.0.0-beta.14 @nocobase/app-client@2.0.0-beta.2 @nocobase/db-dameng@0.1.0-beta.3 @nocobase/db-kingbase@0.1.0-beta.3 @nocobase/db-mssql@0.1.0-beta.3 @nocobase/db-mysql@0.1.0-beta.4 @nocobase/db-oceanbase@0.1.0-beta.3 @nocobase/db-oracle@0.1.0-beta.3 @nocobase/db-postgres@0.1.0-beta.3 @nocobase/app-plugin-api-keys@1.0.0-beta.13 @nocobase/db-testing@0.1.0-beta.0 @nocobase/db-testkit@0.1.0-beta.2 @nocobase/app-plugin-ai-employee@3.0.0-beta.1 @nocobase/app-plugin-ai-employee-example@0.1.0-beta.1 @nocobase/app-plugin-agents@0.1.0-beta.1 @nocobase/hub-cli@1.0.0-beta.1 @nocobase/lifecycle@0.1.0-beta.0 @nocobase/db@1.0.0-beta.18 @nocobase/api-client@1.0.0-beta.3 @nocobase/logging@0.1.0-beta.6 @nocobase/markdown-mermaid@0.1.0-beta.0 @nocobase/queue@0.1.0-beta.8 @nocobase/repository-input@0.1.0-beta.2 @nocobase/secrets@0.1.0-beta.0 @nocobase/service-provider@0.0.2-beta.1 @nocobase/session@0.1.0-beta.2 @nocobase/snowflake@1.0.0-beta.3 @nocobase/app-installer@0.1.0-beta.3 @nocobase/drive@0.1.0-beta.4 @nocobase/dev-config@0.1.0-beta.19 @nocobase/i18n@1.0.0-beta.5 @nocobase/create-plugin@0.1.0-beta.17 @nocobase/app-skills@0.1.0-beta.25 @nocobase/create-app@0.1.0-beta.29 @nocobase/app-cli-client@0.1.0-beta.0 @nocobase/app-websocket@0.0.1 @nocobase/config@0.1.0-beta.2 @nocobase/cli-envelope@0.1.0-beta.0 @nocobase/caching@0.1.0-beta.2 @nocobase/agent-protocol@0.1.0-beta.1 @nocobase/jobs@0.1.0-beta.2 release-beta/2026-10-09.1 @nocobase/realtime@0.0.2-beta.0 @nocobase/agent-runner@0.1.0-beta.1 @nocobase/app-plugin-mail@1.0.0-beta.8 @nocobase/app-plugin-template-print@0.0.2-beta.0 @nocobase/app-plugin-notification-providers@0.2.0-beta.10
2026-10-09 08:10:58 +00:00
PiEgg a695d1987f chore(v3): use public npm and unify workflow naming (#10588) 2026-10-09 03:33:32 -04:00
PiEgg 563f1d704a chore(ci): prepare v3 branches in the main repository 2026-10-09 02:22:31 -04:00
Junyi 88bc9ebbfe feat(ui-library): add the approval-ui block (#586)
* feat(ui-library): add the approval-ui block

Presentational components for an approval process: progress, timeline,
route preview, parallel branches, receipts and an action bar with forms.
They take data already shaped and translated for display and depend on
no plugin. Includes a preview demo, its registry example and tests.

* docs(app-skills): list the approval-ui block in the UI Library catalog
2026-10-09 13:56:47 +08:00
Junyi b9f1157677 refactor(lifecycle): let entry hooks queue work to run after every entry hook (#585) 2026-10-09 13:49:17 +08:00
c7c14b2742 PM-76: Test registry imports in app and plugin contexts (#572)
* test(registry): cover app and plugin import resolution

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* fix(registry): use package-local subpath imports

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

---------

Co-authored-by: 张中合 <zhonghe.zeke@gmail.com>
Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>
Co-authored-by: Zeke Zhang <38434641+zhangzhonghe@users.noreply.github.com>
2026-10-09 01:19:53 -04:00
Zeke Zhang bde3b877e0 PM-75: Prepare client plugins for shadcn installation (#582) 2026-10-09 01:11:22 -04:00
YANG QIAandProject lead b8df35c1ad feat(agents): limit runner concurrency per coding tool (#575)
* feat(agents): limit runs per coding tool on a runner

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* feat(agent-runner): limit runs per coding tool with --slots

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* feat(agents): edit and show limits per coding tool on the runtimes page

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* chore: format and add the changeset for limits per coding tool

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* fix(agents): make the fields for limits per coding tool optional in shared types

* fix(agents): align queue component with per-tool wait reason

* feat(agents): one tools table per runtime, saved with its settings

---------

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>
2026-10-09 11:42:00 +08:00
dc91aab7fd PM-74: Use package-local subpath imports in registry sources (#576)
* fix(registry): use package-local subpath imports

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* docs(registry): preserve package imports in plugin guidance

* fix(registry): validate installed components in packed plugins

* test(create-plugin): isolate offline dependency metadata

---------

Co-authored-by: 张中合 <zhonghe.zeke@gmail.com>
Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>
2026-10-08 23:17:41 -04:00
YANG QIAandProject lead 476f98882d PM-43: Send custom request headers and a per-conversation session id to model services (#568)
* feat(app-plugin-agents): send custom request headers and a per-conversation session id to model services

A model service can carry request headers of its own (a value may be secret: sealed like the API key and never answered) and name a session header, such as OpenCode Go's x-opencode-session, under which every model call of a conversation sends one stable id. Every request to a provider names the plugin first in its user agent.

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* fix(app-plugin-agents): send OpenCode's session id without a service setting

A model service no longer names a session header. A call to an OpenCode base URL (Zen or Go) carries x-opencode-session by itself, with one session id per conversation and a new one for each call outside any; the id hashes the conversation's subject and thread. The service form drops the session-header field.

* refactor(app-plugin-agents): keep only the OpenCode session header

Plain services no longer send request headers of their own: the headers and headersEncrypted columns, the service API's headers field, the form's header table and the sealing they needed are removed. A call to an OpenCode base URL (Zen or Go) carries x-opencode-session automatically, with one session id per conversation and a new one for each call outside any, and every request names the plugin first in its user agent.

---------

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>
2026-10-08 22:21:28 -04:00
PiEgg 1181a6acef chore(ci): remove Hub image publishing and automatic Pro follow-ups (#580) 2026-10-08 22:02:36 -04:00
chenos 71dbc34542 feat(lifecycle): add record lifecycles with ticket, expense and office flow examples (#519)
Add record lifecycle definitions, transactional transitions, durable effects, recovery, jobs integration, and React bindings. Include ticket, expense, and office flow examples in the Examples application, with concurrency and database compatibility fixes.
2026-10-08 20:55:03 -04:00
chenos e01f33c0d5 Merge pull request #579: move Mail plugins to OSS
Move Mail and Mail Example into OSS, preserve their release and migration history, and load the offline demo only in the Examples template.
2026-10-09 07:12:14 +08:00
chenos 52fb620416 Merge pull request #578: fix(db-mssql): preserve connection ownership of queued requests
Keep MSSQL request queues scoped to their physical connection and preserve FIFO execution during concurrent transactions.
2026-10-09 06:57:18 +08:00
chenos 860ef32830 refactor: move Mail plugins into OSS examples 2026-10-08 18:45:24 -04:00
chenos ac30c51786 fix(db-mssql): keep queued requests on their transaction connection 2026-10-08 18:19:26 -04:00
chenos 8a05e6658a feat(create-plugin): group generated tests by source directory and record the test layout (#551)
Group generated plugin tests by source directory, provide shared Node test configuration, and document the layout. Include TSX tests in Node projects with a regression test for test discovery.
2026-10-08 18:14:44 -04:00
YANG QIAandProject lead 10a17599f1 PM-34: fix(markdown): end bare URLs at CJK text and full-width punctuation (#566)
* fix(markdown): end bare URLs at CJK text and full-width punctuation

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

* chore(app-skills): regenerate the UI Library catalog for markdown-view

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>

---------

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>
2026-10-09 01:04:55 +08:00
YANG QIAandProject lead 220700e1e2 PM-54: fix(app-plugin-agents): size the usage chart's Y axis to its tick labels (#571)
The daily trend chart fixed its Y axis at 56px, which fits token counts but clips cost ticks such as US$20.00 at the chart's left edge. Let recharts measure the formatted labels instead.

Co-authored-by: Project lead <agent+studio-project-lead@studio.noreply>
2026-10-08 22:08:20 +08:00
PiEgg bb8484b6d4 feat(client): support CDN asset URLs in application builds (#565) 2026-10-08 05:19:20 -04:00
nocobase[bot] 62a60342d3 chore: merge release 2026-10-08.1 into develop [skip ci]
current app-template-default version: 1.0.0-beta.56
2026-10-08 05:02:54 +00:00
nocobase[bot] f96fad6a32 chore: release 2026-10-08.1 [skip ci]
current app-template-default version: 1.0.0-beta.56
2026-10-08 04:33:57 +00:00
YANG QIA 32d8faadd8 fix(app-plugin-releases): match nothing without a NUL placeholder id (#562) 2026-10-08 12:32:37 +08:00
YANG QIA 6162033060 fix(tests): open popups after their triggers are wired (#561)
* fix(projects): keep an invitation's row menu open when the list renders again

The columns depended on the whole useMutation result, a new object each render, so every cell remounted.

* test: open popups the way a user does

A Base UI trigger is wired to its popup only once React runs the passive effects of the render that mounted it, so a bare fireEvent.click right after the trigger appears is dropped under load. Open popups with userEvent, fix the timing races this exposed, and cancel pending replies when the UI Library chat demo resets.

* chore: add a changeset for the new test dependency
2026-10-08 12:31:45 +08:00
YANG QIA 699315819a fix(db): drop an enum field again (#563) 2026-10-08 11:47:05 +08:00
YANG QIA ec4a25d5be fix(app-plugin-projects): match nothing for an empty id list without a NUL placeholder (#559) 2026-10-08 11:00:05 +08:00
YANG QIA 3883eec0d0 fix(app-cli): keep the application's displayName in dist/package.json (#560) 2026-10-08 10:14:31 +08:00
YANG QIA a6796d9a5f fix(db): drop only the columns a dropped relation field owns (#558)
A hasMany has no column, so dropping it issued DROP COLUMN for a column that never existed, which PostgreSQL rejects.
2026-10-08 10:01:44 +08:00
YANG QIA ee4da29923 fix(app-plugin-releases): keep row menus open when a list renders again (#557)
The DataTable calls a column's cell instead of mounting it as a component, so inline columns no longer remount every cell and close an open row menu.
2026-10-08 09:02:41 +08:00
YANG QIA ff1d976694 chore(scripts): report the CLI commands in the OpenAPI inspection (#556) 2026-10-08 07:38:29 +08:00
YANG QIA 68d4febbcc feat(plugins): add the agents, projects, knowledge and releases plugins (#554)
* Add the agents, projects, knowledge and releases plugins

Four plugins for agent-run applications, the UI Library's agents and projects items, and the generated UI Library catalog of the application Skill with its check.

* Wait on the sent attachment's link as it renders last in the chat test

* Keep the demo chat's reply timers off window, so they outlive a test's environment quietly
2026-10-08 07:10:52 +08:00
YANG QIA 9e481477a1 fix(dev-config): wait longer in component tests so they stop failing at random on CI (#555)
The React preset waits 5s instead of 1s, and the templates' theme tests wait for the popover's options.
2026-10-08 05:35:23 +08:00
YANG QIA bc1e83ffac feat(plugins): update the plugins, templates and UI Library for the new runtime (#553)
* Update the plugins, templates and UI Library for the new runtime

Device authorization, scoped API keys, service accounts, user invitations and preferences, secrets-backed credentials, the inbox and the cn package across the existing plugins, examples and the three templates, with the UI Library's auth, inbox, authorization and component items.

* Declare the UI Library site's favicon

* Use the NocoBase favicon on the UI Library site

* Fix generated-app shell tests and the Hub's user deletion test

Inline the authentication client in the templates' Vitest config so its guards share the test's react-router, and update the Hub test to the users plugin's new copy and spinner label.
2026-10-08 01:10:33 +08:00
YANG QIA 37c8d20aa6 feat(app): add the runtime, CLI client and agent runner for agent-run applications (#552)
Encrypted secrets, a command manifest derived from the API document, environment-variable manifests, sample data and on-demand Apps in the runtime, plus the new agent protocol, application CLI client, agent runner and Docker App Host packages.
2026-10-07 23:54:20 +08:00
Drol a5e19f7854 feat(examples): add an AI employee tasks example and a global AI employee entry (#550)
* fix(app-plugin-ai-employee): translate the nocobase-ai Registry item in the plugin namespace

The Registry item translated through its own locale files and a useAITranslate()
hook that picked a language by prefix and fell back to the English default, so a
key it never defined showed English in every language without anything noticing.
It now calls useTranslation('@nocobase/app-plugin-ai-employee') like the file
plugin's Registry item and the plugin's own pages, and its copy moves into the
plugin's client/locales, which the registered plugin loads.

Four keys the item used without defining them get English and Chinese text, and
a test fails when a key the Registry passes to t() is missing from either locale
file or a file translates outside the plugin namespace.

* feat(examples): add an AI employee tasks example and a global AI employee entry

@nocobase/app-plugin-ai-employee-example registers the AI employee iris and the
read-only tool example-ticket-history through AIResourceRegistrar, declares the
/ai-employee-example route with a fallback page, and publishes a tasks-page
Registry item that replaces it: support tickets whose AIEmployeeShortcut offers
an auto-sent analysis and a reply left in the composer, with the selected ticket
as work context, and a button that starts a queue triage through the global chat
controller.

The examples template installs the nocobase-ai item, wraps its signed-in layout
in a global AI employee entry (a floating trigger that opens the shared
conversation as a side panel and expands into a dialog), registers the example
plugin, installs its tasks page and links it from the homepage.

* test(templates): let the Examples layout carry its AI employee entry

The framework alignment check compares the Examples layout with Default byte for
byte, and the global AI employee entry wraps the signed-in shell. Like the
notification button in the header, it is an Examples-owned demonstration: the
check now removes exactly that wrapper, its import and its marker comment,
re-indents what it wraps, and still requires the shell itself to match Default.
2026-10-07 11:17:11 -04:00
Drol 1197085174 feat(app-plugin-ai-employee): release unused conversation checkpoints on a schedule (#549)
* feat(app-plugin-ai-employee): release unused conversation checkpoints on a schedule

A recurring job on the application's jobs service releases the agent
checkpoints of conversations nobody has used for a week, every day at
03:00 UTC by default. Releasing a conversation sets its thread to 0 and
deletes the checkpoints of every thread it has had, in one transaction per
batch, only while the conversation is still unused. A conversation whose
latest message asks for a tool call is never released.

The next run on a released conversation replays its latest stored messages
onto a fresh thread. This applies only to conversations kept in the
plugin's own tables, never to a resume or a tool decision, and never to a
thread-0 conversation that still has a checkpoint there or has no messages,
so existing runs behave as before.

The schedule is configured under ai.checkpointCleanup and validated by
config check.

* feat(app-plugin-ai-employee): default a conversation's thread to 1

A conversation starts on thread 1 when AIConversationsManager creates it,
but the aiConversations.thread column defaulted to 0, so a row inserted
without a thread looked like a conversation whose checkpoints the cleanup
had released. A new migration sets the default to 1.

Thread 0 now always means a released conversation, so the agent decides
whether to replay stored messages from the thread number alone, without
reading the checkpoint store.

* fix(app-plugin-ai-employee): read each cleanup batch's latest messages in two queries

The checkpoint cleaner looked up the latest message of every candidate
conversation with its own query. It now finds each conversation's latest
message id with one groupBy over the batch and reads those messages with one
more query.

The aggregate goes through the Repository rather than the query builder,
because it reads a bigint result back exactly on every dialect, and a
message id is a snowflake beyond the integers a JavaScript number holds.
2026-10-07 10:56:49 -04:00
chenos 6e30789a3e refactor(templates): move Playwright tests to tests/playwright/ and drop the local AI e2e test (#546)
* refactor(templates): move Playwright tests to tests/playwright/ and drop the local AI e2e test

Keep every test under tests/: Playwright's testDir is tests/playwright/,
Vitest excludes that directory, and tsconfig.node.json typechecks it. The
directory ships with the template like the rest of tests/. The optional
local AI server test is removed; test:e2e still passes with no tests.
The application Skills describe the new location, and the upgrade Skill
says how an existing application moves its e2e/ files.

* refactor(app-template-hub): exclude tests/playwright/ from Vitest like the other templates

The template alignment test requires the three templates to share one
vitest.config.ts. Hub has no Playwright, so the exclusion changes nothing
there today, and a Hub application that adds Playwright already has it.
2026-10-07 22:15:42 +08:00
Drol d631536271 feat(app-plugin-ai-employee): grant AI settings per page under System management, and drop unused management routes (#548)
Replace the single `page:ai.settings` grant with seven settings items under
System management → AI, one per settings page: `ai.employees`,
`ai.llmServices` and `ai.mcpServers` with `read` and `manage`, and
`ai.skills`, `ai.tools`, `ai.usage` and `ai.conversations` with `read`.
Every management route names the permissions it accepts, pages open with
`read` and turn their controls off without `manage`, and previewing another
user's AI file requires `read` on `ai.conversations`.

A migration gives every item and action to each Permission Set that held the
page grant. A grant of every page no longer opens the AI settings.

Remove the management routes no settings page called: employee templates,
create and delete, skill and tool writes, single LLM service and MCP server
reads, and both MCP connection tests. The package moves to the 3.0.0
prerelease line.
2026-10-07 09:53:24 -04:00
gchust e538d12578 fix(file): time out Office Open XML previews that never finish loading (#494)
* fix(file): time out Office Open XML previews that never finish loading

* fix(file): extend the Office Open XML preview timeout to 3 minutes

Let the first failure settle the preview inside reportViewerError, so it
no longer reads the timeout handle before it is declared and the timeout
callback no longer depends on statement order.
2026-10-07 20:14:03 +08:00
gchust 3f1b78f639 feat(app-plugin-file): export FILE_COLUMNS from the server entry (#493)
* feat(app-plugin-file): export FILE_COLUMNS from the server entry

* docs(app-plugin-file): translate the File Repository guide into English
2026-10-07 19:50:47 +08:00
Drol 1071f7d5c3 fix(app-plugin-ai-employee): answer the parallel conversation limit correctly and count runs from when they start (#547)
* fix(app-plugin-ai-employee): save a refused message with its stored columns only

A send refused at the parallel conversation limit saved the user message by
spreading it into the insert, so the key the chat sends with it reached
ai_messages, which has no such column, and the request failed with a SQL
error instead of the limit message.

* fix(app-plugin-ai-employee): count a run towards the limit from when it started

The parallel run limit counts conversations whose updatedAt falls within the
last ten minutes, but an update never set updatedAt, so it stayed at the
conversation's creation time: a run in a conversation older than ten minutes
was never counted. Starting a run now sets updatedAt.
2026-10-06 23:17:16 -04:00
Junyi 3898a89017 feat(workflow): add durable wait nodes and quotation review (#531)
* feat(workflow): add durable wait instruction

* feat(workflow): persist checkpoint recovery and quotation wait review

* fix(examples): retain empty state primitive for workflow review

* fix(examples): restore decision focus after submission settles
2026-10-07 09:39:25 +08:00
chenos 8a6a296160 fix(db-mysql): read literal column defaults back as values, and cover MariaDB (#545)
* fix(db-mysql): read a string column's literal default back as its value

MySQL and OceanBase report a literal default in information_schema as the bare text, draft rather than 'draft'. The shared literal parser took it for an expression, so a character, enum or temporal column's default had no value once resolved, and a defaulted NOT NULL enum was listed as required in the API document's create schema on MySQL. Both inspectors now quote the bare value of those types, leaving numbers and CURRENT_TIMESTAMP as they are, and a portable contract checks on every dialect that a string and an enum field's default resolves to its value.

* fix(db-mysql): keep MariaDB and expression defaults out of the literal quoting

MariaDB 10.2.7 and later report column_default in the form it was declared,
'draft' for a literal and the bare word NULL for a nullable column without a
default, so quoting it again read 'draft' with its quotes and gave every such
column a "NULL" default. The inspector now reads version() with the columns and
passes a MariaDB default through, mapping its bare NULL to no default.

OceanBase reports default (uuid()) exactly as default 'uuid()', so a character
column's default is now told apart by reading the table's DDL, rather than
quoting an expression into a value the Repository would write.

A temporal default is quoted only when it starts like a date or a time, which
keeps curdate(), now() and CURRENT_TIMESTAMP expressions on every server, and
the temporal type list is taken from mysqlTypes instead of a second copy.

* fix(db-mysql): resolve the backslash escapes in a MariaDB default

MariaDB reports a string default escaped as MySQL writes literals, so
'back\\slash' and a text column's 'it\'s here' read back with the escape left
in them. Their literal now goes through the same unescaping as a MySQL
expression default before the shared parser reads it.

* fix(db-mysql): run the JSON filters on MariaDB and test the dialect against it

MariaDB stores JSON as text and has no cast(… as json), so every JSON equality
and membership filter failed to parse there. Both are now compared through
JSON_OVERLAPS, which MySQL and MariaDB evaluate alike: equality wraps each side
in a one-element array, so object keys compare in any order, array elements in
order, and 1 matches neither "1" nor true.

test:integration now runs the shared suite against MariaDB 10.11 after MySQL,
from a second service in docker-compose.yml, so CI covers both servers the
dialect serves. The isolation test reads tx_isolation where MariaDB before 11.1
has no transaction_isolation.

* fix(db-mysql): compare JSON equality both ways and keep OceanBase view expressions out of defaults

MariaDB compares two arrays inside JSON_OVERLAPS only as far as the second
one goes, so `[1, 2]` equalled `[1]` and every array equalled `[]`. Equality
now checks the overlap in both directions, which both servers evaluate
alike, and the JSON filter contract covers empty and partial containers.
The JSON filters need MySQL 8.0.17, as membership already did; the README
and changeset say so.

OceanBase reports `default (uuid())` and `default 'uuid()'` alike on a view
too, and a view's DDL declares no defaults, so a character default on a
view that reads like a function call is now read as an expression.

The MySQL integration runner no longer starts MariaDB after an interrupted
MySQL run, or while the MySQL database is kept.
2026-10-06 23:33:13 +08:00
chenos b0a5954430 fix(app-plugin-notification-example): answer a malformed task id with 403 on PostgreSQL (#536)
* fix: answer a malformed task id with 403 on PostgreSQL, and keep the articles test portable to OceanBase

The notification example compared any path id with its uuid column, which PostgreSQL rejects with a 500 for a value like 'missing'; an id that is not a UUID now names no task. The examples template's articles migration test gives content in its raw insert, because OceanBase keeps no TEXT default in the table.

* fix(app-plugin-notification-example): match a task id in any case, and cover a malformed id on update

Validate the id with z.guid() instead of a hand-written pattern and lowercase it
before the query, so an uppercase id names the same task on SQLite and MySQL as
on dialects that compare uuid natively. Name Kingbase and MSSQL alongside
PostgreSQL as the dialects that reject a malformed uuid, and test PATCH with a
malformed id and GET with an uppercase one.
2026-10-06 19:13:33 +08:00
chenos e23c66d4ad feat(create-plugin): prepare generated client plugins for page tests, and point page tests at app-testing/client (#535)
* docs: point page tests at app-testing/client, and test the Skill's page example with real translations

AGENTS.md and the AGENTS.md create-plugin generates name @nocobase/app-testing/client for page tests. The plugin-development Skill's page test example renders with the strict runtime from @nocobase/i18n/testing and the plugin's locale file instead of a mocked t, which let a missing or misspelt key pass. The example keeps its mocked services until @nocobase/app-testing is published.

* feat(create-plugin): prepare generated client plugins for page tests, and render the Skill's page test with renderWithApp

The Skill's settings page test renders inside a client application with
renderWithApp(), registers the real AuthorizationClient through services and
answers its permissions request with answerApi(), and shows the locale keys
the page needs, so it runs as written. A plugin create-plugin generates with
client code gets app-testing and the jsdom test packages, and a vitest.config.ts
that runs tests/client/ under jsdom; its AGENTS.md describes page tests in a
section of their own, including the plugins option. AGENTS.md no longer calls
renderWithApp()'s toaster the real one.
2026-10-06 19:12:02 +08:00
gchustandgchust 0151805e23 fix(app-plugin-file): embed PDF previews as application/pdf and cover PDF in the Skill checklist (#460)
* fix(app-plugin-file): embed PDF previews as application/pdf and cover PDF in the Skill checklist

Refs TestManage problem #234.

* fix(app-plugin-file-example): embed PDF previews as application/pdf

Apply the Registry preview's PDF rule to the file example's preview
dialog: refuse a response carrying an active markup type and retype the
blob to application/pdf before embedding it. Clarify that retyping is the
safeguard, assert the frame source in the Registry test, and drop the
canvas-renderer history from the file Skill.

* refactor(app-plugin-file): share the PDF preview checks and tidy their tests

Use isActiveMarkupMimeType in the file example's previewKind instead of a
second inline list, name the Registry PDF preview error once, make the
example's discarded refusal message describe what happened, and type the
createObjectURL mock instead of asserting its argument.

* docs(app-plugin-file): separate browser and session failures in the PDF check

A login redirect during a PDF preview points at the session, not the
browser. Drop the example's unread refusal message and state the fixed
case precisely in the changeset.

* docs(app-plugin-file): state the PDF preview risk as external content URLs

* refactor(app-plugin-file): name the refused PDF response and tidy the MIME helpers

Report an HTML or XML response to the PDF preview with its own message so it
is distinguishable from a failed request, share MIME normalization in
file-preview.ts, move the example's active markup check into lib/mime.ts and
shorten the Skill's PDF guidance.

* docs(app-plugin-file): scope the PDF browser-limitation note to headless browsers

---------

Co-authored-by: gchust <5254737+gchust@users.noreply.github.com>
2026-10-06 10:29:56 +08:00
gchust 8885ce42ba fix(file): fall back to download when a previewed image fails to load (#492)
* fix(file): fall back to download when a previewed image fails to load

* fix(file): show the type icon in the image fallback instead of reloading the failed image

* fix(file): ship the image preview fallback in the Default template

Refresh the Default template's copy of the File Registry, which the
default-file-registry check requires, and add the template to the
changeset. Give ImagePreview a required url so a missing URL can no
longer match the initial failed-URL state, and replace the empty-URL
sentinel in DownloadFallback with an explicit FileThumbnail iconOnly prop.
2026-10-05 21:22:28 +08:00
gchust f037763d11 chore: improve agent annotation hints (#334) 2026-10-05 20:01:24 +08:00
PiEgg be4a800755 test: wait for the shell to render the toggled navigation in the templates' shell test (#540)
The shell re-renders from the shared sidebar preference only once its subscription effect has run, so the test now waits for the collapsed and expanded states instead of asserting right after the click. Applied to all three templates.
2026-10-05 12:59:15 +08:00
nocobase[bot] d74c783ba7 chore: merge release 2026-10-05.2 into develop [skip ci]
current app-template-default version: 1.0.0-beta.55
2026-10-05 03:28:55 +00:00