Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09a7af478f | ||
|
|
60b19ea12b | ||
|
|
8f6a50dcdc | ||
|
|
8be3701cf7 | ||
|
|
e9ec16767e | ||
|
|
7092edc832 | ||
|
|
315d6ee72d | ||
|
|
6f5e7b368b | ||
|
|
3cdbaaa49a | ||
|
|
a44f475484 | ||
|
|
c2285d2f5a | ||
|
|
22a011c9b0 | ||
|
|
52f49a81c4 | ||
|
|
e2eca70847 | ||
|
|
be9cb446e7 | ||
|
|
192e748b56 | ||
|
|
bfa1ba2678 | ||
|
|
1947e0e57e | ||
|
|
987a23a0eb | ||
|
|
d86164e753 | ||
|
|
131da801ca | ||
|
|
466aad97da | ||
|
|
0c695b2aea | ||
|
|
28800968c1 | ||
|
|
b0c18f73e8 | ||
|
|
bf4234c45d | ||
|
|
54ec0bd660 | ||
|
|
b70fe5495c | ||
|
|
7af066e14c | ||
|
|
3e89f5a708 | ||
|
|
64864fe299 | ||
|
|
6ae4ac704c | ||
|
|
6ee6ed38a1 | ||
|
|
057c30875b | ||
|
|
8e542da2e9 | ||
|
|
ce022acf1d | ||
|
|
34d8267528 | ||
|
|
7fe5bc2176 | ||
|
|
1a60c21ed9 | ||
|
|
afc0fa3d32 | ||
|
|
31b3d8d6a3 | ||
|
|
15ac53f395 | ||
|
|
4f51f6e0b2 | ||
|
|
c7990360dc | ||
|
|
25a52f084b | ||
|
|
6f272133c7 | ||
|
|
4003050400 | ||
|
|
d75d546040 | ||
|
|
1a71ad2e02 | ||
|
|
78203c8985 | ||
|
|
9789badfb8 | ||
|
|
2dd60acb79 | ||
|
|
893778f260 | ||
|
|
4522facdf0 | ||
|
|
9a9084d817 | ||
|
|
154eb34c45 | ||
|
|
c2cff24650 | ||
|
|
744cee5b7f | ||
|
|
dcc41d255f | ||
|
|
313df7b4af | ||
|
|
321320be5e | ||
|
|
9a69c6b85b | ||
|
|
a0403dfc9f | ||
|
|
fc5b811f11 | ||
|
|
44a5dd764f | ||
|
|
30e0b14ddf | ||
|
|
cf65e3b09b | ||
|
|
9d2c6cf523 | ||
|
|
280693014a | ||
|
|
5bd572d2ac | ||
|
|
fac22c1cf6 | ||
|
|
7689d03b89 | ||
|
|
e14dae3f7b | ||
|
|
54f25639d3 | ||
|
|
6d2da5843f | ||
|
|
c495d84328 | ||
|
|
b455ec4d37 | ||
|
|
f21960b4d6 | ||
|
|
98a6bcc601 | ||
|
|
da8a8dd958 | ||
|
|
a4c23643eb | ||
|
|
886134ceb5 | ||
|
|
3f063a7014 | ||
|
|
1976b06c01 | ||
|
|
25623e2928 | ||
|
|
556937b6de | ||
|
|
8a7a138f4e | ||
|
|
252fa26d6f | ||
|
|
893ac7943e | ||
|
|
c7623e7c68 | ||
|
|
a3a781ae36 | ||
|
|
6f41176e43 | ||
|
|
1a9661dfc1 | ||
|
|
e0deaf1780 | ||
|
|
94a6f01d75 | ||
|
|
8bbd65fbb7 | ||
|
|
c16f6c57b9 | ||
|
|
7c11c7bb5e | ||
|
|
c6f201a923 | ||
|
|
17c7b30ef6 | ||
|
|
876ea9ced5 | ||
|
|
e45d33852a | ||
|
|
b20c13b78f |
@@ -1,2 +1,2 @@
|
||||
https://github.com/heroku/heroku-buildpack-nodejs.git#v371
|
||||
https://github.com/heroku/heroku-buildpack-nodejs.git#v365
|
||||
https://github.com/pkgr/heroku-buildpack-ruby.git#v361-1
|
||||
@@ -78,8 +78,8 @@ make a review look thorough is not.
|
||||
|
||||
Also out of scope in every review:
|
||||
|
||||
- Style and formatting a linter or formatter owns (RuboCop, ESLint, oxlint, Oxfmt, Stylelint),
|
||||
unless it actively obscures meaning or breaks a documented standard.
|
||||
- Style and formatting a linter owns (RuboCop, ESLint, Prettier), unless it actively obscures
|
||||
meaning or breaks a documented standard.
|
||||
- Naming preferences not covered by a convention doc.
|
||||
- Speculative future requirements that are not in the issue.
|
||||
- Pre-existing code visible in diff context but untouched by the change.
|
||||
@@ -308,19 +308,6 @@ or translation quality for some users.
|
||||
other `$t(...)` / `i18n.t(...)` calls or the base locale file. If a near-identical string
|
||||
exists, flag the new one as a duplicate and suggest reusing it — every distinct string adds
|
||||
translator workload across all supported languages.
|
||||
- **Danger styling and confirmations** — `danger` and `remove` (which counts as danger) mark the
|
||||
click that cannot be undone, so they stay only on controls that act immediately. Flag a `danger`
|
||||
or `remove` trigger whose handler ends in `waitForConfirmation` / `waitForVariantConfirmation`,
|
||||
or opens a flyout that asks first. What replaces it depends on the kind of trigger: a `danger`
|
||||
button becomes `tertiary` with an icon naming the action (`trash3` for delete and discard,
|
||||
`arrow-counterclockwise` for reset); a menu item carries no variant at all, icon included; a
|
||||
`remove` icon button loses the variant, keeps its icon, and takes the variant UX decides per
|
||||
place (`tertiary` so far), so do not assume one. Flag a confirmation for irrecoverable loss
|
||||
(deleting records, resetting user settings, discarding unsaved changes, clearing filters or
|
||||
recent lists) whose confirm button is not `danger`: the `delete` and `unsaved` variants of
|
||||
`CommonConfirmationDialog` already render one, so only the default `confirm` variant needs
|
||||
`buttonVariant: 'danger'`. A control that asks only in some states (a dirty taskbar tab) follows
|
||||
the state.
|
||||
- Never flag a change to `i18n/*.po` as the fix. Those files are managed externally.
|
||||
|
||||
### Backend — `[backend]`
|
||||
|
||||
@@ -9,7 +9,7 @@ Resolvers are thin wrappers. Business logic lives in `app/services/service/`:
|
||||
|
||||
```ruby
|
||||
def resolve(...)
|
||||
Service::SomeAction.execute(...)
|
||||
Service::SomeAction.new(...).execute
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
@@ -64,13 +64,12 @@ Do not "fix" these without a decision:
|
||||
inactive knowledge base that way — the policy for anyone with effective access
|
||||
to the record (a reader included), the scope for the `knowledge_base.editor`
|
||||
permission.
|
||||
- `Gql::Concerns::SearchesKnowledgeBaseAnswers` answers with an **empty result**
|
||||
instead of raising when no knowledge base is active. It is reached from a
|
||||
document that asks for more than the knowledge base — the desktop quicksearch
|
||||
requests every searchable entity in one query — and the search field is
|
||||
`null: false`, so a raise would null the root and take the ticket, user and
|
||||
organization groups down with it on every instance that has no knowledge base.
|
||||
The knowledge base's own queries, `Gql::Queries::KnowledgeBase::Search`
|
||||
included, do raise: they are asked for on their own.
|
||||
- `Gql::Concerns::SearchesKnowledgeBaseAnswers` and
|
||||
`Gql::Queries::KnowledgeBase::Search` answer with an **empty result** instead of
|
||||
raising when no knowledge base is active. Both are reached from a document that
|
||||
asks for more than the knowledge base — the desktop quicksearch requests every
|
||||
searchable entity in one query — and the search field is `null: false`, so a
|
||||
raise would null the root and take the ticket, user and organization groups down
|
||||
with it on every instance that has no knowledge base.
|
||||
|
||||
Each of these carries the reasoning in a code comment; keep the two in sync.
|
||||
|
||||
@@ -36,8 +36,8 @@ is not enough.
|
||||
|
||||
### Skeleton
|
||||
|
||||
Minimal concern following `app/models/mention/assets.rb` (belongs_to user +
|
||||
polymorphic relation):
|
||||
Minimal concern following `app/models/mention/assets.rb` and
|
||||
`app/models/audit_log/assets.rb` (belongs_to user + polymorphic relation):
|
||||
|
||||
```ruby
|
||||
class MyModel
|
||||
@@ -67,6 +67,7 @@ end
|
||||
### Reference examples
|
||||
|
||||
- `app/models/mention/assets.rb` — user + polymorphic `mentionable`
|
||||
- `app/models/audit_log/assets.rb` — optional user + polymorphic `auditable`
|
||||
- `app/models/online_notification/assets.rb` — lookup tables + created/updated by
|
||||
- `app/models/group/assets.rb` — attribute filtering and per-user authorization
|
||||
|
||||
|
||||
@@ -170,13 +170,13 @@ existing code.
|
||||
- **UI-6 (proposed)** — Should new UI be required to compose existing design-system components and
|
||||
tokens, with a new primitive treated as a decision rather than a detail?
|
||||
- **UI-7 (proposed)** — Should a resumable view offer its own taskbar-behaviour-on-update setting,
|
||||
stored independently per view? Seen once, in the story that introduced editing knowledge base
|
||||
answers; unclear whether it generalises.
|
||||
stored independently per view? Seen once, in
|
||||
`zammad/coordination-desktop-view#785`; unclear whether it generalises.
|
||||
- **When is a new setting justified?** `DEFAULT-2` states the preference but not the test. There are
|
||||
~300 settings today, so a usable criterion would have real leverage.
|
||||
- **Are bulk or batch variants expected** for single-record actions, or added only on demand?
|
||||
- **Where does deferred or scheduled state belong** in the interface? The same story grew a whole
|
||||
scheduled visibility capability, which suggests there is no settled pattern for it yet.
|
||||
- **Where does deferred or scheduled state belong** in the interface? `#785` grew a whole scheduled
|
||||
visibility capability, which suggests there is no settled pattern for it yet.
|
||||
- **How much of the legacy interface does a new feature have to reach**, and when is parity
|
||||
explicitly not required?
|
||||
- **How custom file overrides and packages are meant to work in a container**, given `DEPLOY-1`.
|
||||
|
||||
@@ -146,7 +146,7 @@ A **layer slice** can never be a story. "Add the service and the mutation" has n
|
||||
and nothing observable — forcing it into story form produces a fake user story, which is worse than
|
||||
a large one. Layer slices are tasks. Split stories along capability and surface seams only.
|
||||
|
||||
### Worked example — editing knowledge base answers
|
||||
### Worked example — `zammad/coordination-desktop-view#785`
|
||||
|
||||
"Edit an answer of the knowledge base", one story, sixteen tasks, one very large merge request.
|
||||
Its criteria classified by the test above:
|
||||
|
||||
@@ -40,19 +40,6 @@ Selenium opens a real, visible browser window.
|
||||
SELENIUM_BROWSER_HEADLESS=1 RAILS_ENV=test VITE_TEST_MODE=1 bundle exec rspec spec/system/path/to/file_spec.rb
|
||||
```
|
||||
|
||||
### Ports of a test run
|
||||
|
||||
The suite serves Capybara on `CAPYBARA_PORT` (default `3001`) and its websocket
|
||||
server on `WS_PORT` (default `6043`) — next to, never on, the ports of the
|
||||
development stack, so a run does not collide with a stack of the same checkout.
|
||||
Set both to run two suites side by side; they still share the `test` database,
|
||||
the Redis keys and the Elasticsearch indices, so those (`DATABASE_URL`,
|
||||
`REDIS_URL`, `ES_INDEX`) need separating as well.
|
||||
|
||||
```bash
|
||||
CAPYBARA_PORT=3101 WS_PORT=6143 bundle exec rspec spec/system/path/to/file_spec.rb
|
||||
```
|
||||
|
||||
### Capybara form helpers (new frontend stack)
|
||||
|
||||
System tests for the Vue frontend use custom helpers to interact
|
||||
|
||||
@@ -40,7 +40,7 @@ finding, what is out of scope, how to classify findings, and how to write them.
|
||||
Apply it rather than your own judgement about what matters, and do not restate it
|
||||
here.
|
||||
|
||||
Three things from it deserve emphasis in this position specifically:
|
||||
Two things from it deserve emphasis in this position specifically:
|
||||
|
||||
- **The flagging threshold.** You may be reviewing work in progress, where scaffolding
|
||||
and half-finished edges are expected. Report what meets the bar and nothing else.
|
||||
|
||||
@@ -39,26 +39,6 @@ The CoffeeScript frontend uses REST controllers.
|
||||
- Never edit translation files (`i18n/*.po`) directly —
|
||||
translations are managed via translations.zammad.org.
|
||||
|
||||
### Code Comments
|
||||
|
||||
Comment only what the code cannot say itself: a non-obvious _why_, a
|
||||
workaround with its reason, a spec/protocol quirk, or a deliberate
|
||||
deviation from a pattern. Otherwise add no comment — clear naming and
|
||||
small methods are preferred over explanation.
|
||||
|
||||
- One or two short lines, in the style of the surrounding file.
|
||||
- Never restate what the next line does, summarise a block, label
|
||||
sections (`# --- setup ---`), or narrate a change (`# new`, `# was …`,
|
||||
`# fixed`).
|
||||
- Keep out reasoning that belongs in the commit message, the issue or
|
||||
the MR description.
|
||||
- Never reference an issue from an internal repository (`coordination-*`) —
|
||||
this repository is publicly mirrored. Reference a public `zammad/zammad`
|
||||
issue, or state the reason without a link.
|
||||
- Never mark a fix for a security vulnerability as such — this repository
|
||||
is publicly mirrored, and the comment points at the vulnerable code in
|
||||
installations that are not updated yet.
|
||||
|
||||
### UI Principles
|
||||
|
||||
- Icon-only buttons need `v-tooltip` supplying the accessible name.
|
||||
@@ -67,13 +47,6 @@ small methods are preferred over explanation.
|
||||
- Translatable strings: use complete, meaningful source strings,
|
||||
sentence case for English source strings, and check for existing
|
||||
near-duplicate strings before adding new ones.
|
||||
- Red marks the point of no return: `danger` and `remove` stay only on
|
||||
controls that act immediately. A trigger that only opens a confirmation
|
||||
dialog or a confirming flyout is not red: a button becomes `tertiary`
|
||||
with an icon naming the action (`trash3` for delete and discard,
|
||||
`arrow-counterclockwise` for reset), a menu item carries no variant, a
|
||||
`remove` icon button keeps its icon and takes the variant UX names per
|
||||
place. The decisive button in the dialog or flyout is `danger`.
|
||||
|
||||
## Essential Commands
|
||||
|
||||
@@ -95,32 +68,6 @@ pnpm generate-graphql-api # Regenerate GraphQL types aft
|
||||
pnpm generate-setting-types # Regenerate Config types after setting changes
|
||||
```
|
||||
|
||||
### Development stack
|
||||
|
||||
A browser-clickable instance for this checkout. Start it via `bin/dev` rather
|
||||
than `forego` directly, and wait for it to answer before using it.
|
||||
|
||||
```bash
|
||||
RAILS_ENV=development bundle exec rake db:create zammad:bootstrap:reset # once per checkout
|
||||
bin/dev # does not exit; run it in the background
|
||||
```
|
||||
|
||||
It serves on `localhost:3000`, with the websocket server on `6042` and Vite on
|
||||
`3036`. Export `ZAMMAD_RAILS_PORT`, `ZAMMAD_WEBSOCKET_PORT` and
|
||||
`VITE_RUBY_PORT` before `bin/dev` to move them — the whole stack has to agree
|
||||
on them, so export, do not set them per process.
|
||||
|
||||
`zammad:bootstrap:reset` migrates, seeds and runs the auto wizard, which creates
|
||||
`admin@example.com` / `test`. Plain `zammad:db:init` skips the wizard and leaves
|
||||
the browser on the getting-started screen. Never run `zammad:bootstrap:init` or
|
||||
`zammad:setup:db_config`: they overwrite `config/database.yml` and prompt on
|
||||
stdin, which hangs a non-interactive session.
|
||||
|
||||
The test suite uses its own ports (`3001` and `6043`) and its own database, so
|
||||
it can run while the stack is up. Several checkouts, however, share the
|
||||
development database and Redis — only one stack per machine unless
|
||||
`DATABASE_URL` and `REDIS_URL` say otherwise.
|
||||
|
||||
## Development Lifecycle
|
||||
|
||||
Issues are tracked on **GitHub**, code is developed on a self-hosted **GitLab**.
|
||||
@@ -131,7 +78,7 @@ Stories are refined and broken down into task issues before this lifecycle
|
||||
starts (`/refine-story` → `/plan-story`). Bugs skip that and enter it directly.
|
||||
|
||||
Lifecycle: Understand → Research → Plan → Branch (`/prepare-issue-branch`) →
|
||||
Implement → Test → Review → Commit → MR (`/create-mr`) → Cherry-pick
|
||||
Implement → Test → Commit → Review → MR (`/create-mr`) → Cherry-pick
|
||||
(`/cherry-pick-to-stable`)
|
||||
|
||||
See `.dev/agent_docs/development_workflow.md` for the full lifecycle and
|
||||
@@ -164,7 +111,7 @@ You MUST read the relevant file(s) below before responding when working on that
|
||||
## CodeGraph
|
||||
|
||||
In repositories indexed by CodeGraph (a `.codegraph/` directory exists at the repo
|
||||
root), reach for it before grep/find or reading files when you need to understand
|
||||
root), reach for it BEFORE grep/find or reading files when you need to understand
|
||||
or locate code:
|
||||
|
||||
- **MCP tool** (when available): `codegraph_explore` answers most code questions
|
||||
@@ -173,9 +120,14 @@ or locate code:
|
||||
in the query to read its current line-numbered source. If it's listed but
|
||||
deferred, load it by name via tool search.
|
||||
- **Shell** (always works): `pnpm exec codegraph explore "<symbol names or question>"`
|
||||
prints the same output using the repository-pinned CodeGraph version.
|
||||
prints the same output — `codegraph` is a local dev dependency, so the bare
|
||||
command is not on `PATH`.
|
||||
|
||||
If there is no `.codegraph/` directory, skip CodeGraph entirely — indexing is the
|
||||
user's decision. If they ask to initialize it, run `pnpm codegraph:init`. Developer
|
||||
setup and removal are documented in
|
||||
`doc/developer_manual/development_environment/codegraph-setup.md`.
|
||||
Setup is per developer: `pnpm codegraph:install` indexes this checkout and registers
|
||||
the server with the agent harnesses it finds (Claude Code, Cursor, Codex CLI,
|
||||
opencode, …). Say yes when it offers to put the CLI on `PATH`: that is how they
|
||||
launch it. `pnpm codegraph:uninstall` reverts it. Nothing lands in a commit —
|
||||
`.codegraph/` and `.mcp.json` are gitignored, and the harness registration lives in
|
||||
each tool's own config outside the repo.
|
||||
|
||||
If there is no `.codegraph/` directory, skip CodeGraph entirely — indexing is the user's decision.
|
||||
|
||||
@@ -20,14 +20,7 @@ export default defineConfig({
|
||||
downloadsFolder: '.dev/cypress/downloads',
|
||||
screenshotsFolder: '.dev/cypress/screenshots',
|
||||
videoCompression: false,
|
||||
// Cypress 16 defaults to `0`, which types faster than the rich text editor can
|
||||
// process input events.
|
||||
keystrokeDelay: 10,
|
||||
// Cypress 16 defaults to `modern`, which relies on `Element.checkVisibility()`
|
||||
// and therefore reports elements moved out of the viewport via `transform` as
|
||||
// visible.
|
||||
visibilityStrategy: 'legacy',
|
||||
expose: {
|
||||
env: {
|
||||
CY_CI: isCYCI,
|
||||
pluginVisualRegressionDiffConfig: {
|
||||
threshold: 0.02,
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@frsource/cypress-plugin-visual-regression-diff": "^4.2.1",
|
||||
"@frsource/cypress-plugin-visual-regression-diff": "^4.1.1",
|
||||
"@testing-library/cypress": "^10.1.3",
|
||||
"cypress": "^16.1.1",
|
||||
"cypress-real-events": "^1.15.1"
|
||||
"cypress": "^15.21.1",
|
||||
"cypress-real-events": "^1.15.0"
|
||||
},
|
||||
"imports": {
|
||||
"#tests/*": "../../app/frontend/tests/*",
|
||||
|
||||
303
.dev/cypress/pnpm-lock.yaml
generated
303
.dev/cypress/pnpm-lock.yaml
generated
@@ -9,17 +9,17 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
'@frsource/cypress-plugin-visual-regression-diff':
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1(cypress@16.1.1)
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.1(cypress@15.21.1)
|
||||
'@testing-library/cypress':
|
||||
specifier: ^10.1.3
|
||||
version: 10.1.3(cypress@16.1.1)
|
||||
version: 10.1.3(cypress@15.21.1)
|
||||
cypress:
|
||||
specifier: ^16.1.1
|
||||
version: 16.1.1
|
||||
specifier: ^15.21.1
|
||||
version: 15.21.1
|
||||
cypress-real-events:
|
||||
specifier: ^1.15.1
|
||||
version: 1.15.1(cypress@16.1.1)
|
||||
specifier: ^1.15.0
|
||||
version: 1.15.0(cypress@15.21.1)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -45,12 +45,12 @@ packages:
|
||||
'@emnapi/runtime@1.11.3':
|
||||
resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
|
||||
|
||||
'@frsource/base64@1.0.237':
|
||||
resolution: {integrity: sha512-X0tSa8rrusTEkYNy7aE+M+sZlsdyjMt8OgxWc6RerYefph3EKIVRTaL0qg8iw53iabvM7mJDK8MNc4W1yTAz2w==}
|
||||
'@frsource/base64@1.0.213':
|
||||
resolution: {integrity: sha512-KaW0AbWO5gLtFJ+C9QZjY25P2dKkOFBtKtuyIj+DEA87moaO4cpovazCE8Zps8JP7cVyuZ+rDxkXlQTt8xli+Q==}
|
||||
|
||||
'@frsource/cypress-plugin-visual-regression-diff@4.2.1':
|
||||
resolution: {integrity: sha512-zu+Lfet2mydw+kkGMQ96gN6w8uejPsonKgmaybAMrS3HVXx4V28D961Q8f7ohs9hGa+v+njPJeGbTZuKpnLCkQ==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
'@frsource/cypress-plugin-visual-regression-diff@4.1.1':
|
||||
resolution: {integrity: sha512-O/RAf8shfs9UcwzPfR0TmrXnuy0UymjPNrbLhXFsls2bHsnWH++LskqXgkMdi9fnTA7E51XKqptUexNKOeEg7g==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
cypress: '>=13.0.0'
|
||||
|
||||
@@ -58,160 +58,160 @@ packages:
|
||||
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==}
|
||||
'@img/sharp-darwin-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-darwin-x64@0.35.4':
|
||||
resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==}
|
||||
'@img/sharp-darwin-x64@0.35.3':
|
||||
resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-freebsd-wasm32@0.35.4':
|
||||
resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==}
|
||||
'@img/sharp-freebsd-wasm32@0.35.3':
|
||||
resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
os: [freebsd]
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.3':
|
||||
resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==}
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.2':
|
||||
resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.3.3':
|
||||
resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==}
|
||||
'@img/sharp-libvips-darwin-x64@1.3.2':
|
||||
resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.3.3':
|
||||
resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==}
|
||||
'@img/sharp-libvips-linux-arm64@1.3.2':
|
||||
resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.3.3':
|
||||
resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==}
|
||||
'@img/sharp-libvips-linux-arm@1.3.2':
|
||||
resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.3':
|
||||
resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==}
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.2':
|
||||
resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.3':
|
||||
resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==}
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.2':
|
||||
resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.3.3':
|
||||
resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==}
|
||||
'@img/sharp-libvips-linux-s390x@1.3.2':
|
||||
resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.3.3':
|
||||
resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==}
|
||||
'@img/sharp-libvips-linux-x64@1.3.2':
|
||||
resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.3':
|
||||
resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==}
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.2':
|
||||
resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.3':
|
||||
resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==}
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.2':
|
||||
resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==}
|
||||
'@img/sharp-linux-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.35.4':
|
||||
resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==}
|
||||
'@img/sharp-linux-arm@0.35.3':
|
||||
resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-ppc64@0.35.4':
|
||||
resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==}
|
||||
'@img/sharp-linux-ppc64@0.35.3':
|
||||
resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-riscv64@0.35.4':
|
||||
resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==}
|
||||
'@img/sharp-linux-riscv64@0.35.3':
|
||||
resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.35.4':
|
||||
resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==}
|
||||
'@img/sharp-linux-s390x@0.35.3':
|
||||
resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.35.4':
|
||||
resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==}
|
||||
'@img/sharp-linux-x64@0.35.3':
|
||||
resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==}
|
||||
'@img/sharp-linuxmusl-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.35.4':
|
||||
resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==}
|
||||
'@img/sharp-linuxmusl-x64@0.35.3':
|
||||
resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.35.4':
|
||||
resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==}
|
||||
'@img/sharp-wasm32@0.35.3':
|
||||
resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
|
||||
'@img/sharp-webcontainers-wasm32@0.35.4':
|
||||
resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==}
|
||||
'@img/sharp-webcontainers-wasm32@0.35.3':
|
||||
resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@img/sharp-win32-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==}
|
||||
'@img/sharp-win32-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@img/sharp-win32-ia32@0.35.4':
|
||||
resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==}
|
||||
'@img/sharp-win32-ia32@0.35.3':
|
||||
resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==}
|
||||
engines: {node: ^20.9.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@img/sharp-win32-x64@0.35.4':
|
||||
resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==}
|
||||
'@img/sharp-win32-x64@0.35.3':
|
||||
resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -386,22 +386,22 @@ packages:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
cypress-real-events@1.15.1:
|
||||
resolution: {integrity: sha512-BiTyqYcNHiIFWfSLRn3H+TgTvpnTGOKfl4Brz51yeSGKMxBbD60wtRQw31nII00yQ67Xg3C18mU8lqUxDN3OUA==}
|
||||
cypress-real-events@1.15.0:
|
||||
resolution: {integrity: sha512-in98xxTnnM9Z7lZBvvVozm99PBT2eEOjXRG5LKWyYvQnj9mGWXMiPNpfw7e7WiraBFh7XlXIxnE9Cu5o+52kQQ==}
|
||||
peerDependencies:
|
||||
cypress: ^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x || ^11.x || ^12.x || ^13.x || ^14.x || ^15.x || ^16.x
|
||||
cypress: ^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x || ^11.x || ^12.x || ^13.x || ^14.x || ^15.x
|
||||
|
||||
cypress@16.1.1:
|
||||
resolution: {integrity: sha512-T09qNpMKssD6eEMqqfywQ8OUub/VrNCvIUFAyQCfWsJ6o4CZ5Yeapce+WoZY9FXly6+3+pk7sjEB5voxduWQlQ==}
|
||||
engines: {node: ^22.0.0 || ^24.0.0 || >=26.0.0}
|
||||
cypress@15.21.1:
|
||||
resolution: {integrity: sha512-ogHpHMj0XNlZA5MGzjg8SWHf0eMw9lTwVQRKjpcT1GzNTxNUjwnHA8YCG6nOJ8ThU+XZaUxJgpMYZnJ//8aDaw==}
|
||||
engines: {node: ^20.1.0 || ^22.0.0 || >=24.0.0}
|
||||
hasBin: true
|
||||
|
||||
dashdash@1.14.1:
|
||||
resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
|
||||
engines: {node: '>=0.10'}
|
||||
|
||||
dayjs@1.11.23:
|
||||
resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==}
|
||||
dayjs@1.11.21:
|
||||
resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==}
|
||||
|
||||
debug@3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
@@ -490,6 +490,7 @@ packages:
|
||||
|
||||
extsprintf@1.3.0:
|
||||
resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
|
||||
engines: {'0': node >=0.6.0}
|
||||
|
||||
forever-agent@0.6.1:
|
||||
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
|
||||
@@ -624,6 +625,7 @@ packages:
|
||||
|
||||
jsprim@2.0.2:
|
||||
resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
|
||||
engines: {'0': node >=0.6.0}
|
||||
|
||||
listr2@9.0.5:
|
||||
resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==}
|
||||
@@ -792,8 +794,8 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
sharp@0.35.4:
|
||||
resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==}
|
||||
sharp@0.35.3:
|
||||
resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
peerDependencies:
|
||||
'@types/node': '*'
|
||||
@@ -928,6 +930,7 @@ packages:
|
||||
|
||||
verror@1.10.0:
|
||||
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
|
||||
engines: {'0': node >=0.6.0}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
@@ -1001,132 +1004,132 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@frsource/base64@1.0.237': {}
|
||||
'@frsource/base64@1.0.213': {}
|
||||
|
||||
'@frsource/cypress-plugin-visual-regression-diff@4.2.1(cypress@16.1.1)':
|
||||
'@frsource/cypress-plugin-visual-regression-diff@4.1.1(cypress@15.21.1)':
|
||||
dependencies:
|
||||
'@frsource/base64': 1.0.237
|
||||
cypress: 16.1.1
|
||||
'@frsource/base64': 1.0.213
|
||||
cypress: 15.21.1
|
||||
glob: 13.0.6
|
||||
meta-png: 1.0.6
|
||||
move-file: 4.1.0
|
||||
pixelmatch: 7.2.0
|
||||
pngjs: 7.0.0
|
||||
sharp: 0.35.4
|
||||
sharp: 0.35.3
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
'@img/colour@1.1.0': {}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.35.4':
|
||||
'@img/sharp-darwin-arm64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.3
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-darwin-x64@0.35.4':
|
||||
'@img/sharp-darwin-x64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.3
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-freebsd-wasm32@0.35.4':
|
||||
'@img/sharp-freebsd-wasm32@0.35.3':
|
||||
dependencies:
|
||||
'@img/sharp-wasm32': 0.35.4
|
||||
'@img/sharp-wasm32': 0.35.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.3':
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.3.3':
|
||||
'@img/sharp-libvips-darwin-x64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.3.3':
|
||||
'@img/sharp-libvips-linux-arm64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.3.3':
|
||||
'@img/sharp-libvips-linux-arm@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.3':
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.3':
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.3.3':
|
||||
'@img/sharp-libvips-linux-s390x@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.3.3':
|
||||
'@img/sharp-libvips-linux-x64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.3':
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.3':
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.2':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm64@0.35.4':
|
||||
'@img/sharp-linux-arm64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.3
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm@0.35.4':
|
||||
'@img/sharp-linux-arm@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm': 1.3.3
|
||||
'@img/sharp-libvips-linux-arm': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-ppc64@0.35.4':
|
||||
'@img/sharp-linux-ppc64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.3
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-riscv64@0.35.4':
|
||||
'@img/sharp-linux-riscv64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.3
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-s390x@0.35.4':
|
||||
'@img/sharp-linux-s390x@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.3
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-x64@0.35.4':
|
||||
'@img/sharp-linux-x64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-x64': 1.3.3
|
||||
'@img/sharp-libvips-linux-x64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.35.4':
|
||||
'@img/sharp-linuxmusl-arm64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.3
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.35.4':
|
||||
'@img/sharp-linuxmusl-x64@0.35.3':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.3
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.2
|
||||
optional: true
|
||||
|
||||
'@img/sharp-wasm32@0.35.4':
|
||||
'@img/sharp-wasm32@0.35.3':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.11.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-webcontainers-wasm32@0.35.4':
|
||||
'@img/sharp-webcontainers-wasm32@0.35.3':
|
||||
dependencies:
|
||||
'@img/sharp-wasm32': 0.35.4
|
||||
'@img/sharp-wasm32': 0.35.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-arm64@0.35.4':
|
||||
'@img/sharp-win32-arm64@0.35.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-ia32@0.35.4':
|
||||
'@img/sharp-win32-ia32@0.35.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-x64@0.35.4':
|
||||
'@img/sharp-win32-x64@0.35.3':
|
||||
optional: true
|
||||
|
||||
'@testing-library/cypress@10.1.3(cypress@16.1.1)':
|
||||
'@testing-library/cypress@10.1.3(cypress@15.21.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@testing-library/dom': 10.4.1
|
||||
cypress: 16.1.1
|
||||
cypress: 15.21.1
|
||||
|
||||
'@testing-library/dom@10.4.1':
|
||||
dependencies:
|
||||
@@ -1277,11 +1280,11 @@ snapshots:
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
cypress-real-events@1.15.1(cypress@16.1.1):
|
||||
cypress-real-events@1.15.0(cypress@15.21.1):
|
||||
dependencies:
|
||||
cypress: 16.1.1
|
||||
cypress: 15.21.1
|
||||
|
||||
cypress@16.1.1:
|
||||
cypress@15.21.1:
|
||||
dependencies:
|
||||
'@cypress/request': 4.0.1
|
||||
'@cypress/xvfb': 1.2.4(supports-color@8.1.1)
|
||||
@@ -1299,7 +1302,7 @@ snapshots:
|
||||
cli-table3: 0.6.1
|
||||
commander: 6.2.1
|
||||
common-tags: 1.8.2
|
||||
dayjs: 1.11.23
|
||||
dayjs: 1.11.21
|
||||
debug: 4.4.3(supports-color@8.1.1)
|
||||
eventemitter2: 6.4.7
|
||||
execa: 4.1.0
|
||||
@@ -1330,7 +1333,7 @@ snapshots:
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
|
||||
dayjs@1.11.23: {}
|
||||
dayjs@1.11.21: {}
|
||||
|
||||
debug@3.2.7(supports-color@8.1.1):
|
||||
dependencies:
|
||||
@@ -1686,37 +1689,37 @@ snapshots:
|
||||
|
||||
semver@7.8.5: {}
|
||||
|
||||
sharp@0.35.4:
|
||||
sharp@0.35.3:
|
||||
dependencies:
|
||||
'@img/colour': 1.1.0
|
||||
detect-libc: 2.1.2
|
||||
semver: 7.8.5
|
||||
optionalDependencies:
|
||||
'@img/sharp-darwin-arm64': 0.35.4
|
||||
'@img/sharp-darwin-x64': 0.35.4
|
||||
'@img/sharp-freebsd-wasm32': 0.35.4
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.3
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.3
|
||||
'@img/sharp-libvips-linux-arm': 1.3.3
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.3
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.3
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.3
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.3
|
||||
'@img/sharp-libvips-linux-x64': 1.3.3
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.3
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.3
|
||||
'@img/sharp-linux-arm': 0.35.4
|
||||
'@img/sharp-linux-arm64': 0.35.4
|
||||
'@img/sharp-linux-ppc64': 0.35.4
|
||||
'@img/sharp-linux-riscv64': 0.35.4
|
||||
'@img/sharp-linux-s390x': 0.35.4
|
||||
'@img/sharp-linux-x64': 0.35.4
|
||||
'@img/sharp-linuxmusl-arm64': 0.35.4
|
||||
'@img/sharp-linuxmusl-x64': 0.35.4
|
||||
'@img/sharp-webcontainers-wasm32': 0.35.4
|
||||
'@img/sharp-win32-arm64': 0.35.4
|
||||
'@img/sharp-win32-ia32': 0.35.4
|
||||
'@img/sharp-win32-x64': 0.35.4
|
||||
'@img/sharp-darwin-arm64': 0.35.3
|
||||
'@img/sharp-darwin-x64': 0.35.3
|
||||
'@img/sharp-freebsd-wasm32': 0.35.3
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.2
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.2
|
||||
'@img/sharp-libvips-linux-arm': 1.3.2
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.2
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.2
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.2
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.2
|
||||
'@img/sharp-libvips-linux-x64': 1.3.2
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.2
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.2
|
||||
'@img/sharp-linux-arm': 0.35.3
|
||||
'@img/sharp-linux-arm64': 0.35.3
|
||||
'@img/sharp-linux-ppc64': 0.35.3
|
||||
'@img/sharp-linux-riscv64': 0.35.3
|
||||
'@img/sharp-linux-s390x': 0.35.3
|
||||
'@img/sharp-linux-x64': 0.35.3
|
||||
'@img/sharp-linuxmusl-arm64': 0.35.3
|
||||
'@img/sharp-linuxmusl-x64': 0.35.3
|
||||
'@img/sharp-webcontainers-wasm32': 0.35.3
|
||||
'@img/sharp-win32-arm64': 0.35.3
|
||||
'@img/sharp-win32-ia32': 0.35.3
|
||||
'@img/sharp-win32-x64': 0.35.3
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
|
||||
@@ -16,7 +16,7 @@ globalThis.process.env = {
|
||||
|
||||
Cypress.Screenshot.defaults({ capture: 'viewport' })
|
||||
|
||||
if (Cypress.expose('CY_CI')) {
|
||||
if (Cypress.env('CY_CI')) {
|
||||
Cypress.config('defaultCommandTimeout', 20000)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,4 +4,4 @@ corepack enable pnpm
|
||||
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
pnpm cypress:install
|
||||
pnpm test:ci:ct --expose pluginVisualRegressionUpdateImages=$CYPRESS_UPDATE_SNAPSHOTS --spec '../../**/*-visuals.cy.*'
|
||||
pnpm test:ci:ct --env pluginVisualRegressionUpdateImages=$CYPRESS_UPDATE_SNAPSHOTS --spec '../../**/*-visuals.cy.*'
|
||||
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
command: sleep infinity
|
||||
|
||||
elasticsearch:
|
||||
image: elasticsearch:9.5.3
|
||||
image: elasticsearch:9.3.2
|
||||
environment:
|
||||
- "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
|
||||
- discovery.type=single-node
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
|
||||
memcached:
|
||||
command: memcached -m 256M
|
||||
image: memcached:1.6.45-alpine
|
||||
image: memcached:1.6.38-alpine
|
||||
restart: unless-stopped
|
||||
|
||||
postgresql:
|
||||
|
||||
@@ -13,9 +13,9 @@ pnpm config set store-dir "$(pwd)/.pnpm-store" --global
|
||||
|
||||
bin/setup --skip-server
|
||||
|
||||
echo "== Initialize CodeGraph index =="
|
||||
echo "== Install CodeGraph index =="
|
||||
|
||||
pnpm run codegraph:init
|
||||
pnpm run codegraph:install
|
||||
|
||||
echo "== Precompile Ruby cache =="
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ pnpm config set store-dir "$(pwd)/.pnpm-store" --global
|
||||
|
||||
bin/setup --skip-server
|
||||
|
||||
echo "== Initialize CodeGraph index =="
|
||||
echo "== Install CodeGraph index =="
|
||||
|
||||
pnpm run codegraph:init
|
||||
pnpm run codegraph:install
|
||||
|
||||
echo "== Precompile Ruby cache =="
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ pnpm config set store-dir "$(pwd)/.pnpm-store" --global
|
||||
|
||||
bin/setup --skip-server
|
||||
|
||||
echo "== Initialize CodeGraph index =="
|
||||
echo "== Install CodeGraph index =="
|
||||
|
||||
pnpm run codegraph:init
|
||||
pnpm run codegraph:install
|
||||
|
||||
echo "== Precompile Ruby cache =="
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ pnpm config set store-dir "$(pwd)/.pnpm-store" --global
|
||||
|
||||
bin/setup --skip-server
|
||||
|
||||
echo "== Initialize CodeGraph index =="
|
||||
echo "== Install CodeGraph index =="
|
||||
|
||||
pnpm run codegraph:init
|
||||
pnpm run codegraph:install
|
||||
|
||||
echo "== Precompile Ruby cache =="
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
"requireindex": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^10.12.0",
|
||||
"eslint": "^10.9.1",
|
||||
"eslint-plugin-eslint-plugin": "^7.6.2",
|
||||
"eslint-plugin-n": "^18.4.0",
|
||||
"mocha": "^12.0.3",
|
||||
"eslint-plugin-n": "^18.3.0",
|
||||
"mocha": "^11.8.0",
|
||||
"vue-eslint-parser": "^10.4.1"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
606
.eslint-plugin-zammad/pnpm-lock.yaml
generated
606
.eslint-plugin-zammad/pnpm-lock.yaml
generated
@@ -13,29 +13,23 @@ importers:
|
||||
version: 1.2.0
|
||||
devDependencies:
|
||||
eslint:
|
||||
specifier: ^10.12.0
|
||||
version: 10.12.0(supports-color@8.1.1)
|
||||
specifier: ^10.9.1
|
||||
version: 10.9.1(supports-color@8.1.1)
|
||||
eslint-plugin-eslint-plugin:
|
||||
specifier: ^7.6.2
|
||||
version: 7.6.2(eslint@10.12.0(supports-color@8.1.1))
|
||||
version: 7.6.2(eslint@10.9.1(supports-color@8.1.1))
|
||||
eslint-plugin-n:
|
||||
specifier: ^18.4.0
|
||||
version: 18.4.0(eslint@10.12.0(supports-color@8.1.1))
|
||||
specifier: ^18.3.0
|
||||
version: 18.3.0(eslint@10.9.1(supports-color@8.1.1))
|
||||
mocha:
|
||||
specifier: ^12.0.3
|
||||
version: 12.0.3
|
||||
specifier: ^11.8.0
|
||||
version: 11.8.0
|
||||
vue-eslint-parser:
|
||||
specifier: ^10.4.1
|
||||
version: 10.4.1(eslint@10.12.0(supports-color@8.1.1))(supports-color@8.1.1)
|
||||
version: 10.4.1(eslint@10.9.1(supports-color@8.1.1))(supports-color@8.1.1)
|
||||
|
||||
packages:
|
||||
|
||||
'@cacheable/memory@2.2.0':
|
||||
resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==}
|
||||
|
||||
'@cacheable/utils@2.5.0':
|
||||
resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==}
|
||||
|
||||
'@eslint-community/eslint-utils@4.10.1':
|
||||
resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
@@ -62,8 +56,8 @@ packages:
|
||||
resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
'@eslint/plugin-kit@0.7.3':
|
||||
resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==}
|
||||
'@eslint/plugin-kit@0.7.2':
|
||||
resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
'@humanfs/core@0.19.2':
|
||||
@@ -86,14 +80,13 @@ packages:
|
||||
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
|
||||
engines: {node: '>=18.18'}
|
||||
|
||||
'@keyv/bigmap@1.3.1':
|
||||
resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
keyv: ^5.6.0
|
||||
'@isaacs/cliui@8.0.2':
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@keyv/serialize@1.1.1':
|
||||
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@types/esrecurse@4.3.1':
|
||||
resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==}
|
||||
@@ -117,13 +110,35 @@ packages:
|
||||
ajv@6.15.0:
|
||||
resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-regex@6.3.0:
|
||||
resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-styles@6.2.3:
|
||||
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
balanced-match@4.0.4:
|
||||
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
|
||||
brace-expansion@2.1.4:
|
||||
resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==}
|
||||
|
||||
brace-expansion@5.0.9:
|
||||
resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==}
|
||||
engines: {node: 20 || >=22}
|
||||
@@ -131,12 +146,28 @@ packages:
|
||||
browser-stdout@1.3.1:
|
||||
resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==}
|
||||
|
||||
cacheable@2.5.0:
|
||||
resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==}
|
||||
camelcase@6.3.0:
|
||||
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
chokidar@5.0.0:
|
||||
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
|
||||
engines: {node: '>= 20.19.0'}
|
||||
chalk@4.1.2:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
chokidar@4.0.3:
|
||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
|
||||
cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
@@ -151,17 +182,34 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decamelize@4.0.0:
|
||||
resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
diff@9.0.0:
|
||||
resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==}
|
||||
diff@7.0.0:
|
||||
resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
|
||||
enhanced-resolve@5.24.5:
|
||||
resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
escalade@3.2.0:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
escape-string-regexp@4.0.0:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -184,8 +232,8 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: '>=9.0.0'
|
||||
|
||||
eslint-plugin-n@18.4.0:
|
||||
resolution: {integrity: sha512-TEm6Nqn9+l7EWfJXOL6pmrEdpiM2ZTgo4fNMRDvBTM70jeQ7x3X3Akcx+sRCIRfpcSVwMypH3ZAA33PLyNKmYw==}
|
||||
eslint-plugin-n@18.3.0:
|
||||
resolution: {integrity: sha512-cPVguuDe6DrIPb/qUXHf8P89MaVTUmiYWwpt5gX5AILsvRIiZAxMFXcFR6QHYBksqKJpjfUBlL/RleCJUWcD7w==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
peerDependencies:
|
||||
eslint: '>=8.57.1'
|
||||
@@ -209,8 +257,8 @@ packages:
|
||||
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
eslint@10.12.0:
|
||||
resolution: {integrity: sha512-npHjrHb2o4ehH3mE+YuxABR+0gyb0aVWCIolgJDArwCiHEIsonBm3ZKjel5b0U5+a+MbEvIyRCGCzD3eKKK2NA==}
|
||||
eslint@10.9.1:
|
||||
resolution: {integrity: sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -248,23 +296,33 @@ packages:
|
||||
fast-levenshtein@2.0.6:
|
||||
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||
|
||||
file-entry-cache@11.1.5:
|
||||
resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==}
|
||||
|
||||
find-up-simple@1.0.1:
|
||||
resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==}
|
||||
engines: {node: '>=18'}
|
||||
file-entry-cache@8.0.0:
|
||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
find-up@5.0.0:
|
||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
flat-cache@6.1.23:
|
||||
resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==}
|
||||
flat-cache@4.0.1:
|
||||
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
flat@5.0.2:
|
||||
resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
|
||||
hasBin: true
|
||||
|
||||
flatted@3.4.4:
|
||||
resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==}
|
||||
|
||||
foreground-child@3.3.1:
|
||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
get-caller-file@2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
get-tsconfig@4.14.2:
|
||||
resolution: {integrity: sha512-XpwZALwwl/BaKTAyC6+c5T8y6kCg2jk+XGqOVrKIQmW49pNypYLMRjCUXqa28tQgJlhS2RlzP7sc+Rx7W6qsfw==}
|
||||
|
||||
@@ -272,9 +330,10 @@ packages:
|
||||
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
glob@13.0.6:
|
||||
resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
glob@10.5.0:
|
||||
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
hasBin: true
|
||||
|
||||
globals@15.15.0:
|
||||
resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
|
||||
@@ -290,15 +349,9 @@ packages:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
hashery@1.5.1:
|
||||
resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
hookified@1.15.1:
|
||||
resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==}
|
||||
|
||||
hookified@2.2.0:
|
||||
resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==}
|
||||
he@1.2.0:
|
||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||
hasBin: true
|
||||
|
||||
ignore@5.3.2:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
@@ -312,13 +365,21 @@ packages:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-path-inside@4.0.0:
|
||||
resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
|
||||
engines: {node: '>=12'}
|
||||
is-path-inside@3.0.3:
|
||||
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-plain-obj@2.1.0:
|
||||
resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-unicode-supported@0.1.0:
|
||||
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
||||
@@ -327,18 +388,24 @@ packages:
|
||||
isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
js-yaml@5.4.1:
|
||||
resolution: {integrity: sha512-28R/k+NAjeuf7+CKlTxWZVExJGwVVLwY06DgEnOMz2gEpfNkDcD7QvyiVPT0xy0XXhU8vHsd4Ot42OOPdJG7dQ==}
|
||||
jackspeak@3.4.3:
|
||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||
|
||||
js-yaml@4.3.1:
|
||||
resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==}
|
||||
hasBin: true
|
||||
|
||||
json-buffer@3.0.1:
|
||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||
|
||||
json-schema-traverse@0.4.1:
|
||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1:
|
||||
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||
|
||||
keyv@5.6.0:
|
||||
resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==}
|
||||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
levn@0.4.1:
|
||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
@@ -348,21 +415,28 @@ packages:
|
||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
lru-cache@11.5.2:
|
||||
resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==}
|
||||
engines: {node: 20 || >=22}
|
||||
log-symbols@4.1.0:
|
||||
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
minimatch@10.2.6:
|
||||
resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
|
||||
minimatch@9.0.9:
|
||||
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minipass@7.1.3:
|
||||
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
mocha@12.0.3:
|
||||
resolution: {integrity: sha512-beammieDdiWdkjANWeWPpkxUROYGi5FN88fPOkLiticz7HTg3Y+Pho3EYE6SUdcuWnZ3h2WD8EXCA55JF4o6wg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
mocha@11.8.0:
|
||||
resolution: {integrity: sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
hasBin: true
|
||||
|
||||
ms@2.1.3:
|
||||
@@ -383,6 +457,9 @@ packages:
|
||||
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
package-json-from-dist@1.0.1:
|
||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||
|
||||
path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -391,9 +468,9 @@ packages:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-scurry@2.0.2:
|
||||
resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
path-scurry@1.11.1:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
@@ -406,13 +483,16 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
qified@0.10.1:
|
||||
resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==}
|
||||
engines: {node: '>=20'}
|
||||
randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
|
||||
readdirp@5.1.1:
|
||||
resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==}
|
||||
engines: {node: '>= 20.19.0'}
|
||||
readdirp@4.1.2:
|
||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||
engines: {node: '>= 14.18.0'}
|
||||
|
||||
require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
requireindex@1.2.0:
|
||||
resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==}
|
||||
@@ -421,14 +501,16 @@ packages:
|
||||
resolve-pkg-maps@1.0.0:
|
||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||
|
||||
safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
|
||||
semver@7.8.5:
|
||||
resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
serialize-javascript@7.1.1:
|
||||
resolution: {integrity: sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
serialize-javascript@6.0.2:
|
||||
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
@@ -438,9 +520,33 @@ packages:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-json-comments@5.0.3:
|
||||
resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==}
|
||||
engines: {node: '>=14.16'}
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
string-width@5.1.2:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-ansi@7.2.0:
|
||||
resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
strip-json-comments@3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
supports-color@8.1.1:
|
||||
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
|
||||
@@ -472,8 +578,32 @@ packages:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
workerpool@10.0.3:
|
||||
resolution: {integrity: sha512-6z2Iis68Wqth93/G/wJP9u+R3O+d2XTlgWChGCwuT1qLbBsOYueGRZuJ++v3mtDP5KjYdy+WzvWC+VWETSVXJA==}
|
||||
workerpool@9.3.4:
|
||||
resolution: {integrity: sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
wrap-ansi@8.1.0:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yargs-unparser@2.0.0:
|
||||
resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
yargs@17.7.3:
|
||||
resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yocto-queue@0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
@@ -481,21 +611,9 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@cacheable/memory@2.2.0':
|
||||
'@eslint-community/eslint-utils@4.10.1(eslint@10.9.1(supports-color@8.1.1))':
|
||||
dependencies:
|
||||
'@cacheable/utils': 2.5.0
|
||||
'@keyv/bigmap': 1.3.1(keyv@5.6.0)
|
||||
hookified: 1.15.1
|
||||
keyv: 5.6.0
|
||||
|
||||
'@cacheable/utils@2.5.0':
|
||||
dependencies:
|
||||
hashery: 1.5.1
|
||||
keyv: 5.6.0
|
||||
|
||||
'@eslint-community/eslint-utils@4.10.1(eslint@10.12.0(supports-color@8.1.1))':
|
||||
dependencies:
|
||||
eslint: 10.12.0(supports-color@8.1.1)
|
||||
eslint: 10.9.1(supports-color@8.1.1)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/regexpp@4.12.2': {}
|
||||
@@ -518,7 +636,7 @@ snapshots:
|
||||
|
||||
'@eslint/object-schema@3.0.5': {}
|
||||
|
||||
'@eslint/plugin-kit@0.7.3':
|
||||
'@eslint/plugin-kit@0.7.2':
|
||||
dependencies:
|
||||
'@eslint/core': 1.2.1
|
||||
levn: 0.4.1
|
||||
@@ -539,13 +657,17 @@ snapshots:
|
||||
|
||||
'@humanwhocodes/retry@0.4.3': {}
|
||||
|
||||
'@keyv/bigmap@1.3.1(keyv@5.6.0)':
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
hashery: 1.5.1
|
||||
hookified: 1.15.1
|
||||
keyv: 5.6.0
|
||||
string-width: 5.1.2
|
||||
string-width-cjs: string-width@4.2.3
|
||||
strip-ansi: 7.2.0
|
||||
strip-ansi-cjs: strip-ansi@6.0.1
|
||||
wrap-ansi: 8.1.0
|
||||
wrap-ansi-cjs: wrap-ansi@7.0.0
|
||||
|
||||
'@keyv/serialize@1.1.1': {}
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@types/esrecurse@4.3.1': {}
|
||||
|
||||
@@ -566,27 +688,54 @@ snapshots:
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.3.0: {}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
|
||||
ansi-styles@6.2.3: {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
balanced-match@4.0.4: {}
|
||||
|
||||
brace-expansion@2.1.4:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
brace-expansion@5.0.9:
|
||||
dependencies:
|
||||
balanced-match: 4.0.4
|
||||
|
||||
browser-stdout@1.3.1: {}
|
||||
|
||||
cacheable@2.5.0:
|
||||
dependencies:
|
||||
'@cacheable/memory': 2.2.0
|
||||
'@cacheable/utils': 2.5.0
|
||||
hookified: 1.15.1
|
||||
keyv: 5.6.0
|
||||
qified: 0.10.1
|
||||
camelcase@6.3.0: {}
|
||||
|
||||
chokidar@5.0.0:
|
||||
chalk@4.1.2:
|
||||
dependencies:
|
||||
readdirp: 5.1.1
|
||||
ansi-styles: 4.3.0
|
||||
supports-color: 7.2.0
|
||||
|
||||
chokidar@4.0.3:
|
||||
dependencies:
|
||||
readdirp: 4.1.2
|
||||
|
||||
cliui@8.0.1:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 7.0.0
|
||||
|
||||
color-convert@2.0.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
@@ -600,46 +749,55 @@ snapshots:
|
||||
optionalDependencies:
|
||||
supports-color: 8.1.1
|
||||
|
||||
decamelize@4.0.0: {}
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
diff@9.0.0: {}
|
||||
diff@7.0.0: {}
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
|
||||
enhanced-resolve@5.24.5:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.3.3
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
eslint-compat-utils@0.5.1(eslint@10.12.0(supports-color@8.1.1)):
|
||||
eslint-compat-utils@0.5.1(eslint@10.9.1(supports-color@8.1.1)):
|
||||
dependencies:
|
||||
eslint: 10.12.0(supports-color@8.1.1)
|
||||
eslint: 10.9.1(supports-color@8.1.1)
|
||||
semver: 7.8.5
|
||||
|
||||
eslint-plugin-es-x@7.8.0(eslint@10.12.0(supports-color@8.1.1)):
|
||||
eslint-plugin-es-x@7.8.0(eslint@10.9.1(supports-color@8.1.1)):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(supports-color@8.1.1))
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.1(supports-color@8.1.1))
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
eslint: 10.12.0(supports-color@8.1.1)
|
||||
eslint-compat-utils: 0.5.1(eslint@10.12.0(supports-color@8.1.1))
|
||||
eslint: 10.9.1(supports-color@8.1.1)
|
||||
eslint-compat-utils: 0.5.1(eslint@10.9.1(supports-color@8.1.1))
|
||||
|
||||
eslint-plugin-eslint-plugin@7.6.2(eslint@10.12.0(supports-color@8.1.1)):
|
||||
eslint-plugin-eslint-plugin@7.6.2(eslint@10.9.1(supports-color@8.1.1)):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(supports-color@8.1.1))
|
||||
eslint: 10.12.0(supports-color@8.1.1)
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.1(supports-color@8.1.1))
|
||||
eslint: 10.9.1(supports-color@8.1.1)
|
||||
estraverse: 5.3.0
|
||||
|
||||
eslint-plugin-n@18.4.0(eslint@10.12.0(supports-color@8.1.1)):
|
||||
eslint-plugin-n@18.3.0(eslint@10.9.1(supports-color@8.1.1)):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(supports-color@8.1.1))
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.1(supports-color@8.1.1))
|
||||
enhanced-resolve: 5.24.5
|
||||
eslint: 10.12.0(supports-color@8.1.1)
|
||||
eslint-plugin-es-x: 7.8.0(eslint@10.12.0(supports-color@8.1.1))
|
||||
eslint: 10.9.1(supports-color@8.1.1)
|
||||
eslint-plugin-es-x: 7.8.0(eslint@10.9.1(supports-color@8.1.1))
|
||||
get-tsconfig: 4.14.2
|
||||
globals: 15.15.0
|
||||
globrex: 0.1.2
|
||||
ignore: 5.3.2
|
||||
js-yaml: 5.4.1
|
||||
semver: 7.8.5
|
||||
|
||||
eslint-scope@9.1.2:
|
||||
@@ -653,14 +811,14 @@ snapshots:
|
||||
|
||||
eslint-visitor-keys@5.0.1: {}
|
||||
|
||||
eslint@10.12.0(supports-color@8.1.1):
|
||||
eslint@10.9.1(supports-color@8.1.1):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(supports-color@8.1.1))
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.9.1(supports-color@8.1.1))
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@eslint/config-array': 0.23.5(supports-color@8.1.1)
|
||||
'@eslint/config-helpers': 0.7.0
|
||||
'@eslint/core': 1.2.1
|
||||
'@eslint/plugin-kit': 0.7.3
|
||||
'@eslint/plugin-kit': 0.7.2
|
||||
'@humanfs/node': 0.16.8
|
||||
'@humanwhocodes/module-importer': 1.0.1
|
||||
'@humanwhocodes/retry': 0.4.3
|
||||
@@ -675,7 +833,7 @@ snapshots:
|
||||
esquery: 1.7.0
|
||||
esutils: 2.0.3
|
||||
fast-deep-equal: 3.1.3
|
||||
file-entry-cache: 11.1.5
|
||||
file-entry-cache: 8.0.0
|
||||
find-up: 5.0.0
|
||||
glob-parent: 6.0.2
|
||||
ignore: 5.3.2
|
||||
@@ -712,25 +870,31 @@ snapshots:
|
||||
|
||||
fast-levenshtein@2.0.6: {}
|
||||
|
||||
file-entry-cache@11.1.5:
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
flat-cache: 6.1.23
|
||||
|
||||
find-up-simple@1.0.1: {}
|
||||
flat-cache: 4.0.1
|
||||
|
||||
find-up@5.0.0:
|
||||
dependencies:
|
||||
locate-path: 6.0.0
|
||||
path-exists: 4.0.0
|
||||
|
||||
flat-cache@6.1.23:
|
||||
flat-cache@4.0.1:
|
||||
dependencies:
|
||||
cacheable: 2.5.0
|
||||
flatted: 3.4.4
|
||||
hookified: 1.15.1
|
||||
keyv: 4.5.4
|
||||
|
||||
flat@5.0.2: {}
|
||||
|
||||
flatted@3.4.4: {}
|
||||
|
||||
foreground-child@3.3.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
signal-exit: 4.1.0
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
get-tsconfig@4.14.2:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
@@ -739,11 +903,14 @@ snapshots:
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
|
||||
glob@13.0.6:
|
||||
glob@10.5.0:
|
||||
dependencies:
|
||||
minimatch: 10.2.6
|
||||
foreground-child: 3.3.1
|
||||
jackspeak: 3.4.3
|
||||
minimatch: 9.0.9
|
||||
minipass: 7.1.3
|
||||
path-scurry: 2.0.2
|
||||
package-json-from-dist: 1.0.1
|
||||
path-scurry: 1.11.1
|
||||
|
||||
globals@15.15.0: {}
|
||||
|
||||
@@ -753,13 +920,7 @@ snapshots:
|
||||
|
||||
has-flag@4.0.0: {}
|
||||
|
||||
hashery@1.5.1:
|
||||
dependencies:
|
||||
hookified: 1.15.1
|
||||
|
||||
hookified@1.15.1: {}
|
||||
|
||||
hookified@2.2.0: {}
|
||||
he@1.2.0: {}
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
@@ -767,27 +928,39 @@ snapshots:
|
||||
|
||||
is-extglob@2.1.1: {}
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
is-path-inside@4.0.0: {}
|
||||
is-path-inside@3.0.3: {}
|
||||
|
||||
is-plain-obj@2.1.0: {}
|
||||
|
||||
is-unicode-supported@0.1.0: {}
|
||||
|
||||
isexe@2.0.0: {}
|
||||
|
||||
js-yaml@5.4.1:
|
||||
jackspeak@3.4.3:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
js-yaml@4.3.1:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
json-buffer@3.0.1: {}
|
||||
|
||||
json-schema-traverse@0.4.1: {}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||
|
||||
keyv@5.6.0:
|
||||
keyv@4.5.4:
|
||||
dependencies:
|
||||
'@keyv/serialize': 1.1.1
|
||||
json-buffer: 3.0.1
|
||||
|
||||
levn@0.4.1:
|
||||
dependencies:
|
||||
@@ -798,32 +971,46 @@ snapshots:
|
||||
dependencies:
|
||||
p-locate: 5.0.0
|
||||
|
||||
lru-cache@11.5.2: {}
|
||||
log-symbols@4.1.0:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
is-unicode-supported: 0.1.0
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
minimatch@10.2.6:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.9
|
||||
|
||||
minimatch@9.0.9:
|
||||
dependencies:
|
||||
brace-expansion: 2.1.4
|
||||
|
||||
minipass@7.1.3: {}
|
||||
|
||||
mocha@12.0.3:
|
||||
mocha@11.8.0:
|
||||
dependencies:
|
||||
browser-stdout: 1.3.1
|
||||
chokidar: 5.0.0
|
||||
chokidar: 4.0.3
|
||||
debug: 4.4.3(supports-color@8.1.1)
|
||||
diff: 9.0.0
|
||||
find-up-simple: 1.0.1
|
||||
glob: 13.0.6
|
||||
is-path-inside: 4.0.0
|
||||
is-unicode-supported: 0.1.0
|
||||
js-yaml: 5.4.1
|
||||
minimatch: 10.2.6
|
||||
diff: 7.0.0
|
||||
escape-string-regexp: 4.0.0
|
||||
find-up: 5.0.0
|
||||
glob: 10.5.0
|
||||
he: 1.2.0
|
||||
is-path-inside: 3.0.3
|
||||
js-yaml: 4.3.1
|
||||
log-symbols: 4.1.0
|
||||
minimatch: 9.0.9
|
||||
ms: 2.1.3
|
||||
picocolors: 1.1.1
|
||||
serialize-javascript: 7.1.1
|
||||
strip-json-comments: 5.0.3
|
||||
serialize-javascript: 6.0.2
|
||||
strip-json-comments: 3.1.1
|
||||
supports-color: 8.1.1
|
||||
workerpool: 10.0.3
|
||||
workerpool: 9.3.4
|
||||
yargs: 17.7.3
|
||||
yargs-parser: 21.1.1
|
||||
yargs-unparser: 2.0.0
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
@@ -846,13 +1033,15 @@ snapshots:
|
||||
dependencies:
|
||||
p-limit: 3.1.0
|
||||
|
||||
package-json-from-dist@1.0.1: {}
|
||||
|
||||
path-exists@4.0.0: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-scurry@2.0.2:
|
||||
path-scurry@1.11.1:
|
||||
dependencies:
|
||||
lru-cache: 11.5.2
|
||||
lru-cache: 10.4.3
|
||||
minipass: 7.1.3
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
@@ -861,19 +1050,25 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
qified@0.10.1:
|
||||
randombytes@2.1.0:
|
||||
dependencies:
|
||||
hookified: 2.2.0
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
readdirp@5.1.1: {}
|
||||
readdirp@4.1.2: {}
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
requireindex@1.2.0: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
|
||||
safe-buffer@5.2.1: {}
|
||||
|
||||
semver@7.8.5: {}
|
||||
|
||||
serialize-javascript@7.1.1: {}
|
||||
serialize-javascript@6.0.2:
|
||||
dependencies:
|
||||
randombytes: 2.1.0
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
@@ -881,7 +1076,33 @@ snapshots:
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
strip-json-comments@5.0.3: {}
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
string-width@5.1.2:
|
||||
dependencies:
|
||||
eastasianwidth: 0.2.0
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
|
||||
strip-ansi@7.2.0:
|
||||
dependencies:
|
||||
ansi-regex: 6.3.0
|
||||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
||||
supports-color@8.1.1:
|
||||
dependencies:
|
||||
@@ -897,10 +1118,10 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
vue-eslint-parser@10.4.1(eslint@10.12.0(supports-color@8.1.1))(supports-color@8.1.1):
|
||||
vue-eslint-parser@10.4.1(eslint@10.9.1(supports-color@8.1.1))(supports-color@8.1.1):
|
||||
dependencies:
|
||||
debug: 4.4.3(supports-color@8.1.1)
|
||||
eslint: 10.12.0(supports-color@8.1.1)
|
||||
eslint: 10.9.1(supports-color@8.1.1)
|
||||
eslint-scope: 9.1.2
|
||||
eslint-visitor-keys: 5.0.1
|
||||
espree: 11.2.0
|
||||
@@ -915,6 +1136,39 @@ snapshots:
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
workerpool@10.0.3: {}
|
||||
workerpool@9.3.4: {}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
wrap-ansi@8.1.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
yargs-unparser@2.0.0:
|
||||
dependencies:
|
||||
camelcase: 6.3.0
|
||||
decamelize: 4.0.0
|
||||
flat: 5.0.2
|
||||
is-plain-obj: 2.1.0
|
||||
|
||||
yargs@17.7.3:
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
escalade: 3.2.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
string-width: 4.2.3
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
1
.github/workflows/packager.io.yaml
vendored
1
.github/workflows/packager.io.yaml
vendored
@@ -22,6 +22,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- debian:11
|
||||
- debian:12
|
||||
- debian:13
|
||||
- el:9
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -107,7 +107,6 @@
|
||||
|
||||
# Node
|
||||
**/node_modules
|
||||
/.vitest
|
||||
yarn-error.log
|
||||
.yarn/cache
|
||||
/.pnpm-store
|
||||
@@ -142,6 +141,6 @@ schema.graphql
|
||||
/.claude/skills
|
||||
/.claude/settings.local.json
|
||||
|
||||
# CodeGraph
|
||||
# Codegraph
|
||||
/.codegraph/
|
||||
/.mcp.json
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
# Ensures that all precompiled gems in Gemfile.lock are available for every platform
|
||||
# Zammad is built for (packager.io, Docker, CI, development machines), so that none of them
|
||||
# falls back to compiling its native extension from source.
|
||||
#
|
||||
# .gitlab/check_native_gem_platforms.rb [path/to/Gemfile.lock]
|
||||
|
||||
require 'bundler'
|
||||
|
||||
class CheckNativeGemPlatforms
|
||||
|
||||
# `ruby` is the fallback for all unlisted platforms. Bundler silently drops it when a new gem
|
||||
# is added to the Gemfile, which would break installations on those platforms.
|
||||
REQUIRED_PLATFORMS = %w[ruby x86_64-linux-gnu aarch64-linux-gnu x86_64-darwin arm64-darwin].freeze
|
||||
|
||||
# An update can leave only the source variant of a gem in the lockfile, e.g. when its precompiled
|
||||
# gems are not published yet. Listing the gems keeps them checked even then.
|
||||
PRECOMPILED_GEMS = %w[ffi google-protobuf nokogiri pg sass-embedded].freeze
|
||||
|
||||
def self.run(lockfile_path)
|
||||
new(lockfile_path).run
|
||||
end
|
||||
|
||||
def initialize(lockfile_path)
|
||||
@lockfile = Bundler::LockfileParser.new(File.read(lockfile_path))
|
||||
@errors = []
|
||||
end
|
||||
|
||||
def run
|
||||
puts 'Checking native gem platforms in Gemfile.lock…'
|
||||
|
||||
check_required_platforms
|
||||
check_precompiled_gems
|
||||
|
||||
if @errors.any?
|
||||
puts(@errors.map { |error| " #{error}" })
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts " #{@lockfile.platforms.size} platforms present, #{precompiled_gems.size} precompiled gems (#{precompiled_gems.keys.sort.join(', ')}) available for all #{binary_platforms.size} binary platforms."
|
||||
puts 'done.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_required_platforms
|
||||
platforms = @lockfile.platforms.map(&:to_s)
|
||||
|
||||
(REQUIRED_PLATFORMS - platforms).each do |platform|
|
||||
@errors << "Platform '#{platform}' is missing, restore it with: bundle lock --add-platform #{platform}"
|
||||
end
|
||||
end
|
||||
|
||||
def check_precompiled_gems
|
||||
precompiled_gems.each do |name, variants|
|
||||
# This script runs without ActiveSupport, so Array#exclude? is not available.
|
||||
@errors << "#{name} is a precompiled gem, add it to PRECOMPILED_GEMS in #{__FILE__}." if !PRECOMPILED_GEMS.include?(name) # rubocop:disable Rails/NegateInclude
|
||||
|
||||
binary_platforms.each do |platform|
|
||||
next if variants.any? { |spec| binary?(spec) && Gem::Platform.new(spec.platform) === platform } # rubocop:disable Style/CaseEquality
|
||||
|
||||
@errors << "#{name} #{variants.first.version} has no precompiled gem for #{platform}#{' and would need a Rust toolchain' if rust?(variants)}."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# A gem counts as precompiled if it is listed, or ships at least one platform variant. Rust-based
|
||||
# gems count even without either, their source variant is recognizable by its rb_sys dependency.
|
||||
def precompiled_gems
|
||||
@precompiled_gems ||= @lockfile.specs.group_by(&:name).select do |name, variants|
|
||||
PRECOMPILED_GEMS.include?(name) || variants.any? { |spec| binary?(spec) } || rust?(variants)
|
||||
end
|
||||
end
|
||||
|
||||
def rust?(variants)
|
||||
variants.any? { |spec| !binary?(spec) && spec.dependencies.any? { |dependency| dependency.name == 'rb_sys' } }
|
||||
end
|
||||
|
||||
def binary?(spec)
|
||||
spec.platform != Gem::Platform::RUBY
|
||||
end
|
||||
|
||||
def binary_platforms
|
||||
@binary_platforms ||= @lockfile.platforms.reject { |platform| platform == Gem::Platform::RUBY }
|
||||
end
|
||||
end
|
||||
|
||||
CheckNativeGemPlatforms.run(ARGV[0] || File.expand_path('../Gemfile.lock', __dir__))
|
||||
@@ -1,5 +0,0 @@
|
||||
# Certain jobs use no artifacts of the earlier stages. Without this, GitLab downloads all of
|
||||
# them, and retrying such a job after the database dumps expired fails it with
|
||||
# `missing_dependency_failure`.
|
||||
.no_artifact_dependencies:
|
||||
dependencies: []
|
||||
@@ -4,6 +4,9 @@ default:
|
||||
tags:
|
||||
- docker
|
||||
|
||||
# Most jobs execute ruby commands, so take that as default.
|
||||
cache: !reference [.cache, read_only_ruby]
|
||||
|
||||
# Artifacts are stored for failed jobs
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
@@ -15,20 +18,16 @@ default:
|
||||
|
||||
interruptible: true
|
||||
|
||||
# Initialize application env
|
||||
before_script:
|
||||
- !reference [.scripts, source_rvm]
|
||||
- !reference [.scripts, bundle_install]
|
||||
- !reference [.scripts, configure_environment]
|
||||
|
||||
after_script:
|
||||
- .gitlab/environment_info.sh > log/environment_info.log
|
||||
# Copy logs from other containers to store them as artifacts.
|
||||
- cp /builds/*.log log/ || true
|
||||
# Print recorded test runtimes for script/build/update_test_timings.rb. The script is
|
||||
# missing if an older commit is checked out, e.g. in rspec:migration.
|
||||
- if [ -x .gitlab/print_test_timings.sh ]; then .gitlab/print_test_timings.sh; fi
|
||||
# Logs and screenshots are only needed for failed jobs, see .artifacts_with_test_report.
|
||||
- if [ "$CI_JOB_STATUS" = success ]; then rm -rf log/*.log tmp/screenshot* tmp/playwright-traces; fi
|
||||
|
||||
# For jobs running the application's Ruby code: read the gem cache and initialize the
|
||||
# application environment.
|
||||
.template_ruby:
|
||||
cache: !reference [.cache, read_only_ruby]
|
||||
before_script:
|
||||
- !reference [.scripts, source_rvm]
|
||||
- !reference [.scripts, bundle_install]
|
||||
- !reference [.scripts, configure_environment]
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# Building blocks for `needs:`, combined per job:
|
||||
#
|
||||
# needs:
|
||||
# - !reference [.needs, ruby]
|
||||
# - !reference [.needs, lint]
|
||||
#
|
||||
# A job with `needs:` starts as soon as the listed jobs have finished, instead of waiting
|
||||
# for all jobs of the earlier stages, and downloads the artifacts of the listed jobs only.
|
||||
#
|
||||
# Jobs of the test and browser stages need `lint`, so that none of them is started for a
|
||||
# commit that fails linting. The manual lint jobs are not listed, a job needing them
|
||||
# would wait for them forever.
|
||||
#
|
||||
# Jobs with rules of their own are optional, because filtered pipelines ($JOB_FILTER,
|
||||
# $BROWSER_TEST_FILTER) do not contain them, and needing a job that is missing from the
|
||||
# pipeline fails its creation. Without 'write database dumps', .gitlab/init_database.sh
|
||||
# initializes the database from scratch.
|
||||
.needs:
|
||||
ruby:
|
||||
- job: 'write cache: ruby'
|
||||
artifacts: false
|
||||
nodejs:
|
||||
- job: 'write cache: nodejs'
|
||||
artifacts: false
|
||||
database:
|
||||
- job: 'write database dumps'
|
||||
optional: true
|
||||
assets:
|
||||
- job: 'assets:build'
|
||||
lint:
|
||||
- job: 'lint: shellcheck'
|
||||
artifacts: false
|
||||
optional: true
|
||||
- job: 'lint: i18n & rails'
|
||||
artifacts: false
|
||||
optional: true
|
||||
- job: 'lint: ruby & security'
|
||||
artifacts: false
|
||||
optional: true
|
||||
- job: 'lint: markdown, coffee & css'
|
||||
artifacts: false
|
||||
optional: true
|
||||
- job: 'lint: js'
|
||||
artifacts: false
|
||||
optional: true
|
||||
- job: 'lint: secret_detection'
|
||||
artifacts: false
|
||||
optional: true
|
||||
@@ -1,65 +1,5 @@
|
||||
# Rules decide whether a job is added to a pipeline at all, and if so, whether it
|
||||
# starts automatically, waits for a manual start, and may fail. Entries are
|
||||
# evaluated from top to bottom, the first matching one wins.
|
||||
#
|
||||
# This file provides two kinds of building blocks, which must not be confused:
|
||||
#
|
||||
# 1. Fragments below `.rule_fragments` - *partial* rules lists, spliced into the
|
||||
# list of a job with `!reference`:
|
||||
#
|
||||
# rules:
|
||||
# - !reference [.rule_fragments, main_repository_only]
|
||||
# - !reference [.rule_fragments, variable_filters]
|
||||
# - if: $SOMETHING
|
||||
# when: on_success
|
||||
# - !reference [.rule_fragments, then_manual]
|
||||
#
|
||||
# Fragments have no `rules:` key of their own, so using one in `extends:` splices
|
||||
# its keys into the job and GitLab rejects it - never use them there.
|
||||
#
|
||||
# 2. Rule sets named `.job_rules_*` - a *complete* rules list, used with
|
||||
# `extends:`. There is deliberately only one of them, see below.
|
||||
#
|
||||
# Conventions:
|
||||
#
|
||||
# * A `.job_rules_*` set must end in an unconditional entry whose `when` is not
|
||||
# `never`, so that extending it always yields a job that runs somewhere.
|
||||
# Anything that only ever excludes (like `main_repository_only`), or that ends
|
||||
# in `when: never`, has to be a fragment. This is the mistake to worry about:
|
||||
# unlike a fragment in `extends:`, which GitLab rejects, a set that can only
|
||||
# exclude is accepted without error or warning and the job is simply never
|
||||
# created in any pipeline.
|
||||
# * A job's own `rules:` replaces every inherited list rather than merging with
|
||||
# it. Never add a rule set to a job or template that already inherits one -
|
||||
# the reader cannot see which of the two wins. Write the deviating list at the
|
||||
# job as `rules:` instead.
|
||||
# * `then_*` fragments contain the closing, unconditional entry of a list and
|
||||
# therefore appear last and exactly once. Every other fragment contributes
|
||||
# only conditional entries and can be placed anywhere before that.
|
||||
# * Order within a list: guards (`main_repository_only`) first, then the pipeline
|
||||
# filters (`variable_filters`), then the job's own conditions, then the closing
|
||||
# entry. A guard placed further down is dead code.
|
||||
# * Spell out `when:` in every entry, including `when: on_success`. An entry
|
||||
# without it reads as if it would not start the job.
|
||||
# * `$JOB_FILTER` is matched against `$CI_JOB_NAME`, which for `parallel` and
|
||||
# `matrix` jobs contains the shard suffix (e.g. `rspec 1/8`), so those jobs can
|
||||
# only be selected with their full name.
|
||||
#
|
||||
# Every job needs rules of its own to honour $JOB_FILTER: `default:` cannot carry
|
||||
# `rules:`, and a job without any `rules:` runs unconditionally. The few jobs that
|
||||
# want exactly that - because filtered pipelines still need their cache or their
|
||||
# artifacts - say so in a comment.
|
||||
|
||||
.rule_fragments:
|
||||
|
||||
# Never run in forks, e.g. because project specific secrets or runners are needed.
|
||||
main_repository_only:
|
||||
- if: $CI_PROJECT_PATH != "zammad/zammad"
|
||||
when: never
|
||||
|
||||
# Honour the JOB_FILTER and BROWSER_TEST_FILTER push variables, which reduce a
|
||||
# pipeline to a single job (see workflow.yml). A matching JOB_FILTER *forces*
|
||||
# the job to run, whatever its own conditions say.
|
||||
.job_rules:
|
||||
# Allow filtering CI pipelines with JOB_FILTER and BROWSER_TEST_FILTER push variabales.
|
||||
variable_filters:
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: never
|
||||
@@ -68,51 +8,22 @@
|
||||
- if: $JOB_FILTER && $JOB_FILTER != $CI_JOB_NAME
|
||||
when: never
|
||||
|
||||
# Like variable_filters, but without forcing: JOB_FILTER can only *select* the
|
||||
# job, its own conditions still have to match as well. For jobs that must not
|
||||
# become startable outside of the pipelines they were written for.
|
||||
variable_filters_without_force:
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: never
|
||||
- if: $JOB_FILTER && $JOB_FILTER != $CI_JOB_NAME
|
||||
when: never
|
||||
.job_rules_default:
|
||||
rules:
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- when: on_success
|
||||
|
||||
# Closing entry: offer a manual start and never block the pipeline. `allow_failure`
|
||||
# has to be spelled out for manual jobs - in `rules:` it defaults to `false`,
|
||||
# which would turn the manual job into a blocking one.
|
||||
then_manual:
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
# Closing entry for jobs whose signal is wanted regularly, but which are too slow
|
||||
# or too dependent on third parties to gate every commit: they run in the
|
||||
# scheduled pipelines and can be started manually everywhere else.
|
||||
then_manual_unless_scheduled:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: on_success
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
# Closing entry for secondary test lanes that cover the same specs as a primary
|
||||
# lane (e.g. Firefox next to Chrome): in merge requests they are advisory and
|
||||
# only started on demand, on branches they run automatically.
|
||||
then_manual_in_mr:
|
||||
.job_rules_manual_in_mr:
|
||||
rules:
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
|
||||
# Closing entry for the capybara:filtered:* jobs, which exist only to loop a
|
||||
# single spec selected with BROWSER_TEST_FILTER. JOB_FILTER is deliberately not
|
||||
# honoured here, BROWSER_TEST_FILTER is the selector for these jobs.
|
||||
then_browser_test_filter_only:
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: always
|
||||
- when: never
|
||||
|
||||
# The one and only rule set: for jobs that just have to honour the pipeline filters.
|
||||
# Everything else writes its own `rules:`, see the header.
|
||||
.job_rules_default:
|
||||
.job_rules_integration:
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^private/
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
|
||||
@@ -32,12 +32,7 @@
|
||||
# gem and the package.json pin; the driver asserts this at startup
|
||||
# (spec/support/capybara/playwright_driver.rb), so a gem bump fails fast
|
||||
# here instead of at the server's version handshake.
|
||||
PLAYWRIGHT_VERSION: '1.63.0'
|
||||
|
||||
.variables_playwright_firefox:
|
||||
extends: .variables_playwright
|
||||
variables:
|
||||
SELENIUM_BROWSER: 'playwright_firefox'
|
||||
PLAYWRIGHT_VERSION: '1.62.1'
|
||||
|
||||
.variables_proxy:
|
||||
variables:
|
||||
@@ -89,13 +84,14 @@
|
||||
alias: selenium-firefox
|
||||
|
||||
playwright:
|
||||
name: $CI_REGISTRY/docker/zammad-playwright:latest
|
||||
name: $CI_REGISTRY/docker/zammad-playwright:stable
|
||||
alias: playwright
|
||||
variables:
|
||||
# Lets the server accept the Chromium args the driver passes via the
|
||||
# endpoint's launch-options (see playwright_driver.rb); it strips them
|
||||
# otherwise. Opt-in because it also unlocks executablePath - fine here,
|
||||
# as the server is only reachable from this job.
|
||||
# as the server is only reachable from this job. See
|
||||
# docker/zammad-playwright!2.
|
||||
PLAYWRIGHT_UNSAFE: '1'
|
||||
|
||||
redis:
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# For the jobs writing JUnit reports (see CI_JUNIT_REPORT_DIR): upload the artifacts of
|
||||
# passed jobs, too, so that the test reports of pipelines and merge requests contain
|
||||
# all tests and not only the failed ones. The default after_script removes the logs and
|
||||
# screenshots of passed jobs, so that only the report of these is uploaded.
|
||||
.artifacts_with_test_report:
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: always
|
||||
paths:
|
||||
- tmp/screenshot*
|
||||
- tmp/screenshots/*
|
||||
# Recorded by spec/support/capybara/playwright_traces.rb in the Playwright lanes.
|
||||
- tmp/playwright-traces/*
|
||||
- log/*.log
|
||||
reports:
|
||||
junit: tmp/junit/*.xml
|
||||
@@ -29,16 +29,6 @@ variables:
|
||||
# Record the runtime of each test file, used to keep .gitlab/ci/timings/ up to date.
|
||||
CI_TEST_TIMINGS_PATH: 'tmp/test_timings/timings.yml'
|
||||
|
||||
# Write JUnit reports for the test reports of GitLab, see spec/support/junit_report.rb and
|
||||
# .artifacts_with_test_report.
|
||||
CI_JUNIT_REPORT_DIR: 'tmp/junit'
|
||||
|
||||
# Branches that are only ever built through their merge request: feature branches of
|
||||
# developers (private/*) and branches created by automation (cherry-picks, reverts,
|
||||
# dependency updates). Used in rules with `=~`, which requires the pattern to be
|
||||
# enclosed in forward slashes.
|
||||
CI_ZAMMAD_MR_ONLY_BRANCH_PATTERN: '/^(private|cherry-pick-|revert-|renovate|dependabot)/'
|
||||
|
||||
# Compile assets only once.
|
||||
CI_SKIP_ASSETS_PRECOMPILE: 'true'
|
||||
# Avoid unnecessary DB resets.
|
||||
|
||||
@@ -9,6 +9,6 @@ workflow:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
|
||||
when: never
|
||||
# Don't create branch pipelines for pushes to private branches (as there will also be a MR for them).
|
||||
- if: $CI_COMMIT_BRANCH =~ $CI_ZAMMAD_MR_ONLY_BRANCH_PATTERN && $CI_PIPELINE_SOURCE == "push"
|
||||
- if: $CI_COMMIT_BRANCH =~ /^(private|cherry-pick-|revert-|renovate|dependabot)/ && $CI_PIPELINE_SOURCE == "push"
|
||||
when: never
|
||||
- when: always
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
image:
|
||||
name: alpine/curl:latest
|
||||
entrypoint: ['']
|
||||
cache: []
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
# Don't apply job filter here.
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /weblate-merge$/ && $CI_MERGE_REQUEST_SQUASH_ON_MERGE == "true"'
|
||||
when: on_success
|
||||
- when: never
|
||||
before_script: []
|
||||
script:
|
||||
- echo "⚠️ Disabling squash option for this MR..."
|
||||
- |
|
||||
@@ -22,7 +20,6 @@
|
||||
'push translations update commit':
|
||||
stage: automate
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
# Don't apply job filter here.
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_MESSAGE =~ /Translations update from translations[.]zammad[.]org/
|
||||
when: always
|
||||
@@ -79,12 +76,11 @@
|
||||
# GITLAB_API_TOKEN - read_api token for the MR query (defaults to RENOVATE_TOKEN)
|
||||
'dependency digest':
|
||||
stage: automate
|
||||
cache: []
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- !reference [.rule_fragments, variable_filters_without_force]
|
||||
# Runs only when explicitly selected via JOB_FILTER, see the comment above.
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: never
|
||||
- if: $JOB_FILTER == $CI_JOB_NAME && ($CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web") && $CI_COMMIT_REF_NAME == "develop"
|
||||
when: on_success
|
||||
- when: never
|
||||
variables:
|
||||
GIT_DEPTH: '500'
|
||||
@@ -105,12 +101,15 @@
|
||||
image:
|
||||
name: ghcr.io/updatecli/updatecli:latest
|
||||
entrypoint: ['']
|
||||
cache: []
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- !reference [.rule_fragments, variable_filters_without_force]
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: never
|
||||
- if: $JOB_FILTER && $JOB_FILTER != $CI_JOB_NAME
|
||||
when: never
|
||||
- if: ($CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web") && $CI_COMMIT_REF_NAME == "develop"
|
||||
when: on_success
|
||||
- when: never
|
||||
before_script: []
|
||||
script:
|
||||
- updatecli pipeline apply --config .dev/updatecli.yaml --values .dev/updatecli-values-enable-gitlab.yaml
|
||||
after_script: []
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
.template_browser-core_capybara:
|
||||
stage: browser
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .job_rules_default
|
||||
- .tags_docker_low_concurrency
|
||||
- .artifacts_with_test_report
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, database]
|
||||
- !reference [.needs, assets]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 40 minutes
|
||||
script:
|
||||
- !reference [.scripts, zammad_ci_test_prepare]
|
||||
- bundle exec rspec --require ./spec/rspec_extensions.rb --fail-fast -t ~integration -t ~searchindex spec/system
|
||||
@@ -27,11 +19,8 @@
|
||||
.template_browser-core_capybara_firefox:
|
||||
extends:
|
||||
- .template_browser-core_capybara
|
||||
- .job_rules_manual_in_mr
|
||||
- .variables_selenium_firefox
|
||||
# Chrome covers the same specs, so the Firefox lane is advisory in merge requests.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, selenium-firefox]
|
||||
@@ -45,12 +34,13 @@
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, playwright]
|
||||
- !reference [.services, redis]
|
||||
|
||||
.template_browser-core_capybara_playwright_firefox:
|
||||
extends:
|
||||
- .template_browser-core_capybara
|
||||
- .variables_playwright_firefox
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, playwright]
|
||||
- !reference [.services, redis]
|
||||
# A job-level artifacts block replaces the global default one entirely -
|
||||
# repeat its paths and add the traces recorded by playwright_traces.rb.
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- tmp/screenshot*
|
||||
- tmp/screenshots/*
|
||||
- tmp/playwright-traces/*
|
||||
- log/*.log
|
||||
|
||||
@@ -8,25 +8,14 @@ capybara:firefox:
|
||||
- .template_browser-core_capybara_firefox
|
||||
parallel: 16
|
||||
|
||||
# Shadow lane for the Playwright driver evaluation: runs automatically on develop
|
||||
# and in scheduled pipelines next to capybara:chrome, is only started on demand
|
||||
# in merge requests, and never gates - allow_failure keeps a red lane from
|
||||
# blocking the pipeline.
|
||||
# Shadow lane for the Playwright driver evaluation: runs automatically in every
|
||||
# pipeline next to capybara:chrome, so each commit yields a comparable pair,
|
||||
# and never gates - allow_failure keeps a red lane from blocking the pipeline.
|
||||
capybara:playwright:
|
||||
extends:
|
||||
- .template_browser-core_capybara_playwright
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
allow_failure: true
|
||||
parallel: 16
|
||||
|
||||
# Evaluation lane for Playwright's Firefox, not decided yet whether it stays -
|
||||
# only started on demand and never gates.
|
||||
capybara:firefox:playwright:
|
||||
extends:
|
||||
- .template_browser-core_capybara_playwright_firefox
|
||||
# Playwright evaluation is paused - job disabled in CI.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual]
|
||||
parallel: 16
|
||||
- when: never
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
.template_browser-core_capybara_es:
|
||||
extends:
|
||||
- .template_browser-core_capybara
|
||||
timeout: 30 minutes
|
||||
script:
|
||||
- !reference [.scripts, zammad_ci_test_prepare]
|
||||
- bundle exec rspec --require ./spec/rspec_extensions.rb --fail-fast -t ~integration -t searchindex spec/system
|
||||
@@ -20,10 +19,6 @@
|
||||
extends:
|
||||
- .template_browser-core_capybara_es
|
||||
- .variables_selenium_firefox
|
||||
# Like the non-ES Firefox lane: advisory in merge requests.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, elasticsearch]
|
||||
@@ -39,6 +34,16 @@
|
||||
- !reference [.services, elasticsearch]
|
||||
- !reference [.services, playwright]
|
||||
- !reference [.services, redis]
|
||||
# A job-level artifacts block replaces the global default one entirely -
|
||||
# repeat its paths and add the traces recorded by playwright_traces.rb.
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- tmp/screenshot*
|
||||
- tmp/screenshots/*
|
||||
- tmp/playwright-traces/*
|
||||
- log/*.log
|
||||
|
||||
capybara:es:chrome:
|
||||
extends:
|
||||
@@ -47,6 +52,7 @@ capybara:es:chrome:
|
||||
capybara:es:firefox:
|
||||
extends:
|
||||
- .template_browser-core_capybara_firefox_es
|
||||
- .job_rules_manual_in_mr
|
||||
|
||||
# Shadow lane for the Playwright driver evaluation, twin of capybara:es:chrome:
|
||||
# the searchindex-tagged system specs are excluded from the main capybara
|
||||
@@ -54,7 +60,7 @@ capybara:es:firefox:
|
||||
capybara:es:playwright:
|
||||
extends:
|
||||
- .template_browser-core_capybara_playwright_es
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
allow_failure: true
|
||||
# Playwright evaluation is paused - job disabled in CI.
|
||||
rules:
|
||||
- when: never
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
.template_capybara_filtered:
|
||||
# This template has to be listed *after* the browser template in `extends:`: its
|
||||
# `rules:` and `script:` deliberately replace the inherited ones (lists are
|
||||
# replaced, not merged).
|
||||
rules:
|
||||
- !reference [.rule_fragments, then_browser_test_filter_only]
|
||||
# Looping a single spec takes much longer than a regular slice of the suite.
|
||||
timeout: 2 hours
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: always
|
||||
- when: never
|
||||
variables:
|
||||
BROWSER_TEST_FILTER_LOOP_COUNT: 50
|
||||
script:
|
||||
@@ -44,6 +41,9 @@ capybara:filtered:playwright:
|
||||
- .template_browser-core_capybara_playwright
|
||||
- .template_capybara_filtered
|
||||
- .variables_auth
|
||||
# Playwright evaluation is paused - job disabled in CI.
|
||||
rules:
|
||||
- when: never
|
||||
services:
|
||||
- !reference [.template_browser-core_capybara_playwright, services]
|
||||
# Also add containers for integration tests here.
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
capybara:integration:other:
|
||||
extends:
|
||||
- .template_browser-core_capybara_chrome
|
||||
- .job_rules_manual_in_mr
|
||||
- .variables_idoit
|
||||
- .variables_proxy
|
||||
timeout: 20 minutes
|
||||
# These tests need third party service containers and are slow, so they are
|
||||
# advisory in merge requests.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, selenium-chrome]
|
||||
@@ -23,13 +18,8 @@ capybara:integration:other:
|
||||
capybara:integration:saml:
|
||||
extends:
|
||||
- .template_browser-core_capybara_chrome
|
||||
- .job_rules_manual_in_mr
|
||||
- .variables_auth
|
||||
timeout: 20 minutes
|
||||
# These tests need third party service containers and are slow, so they are
|
||||
# advisory in merge requests.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, selenium-chrome]
|
||||
@@ -42,12 +32,7 @@ capybara:integration:saml:
|
||||
.template_capybara_integration_otrs:
|
||||
extends:
|
||||
- .template_browser-core_capybara_chrome
|
||||
timeout: 20 minutes
|
||||
# These tests need third party service containers and are slow, so they are
|
||||
# advisory in merge requests.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_in_mr]
|
||||
- .job_rules_manual_in_mr
|
||||
variables:
|
||||
IMPORT_OTRS_ENDPOINT: "http://zammad-ci-otrsimport-app/otrs/public.pl?Action=ZammadMigrator"
|
||||
services:
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
'write database dumps':
|
||||
stage: lint
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .job_rules_default
|
||||
timeout: 6 minutes
|
||||
needs: !reference [.needs, ruby]
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
variables:
|
||||
|
||||
@@ -3,18 +3,16 @@
|
||||
stage: lint
|
||||
extends:
|
||||
- .job_rules_default
|
||||
# Start right away: the caches written in the pre stage only change with the lock
|
||||
# files, so they are usually filled already.
|
||||
needs: []
|
||||
|
||||
.template_lint_rails:
|
||||
extends:
|
||||
- .template_lint
|
||||
- .template_ruby
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
before_script:
|
||||
- !reference [.template_ruby, before_script]
|
||||
- !reference [.scripts, source_rvm]
|
||||
- !reference [.scripts, bundle_install]
|
||||
- !reference [.scripts, configure_environment]
|
||||
- !reference [.scripts, zammad_db_init]
|
||||
variables:
|
||||
ZAMMAD_SAFE_MODE: 1
|
||||
@@ -25,8 +23,10 @@
|
||||
- .template_lint
|
||||
timeout: 2 minutes
|
||||
image: koalaman/shellcheck-alpine:stable
|
||||
cache: []
|
||||
before_script: []
|
||||
script:
|
||||
- find . \( -name vendor -o -name node_modules \) -prune -o \( -name '*.sh' -o -name functions \) -print0 | xargs -0 shellcheck -S warning
|
||||
- shellcheck -S warning $(find . -name "*.sh" -o -name "functions" | egrep -v "/vendor|node_modules/")
|
||||
after_script: []
|
||||
|
||||
'lint: i18n & rails':
|
||||
@@ -49,7 +49,6 @@
|
||||
'lint: ruby & security':
|
||||
extends:
|
||||
- .template_lint
|
||||
- .template_ruby
|
||||
timeout: 10 minutes
|
||||
before_script:
|
||||
- !reference [.scripts, source_rvm]
|
||||
@@ -67,10 +66,8 @@
|
||||
- echo "bundler-audit security check…"
|
||||
- gem exec bundle-audit update
|
||||
- gem exec bundle-audit
|
||||
- echo "Native gem platforms check…"
|
||||
- .gitlab/check_native_gem_platforms.rb
|
||||
- echo "Brakeman security check…"
|
||||
- bin/brakeman -o /dev/stdout -o tmp/brakeman-report.html
|
||||
- bundle exec brakeman -o /dev/stdout -o tmp/brakeman-report.html
|
||||
- echo "Checking if yard can generate documentation…"
|
||||
- bundle exec yard --no-output --no-progress
|
||||
- echo "Verify that vendored gems are not world writable"
|
||||
@@ -127,8 +124,8 @@
|
||||
timeout: 2 minutes
|
||||
allow_failure: true
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- when: manual
|
||||
script:
|
||||
- bundle exec rake zammad:ci:bundle:orphaned 6
|
||||
|
||||
@@ -137,8 +134,11 @@
|
||||
- .template_lint_rails
|
||||
timeout: 4 minutes
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_unless_scheduled]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE != "schedule"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
script:
|
||||
- bundle exec rake zammad:ci:update_ci_variables
|
||||
|
||||
@@ -147,10 +147,12 @@
|
||||
image:
|
||||
name: 'zricethezav/gitleaks:latest'
|
||||
entrypoint: ['']
|
||||
cache: []
|
||||
timeout: 2 minutes
|
||||
variables:
|
||||
# Go uses all CPUs by default.
|
||||
GOMAXPROCS: 1
|
||||
before_script: []
|
||||
script:
|
||||
# Deep enough to contain the pipeline's base commit, so only the new commits are scanned.
|
||||
# Setting GIT_DEPTH for this job has no effect, the checkout keeps the depth of 1.
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# Write CI cache once for faster runs
|
||||
# No `rules:` on purpose: filtered pipelines ($JOB_FILTER, $BROWSER_TEST_FILTER)
|
||||
# need the cache, too.
|
||||
'write cache: ruby':
|
||||
stage: pre
|
||||
cache: !reference [.cache, read_write_ruby]
|
||||
@@ -10,20 +8,20 @@
|
||||
- !reference [.scripts, bundle_install]
|
||||
after_script: []
|
||||
|
||||
# No `rules:` on purpose, see above.
|
||||
'write cache: nodejs':
|
||||
stage: pre
|
||||
cache: !reference [.cache, read_write_nodejs]
|
||||
before_script: []
|
||||
script:
|
||||
- !reference [.scripts, pnpm_install_all]
|
||||
after_script: []
|
||||
|
||||
'push to github':
|
||||
stage: pre
|
||||
cache: []
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
# Don't apply job filter here.
|
||||
- if: $CI_COMMIT_REF_NAME =~ $CI_ZAMMAD_MR_ONLY_BRANCH_PATTERN
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^(private|cherry-pick-|revert-|renovate|dependabot)/
|
||||
when: never
|
||||
- when: always
|
||||
before_script:
|
||||
@@ -41,8 +39,8 @@
|
||||
stage: pre
|
||||
tags:
|
||||
- push-to-ftp
|
||||
cache: []
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
# Don't apply job filter here.
|
||||
- if: $CI_COMMIT_TAG
|
||||
when: always
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
# Build/update docker image and publish it to the GitLab container registry.
|
||||
- |
|
||||
echo "Build docker image…"
|
||||
echo "$CI_JOB_TOKEN" | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
|
||||
docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||
echo -e "\\e[0Ksection_start:`date +%s`:docker_build[collapsed=true]\\r\\e[0Kdocker build"
|
||||
if [ ! "${SKIP_DOCKER_BUILD}" ]
|
||||
then
|
||||
@@ -231,6 +231,7 @@
|
||||
tags:
|
||||
- review-apps
|
||||
stage: pre
|
||||
cache: []
|
||||
variables:
|
||||
SERVER_NAME: review-apps.dc.zammad.com
|
||||
APP_SLUG: $CI_COMMIT_REF_SLUG
|
||||
@@ -241,10 +242,7 @@
|
||||
environment:
|
||||
name: ${APP_NAME}
|
||||
url: https://${APP_FQDN}#getting_started/auto_wizard
|
||||
# Deploying, stopping and restarting the same review app must not overlap.
|
||||
resource_group: ${APP_NAME}
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- if: $CI_MERGE_REQUEST_ID
|
||||
when: manual
|
||||
allow_failure: true
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
.template_api_client:
|
||||
stage: test
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .job_rules_default
|
||||
- .tags_docker_low_concurrency
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, redis]
|
||||
@@ -20,15 +15,10 @@ api_client:php:
|
||||
extends:
|
||||
- .template_api_client
|
||||
variables:
|
||||
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.cache/composer"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_URL: "http://localhost:3000"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_USERNAME: "admin@example.com"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_PASSWORD: "test"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_DEBUG: 0
|
||||
cache:
|
||||
key: "composer-api-client-php"
|
||||
paths:
|
||||
- .cache/composer/
|
||||
script:
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- echo -e "\\e[0Ksection_start:`date +%s`:zammad_ci_test_start[collapsed=true]\\r\\e[0Kbundle exec rake zammad:ci:test:start"
|
||||
@@ -45,10 +35,6 @@ api_client:php:
|
||||
api_client:ruby:
|
||||
extends:
|
||||
- .template_api_client
|
||||
cache:
|
||||
key: "bundle-api-client-ruby"
|
||||
paths:
|
||||
- .cache/bundle/
|
||||
script:
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- cp contrib/auto_wizard_test.json auto_wizard.json
|
||||
@@ -57,7 +43,6 @@ api_client:ruby:
|
||||
- echo -e "\\e[0Ksection_end:`date +%s`:zammad_ci_test_start\\r\\e[0K"
|
||||
- git clone https://github.com/zammad/zammad-api-client-ruby.git
|
||||
- cd zammad-api-client-ruby
|
||||
- export BUNDLE_PATH="$CI_PROJECT_DIR/.cache/bundle"
|
||||
- bundle update --bundler
|
||||
- bundle install -j $(nproc)
|
||||
- bundle exec rspec
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
assets:build:
|
||||
stage: test
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, nodejs]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
# No `rules:` on purpose: the browser jobs of a filtered pipeline ($JOB_FILTER,
|
||||
# $BROWSER_TEST_FILTER) still need the assets built here, as the specs
|
||||
# themselves skip the compilation ($CI_SKIP_ASSETS_PRECOMPILE).
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .no_artifact_dependencies
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
artifacts:
|
||||
@@ -39,14 +28,7 @@ assets:build:
|
||||
assets:build:pwa:
|
||||
stage: test
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .job_rules_default
|
||||
- .no_artifact_dependencies
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, nodejs]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
cache: !reference [.cache, read_only_full]
|
||||
|
||||
@@ -6,12 +6,11 @@
|
||||
# The job only needs the repository checkout. Without this, it implicitly
|
||||
# depends on the artifacts of all earlier stages, so retrying it after those
|
||||
# artifacts expired fails with `missing_dependency_failure`.
|
||||
needs:
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
needs: []
|
||||
variables:
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
DEVCONTAINERS_CLI_VERSION: '0.89.0'
|
||||
DEVCONTAINERS_CLI_VERSION: '0.87.0'
|
||||
cache: []
|
||||
before_script:
|
||||
- apk add --no-cache docker-cli docker-cli-buildx docker-compose
|
||||
after_script: []
|
||||
@@ -24,5 +23,8 @@
|
||||
--config .devcontainer/$VARIANT/devcontainer.json
|
||||
--frozen-lockfile
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual_unless_scheduled]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: on_success
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
.template_docker:
|
||||
image: docker
|
||||
stage: test
|
||||
extends:
|
||||
- .no_artifact_dependencies
|
||||
needs:
|
||||
- !reference [.needs, lint]
|
||||
timeout: 30 minutes
|
||||
interruptible: false
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_REF_NAME =~ $CI_ZAMMAD_MR_ONLY_BRANCH_PATTERN
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_REF_NAME =~ /^(private|cherry-pick-|revert-|renovate|dependabot)/
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
services: []
|
||||
cache: []
|
||||
variables:
|
||||
ZAMMAD_IMAGE_TAG: "ci-${CI_JOB_ID}-${CI_COMMIT_SHORT_SHA}"
|
||||
ZAMMAD_IMAGE_REPO: "zammad"
|
||||
ZAMMAD_IMAGE: "${ZAMMAD_IMAGE_REPO}:${ZAMMAD_IMAGE_TAG}"
|
||||
before_script:
|
||||
- echo "$CI_JOB_TOKEN" | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||
- git clone --depth=1 https://github.com/zammad/zammad-docker-compose.git
|
||||
# Make the stack use the image that was just built.
|
||||
- echo "IMAGE_REPO=${ZAMMAD_IMAGE_REPO}" > zammad-docker-compose/.env
|
||||
|
||||
@@ -2,20 +2,13 @@
|
||||
stage: test
|
||||
extends:
|
||||
- .job_rules_default
|
||||
- .no_artifact_dependencies
|
||||
- .artifacts_with_test_report
|
||||
needs:
|
||||
- !reference [.needs, nodejs]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
cache: !reference [.cache, read_only_nodejs]
|
||||
before_script:
|
||||
- !reference [.scripts, pnpm_install]
|
||||
- !reference [.scripts, pnpm_install_eslint_plugin_zammad]
|
||||
script:
|
||||
# Only run one worker to avoid load peaks affecting other jobs.
|
||||
# Vitest resolves a relative output file against app/frontend, its root.
|
||||
- pnpm test --max-workers=1 --shard $CI_NODE_INDEX/$CI_NODE_TOTAL --reporter=default --reporter=junit --outputFile.junit=$CI_PROJECT_DIR/$CI_JUNIT_REPORT_DIR/vitest.xml
|
||||
- pnpm test --max-workers=1 --shard $CI_NODE_INDEX/$CI_NODE_TOTAL
|
||||
# Stop here, except on the first shard.
|
||||
- "[[ $CI_NODE_INDEX = 1 ]] || exit 0"
|
||||
- echo "Also test eslint-plugin-zammad…"
|
||||
@@ -32,11 +25,6 @@ frontend:cypress:
|
||||
extends:
|
||||
- .job_rules_default
|
||||
- .tags_docker_low_concurrency
|
||||
- .no_artifact_dependencies
|
||||
needs:
|
||||
- !reference [.needs, nodejs]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
cache: !reference [.cache, read_only_nodejs]
|
||||
before_script:
|
||||
- !reference [.scripts, pnpm_install_cypress]
|
||||
|
||||
@@ -3,24 +3,10 @@ include:
|
||||
|
||||
.template_integration:
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .artifacts_with_test_report
|
||||
# These tests partly talk to live third party services. On private branches their
|
||||
# signal is advisory only, so a failure does not block the pipeline.
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^private/
|
||||
when: on_success
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
- .job_rules_integration
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, imap]
|
||||
- !reference [.services, redis]
|
||||
- !reference [.services, memcached]
|
||||
stage: test
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, database]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
.template_integration_es:
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .artifacts_with_test_report
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, redis]
|
||||
- !reference [.services, memcached]
|
||||
- !reference [.services, elasticsearch]
|
||||
stage: test
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, database]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 30 minutes
|
||||
script:
|
||||
- !reference [.scripts, zammad_db_init]
|
||||
- bundle exec rspec --tag searchindex --tag ~type:system
|
||||
@@ -27,8 +19,8 @@ rspec:es:
|
||||
matrix:
|
||||
- ELASTICSEARCH_TAG: [stable, latest]
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
# The lowest supported version is covered in every pipeline.
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $ELASTICSEARCH_TAG == "stable"
|
||||
when: on_success
|
||||
- !reference [.rule_fragments, then_manual_unless_scheduled]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
extends:
|
||||
- .template_integration_otrs
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.rule_fragments, then_manual]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
rspec:integration:otrs:6:
|
||||
extends:
|
||||
|
||||
@@ -5,31 +5,26 @@ rspec:migration:
|
||||
stage: test
|
||||
extends:
|
||||
- .job_rules_default
|
||||
- .artifacts_with_test_report
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 20 minutes
|
||||
cache: !reference [.cache, read_only_ruby]
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, redis]
|
||||
# The database must be initialized by the code of the stable branch, so the database dump
|
||||
# of this pipeline must not be used here.
|
||||
dependencies: []
|
||||
before_script: []
|
||||
script:
|
||||
# First, checkout stable and set it up.
|
||||
- git fetch --depth=1 origin stable-6.0
|
||||
- git checkout FETCH_HEAD
|
||||
- git fetch --unshallow
|
||||
- git checkout stable-6.0
|
||||
- !reference [.scripts, source_rvm]
|
||||
- rvm use $(cat .ruby-version)
|
||||
- rvm use 3.1.3
|
||||
- bundle config set without mysql
|
||||
- !reference [.scripts, bundle_install]
|
||||
- !reference [.scripts, configure_environment]
|
||||
- !reference [.scripts, zammad_db_init]
|
||||
# Then, switch to the current commit, migrate to it and run a few selected tests.
|
||||
- git checkout $CI_COMMIT_SHA
|
||||
- rvm use $(cat .ruby-version)
|
||||
- rvm use 3.4.9
|
||||
- !reference [.scripts, bundle_install]
|
||||
# Force redis usage, even if it was disabled by the initial configure_environment script of stable.
|
||||
- export REDIS_URL=redis://redis
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
.packager.io:
|
||||
image: docker
|
||||
stage: test
|
||||
extends:
|
||||
- .no_artifact_dependencies
|
||||
needs:
|
||||
- !reference [.needs, lint]
|
||||
timeout: 30 minutes
|
||||
interruptible: false
|
||||
allow_failure: true
|
||||
retry: 2
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
# Don't apply job filter here.
|
||||
# These jobs can only run for a) published paths and b) when triggered after the packager.io build is complete.
|
||||
# The pattern is deliberately not anchored at the end: packager.io publishes a
|
||||
# repository per branch, so stable-* maintenance branches are valid targets, too.
|
||||
- if: ($CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web") && $CI_COMMIT_REF_NAME =~ /^(stable|develop)/
|
||||
when: on_success
|
||||
- when: never
|
||||
services: []
|
||||
cache: []
|
||||
before_script: []
|
||||
script:
|
||||
- .gitlab/packager.io/run_scenarios.sh
|
||||
after_script:
|
||||
@@ -28,4 +20,4 @@ packager.io:
|
||||
extends: [.packager.io]
|
||||
parallel:
|
||||
matrix:
|
||||
- DISTRO: [debian-12, debian-13, ubuntu-22.04, ubuntu-24.04, ubuntu-26.04, rhel-9, rhel-10, sles-15, sles-16.0]
|
||||
- DISTRO: [debian-11, debian-12, debian-13, ubuntu-22.04, ubuntu-24.04, ubuntu-26.04, rhel-9, rhel-10, sles-15, sles-16.0]
|
||||
|
||||
@@ -1,35 +1,29 @@
|
||||
performance:
|
||||
stage: test
|
||||
needs:
|
||||
- !reference [.needs, lint]
|
||||
timeout: 45 minutes
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"
|
||||
when: on_success
|
||||
allow_failure: true
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- .gitlab/ci/test/performance.yml
|
||||
- .gitlab/performance/**/*
|
||||
when: on_success
|
||||
allow_failure: true
|
||||
# No manual start: the job runs for a long time and needs an exclusive runner.
|
||||
- when: never
|
||||
# Make sure this gets executed exclusively on a runner.
|
||||
tags: ['no_concurrency']
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, redis]
|
||||
cache: []
|
||||
before_script:
|
||||
# Copy performance checking code to tmp/ so that it survives branch switching
|
||||
- cp -rv .gitlab/performance tmp/
|
||||
|
||||
# First, checkout stable and set it up.
|
||||
- git fetch --depth=1 origin stable-6.0
|
||||
- git checkout FETCH_HEAD
|
||||
- git fetch --unshallow >/dev/null 2>&1
|
||||
- git checkout stable-6.0
|
||||
- !reference [.scripts, source_rvm]
|
||||
- rvm use $(cat .ruby-version)
|
||||
- rvm use 3.1.3
|
||||
- bundle config set without mysql
|
||||
- !reference [.scripts, bundle_install]
|
||||
- !reference [.scripts, configure_environment]
|
||||
@@ -41,7 +35,7 @@ performance:
|
||||
- bundle exec rails r tmp/performance/run_tests.rb || true
|
||||
# Then, switch to the current commit, migrate to it and run a few selected tests.
|
||||
- git checkout $CI_COMMIT_SHA
|
||||
- rvm use $(cat .ruby-version)
|
||||
- rvm use 3.4.9
|
||||
- !reference [.scripts, bundle_install]
|
||||
# Force redis usage, even if it was disabled by the initial configure_environment script of stable.
|
||||
- export REDIS_URL=redis://redis
|
||||
|
||||
@@ -4,14 +4,7 @@ include:
|
||||
.template_rspec:
|
||||
stage: test
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .job_rules_default
|
||||
- .artifacts_with_test_report
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, database]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 40 minutes
|
||||
script:
|
||||
- !reference [.scripts, zammad_db_init]
|
||||
- bundle exec rspec --require ./spec/rspec_extensions.rb --exclude-pattern "spec/system/**/*_spec.rb" -t ~searchindex -t ~integration
|
||||
@@ -26,28 +19,13 @@ include:
|
||||
rspec:integration:
|
||||
stage: test
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .variables_proxy
|
||||
- .variables_mattermost
|
||||
- .variables_s3
|
||||
- .artifacts_with_test_report
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, database]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 30 minutes
|
||||
allow_failure: true
|
||||
# Squid permits CONNECT to 443, 8443 and 3001 only (configs/squid-ci.conf in
|
||||
# docker/zammad-proxies), so the SSL server of spec/lib/user_agent_spec.rb
|
||||
# has to stay on 3001 for the examples that go through the proxy service.
|
||||
# Safe here, and only here: this is the one job that runs that spec, and it
|
||||
# excludes spec/system, so Capybara never serves on that port alongside it.
|
||||
variables:
|
||||
ZAMMAD_TEST_WEB_SSL_PORT: '3001'
|
||||
rules:
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: on_success
|
||||
allow_failure: true
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
@@ -89,9 +67,9 @@ rspec:integration:
|
||||
- app/models/{channel,external_credential,store,webhook}.rb
|
||||
- app/models/{channel,external_credential,store,webhook}/**/*
|
||||
- app/services/service/{ai,ticket/external_references}/**/*
|
||||
when: on_success
|
||||
allow_failure: true
|
||||
- !reference [.rule_fragments, then_manual]
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, imap]
|
||||
|
||||
@@ -2,21 +2,14 @@
|
||||
addon:subscription:
|
||||
stage: test
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .artifacts_with_test_report
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, database]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 15 minutes
|
||||
- .job_rules_default
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- !reference [.rule_fragments, variable_filters]
|
||||
- !reference [.job_rules, variable_filters]
|
||||
- if: $CI_COMMIT_REF_NAME == 'develop'
|
||||
when: on_success
|
||||
# Complain if breaking changes were merged and subscription is not ported.
|
||||
allow_failure: false
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^private/
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^(private|develop)/
|
||||
when: on_success
|
||||
# It could happen that in a branch we need to make breaking changes, so
|
||||
# only hint at the situation but don't block the pipeline.
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
.template_supabase:
|
||||
stage: test
|
||||
extends:
|
||||
- .template_ruby
|
||||
- .no_artifact_dependencies
|
||||
needs:
|
||||
- !reference [.needs, ruby]
|
||||
- !reference [.needs, lint]
|
||||
timeout: 10 minutes
|
||||
tags:
|
||||
- push-to-ftp # use only allow-listed ci runners
|
||||
services:
|
||||
@@ -18,10 +11,9 @@ supabase:translation_stats:
|
||||
extends:
|
||||
- .template_supabase
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME =~ /^(develop|stable)$/
|
||||
when: always
|
||||
- when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME =~ /^(develop|stable)$/
|
||||
when: always
|
||||
- when: never
|
||||
script:
|
||||
- bundle exec rails runner .gitlab/supabase/translation_stats.rb
|
||||
|
||||
@@ -29,7 +21,6 @@ supabase:github_stats:
|
||||
extends:
|
||||
- .template_supabase
|
||||
rules:
|
||||
- !reference [.rule_fragments, main_repository_only]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME == "develop"
|
||||
when: always
|
||||
- when: never
|
||||
|
||||
19
.gitlab/environment_info.sh
Executable file
19
.gitlab/environment_info.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
date -u --rfc-3339=seconds
|
||||
echo
|
||||
top -b -n1 -w240
|
||||
echo
|
||||
ps aux --width 240
|
||||
echo
|
||||
free -m
|
||||
echo
|
||||
mount
|
||||
echo
|
||||
df -h
|
||||
echo
|
||||
echo "Last 100 lines from kernel log"
|
||||
dmesg | tail -n 100
|
||||
echo
|
||||
echo "Last 1000 lines from system log (journalctl)"
|
||||
journalctl -n 1000
|
||||
@@ -6,6 +6,11 @@ export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
cd "$(dirname $0)"
|
||||
|
||||
# Debian 11 LTS has ended and its security updates were removed from deb.debian.org, but not yet added to archive.debian.org.
|
||||
if [ "${DISTRIBUTION_VERSION}" = "11" ]; then
|
||||
sed -i 's#^deb http://deb.debian.org/debian-security bullseye-security main$#deb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/20260830T000000Z bullseye-security main#' /etc/apt/sources.list
|
||||
fi
|
||||
|
||||
bash ./shared.deb.sh
|
||||
|
||||
echo "deb [signed-by=/usr/share/keyrings/zammad-archive-keyring.gpg] https://go.packager.io/srv/deb/zammad/zammad/${CI_COMMIT_REF_NAME}/debian ${DISTRIBUTION_VERSION} main" > /etc/apt/sources.list.d/zammad.list
|
||||
|
||||
@@ -6,9 +6,6 @@ dnf update -y
|
||||
|
||||
dnf install -y systemd epel-release
|
||||
|
||||
# A background metadata refresh races with the scenario's dnf calls on the lock file.
|
||||
systemctl mask dnf-makecache.timer dnf-makecache.service
|
||||
|
||||
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
|
||||
echo "[elasticsearch-8.x]
|
||||
name=Elasticsearch repository for 8.x packages
|
||||
|
||||
@@ -2,21 +2,6 @@
|
||||
|
||||
set -eu
|
||||
|
||||
# systemd is not reachable yet right after container start, and reports "degraded" inside
|
||||
# containers once boot has finished.
|
||||
booted=false
|
||||
for _ in $(seq 60); do
|
||||
case "$(systemctl is-system-running 2>/dev/null || true)" in
|
||||
running|degraded) booted=true; break ;;
|
||||
esac
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ "$booted" != true ]; then
|
||||
echo "systemd did not finish booting within 60 seconds." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dnf install -y zammad
|
||||
|
||||
curl --retry 30 --retry-delay 1 --retry-connrefused http://localhost:3000 | grep "Zammad Helpdesk"
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"ignorePaths": ["**/node_modules/**"],
|
||||
"enabledManagers": [
|
||||
"bundler",
|
||||
"npm",
|
||||
"github-actions",
|
||||
"devcontainer",
|
||||
"dockerfile",
|
||||
"docker-compose",
|
||||
"gitlabci",
|
||||
"custom.regex"
|
||||
],
|
||||
"enabledManagers": ["bundler", "npm", "github-actions", "devcontainer", "custom.regex"],
|
||||
"customManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
@@ -21,15 +10,6 @@
|
||||
"depNameTemplate": "@devcontainers/cli",
|
||||
"datasourceTemplate": "npm"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"managerFilePatterns": [
|
||||
"/^\\.gitlab/ci/.*\\.yml$/"
|
||||
],
|
||||
"matchStrings": ["PLAYWRIGHT_VERSION: '(?<currentValue>[^']+)'"],
|
||||
"depNameTemplate": "playwright",
|
||||
"datasourceTemplate": "npm"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"managerFilePatterns": [
|
||||
@@ -47,11 +27,6 @@
|
||||
"commitMessageExtra": "(Ruby)"
|
||||
}
|
||||
},
|
||||
"gitlabci": {
|
||||
"managerFilePatterns": [
|
||||
"/^\\.gitlab/ci/.*\\.yml$/"
|
||||
]
|
||||
},
|
||||
"devcontainer": {
|
||||
"managerFilePatterns": [
|
||||
"/^\\.devcontainer/[^/]+/devcontainer\\.json$/"
|
||||
@@ -66,11 +41,6 @@
|
||||
}
|
||||
},
|
||||
"minimumReleaseAge": "3 days",
|
||||
"osvVulnerabilityAlerts": true,
|
||||
"vulnerabilityAlerts": {
|
||||
"minimumReleaseAge": null,
|
||||
"addLabels": ["security"]
|
||||
},
|
||||
"assignees": ["fl"],
|
||||
"packageRules": [
|
||||
{
|
||||
@@ -95,35 +65,8 @@
|
||||
},
|
||||
{
|
||||
"matchCategories": ["js"],
|
||||
"matchFileNames": [".dev/cypress/package.json"],
|
||||
"addLabels": ["cypress"]
|
||||
},
|
||||
{
|
||||
"matchManagers": ["dockerfile", "docker-compose"],
|
||||
"matchFileNames": [
|
||||
".dev/**",
|
||||
".gitlab/packager.io/**"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchPackageNames": [
|
||||
"playwright",
|
||||
"playwright-ruby-client",
|
||||
"capybara-playwright-driver"
|
||||
],
|
||||
"groupName": "Playwright packages",
|
||||
"groupSlug": "playwright"
|
||||
},
|
||||
{
|
||||
"matchDepNames": ["ruby", "docker.io/library/ruby"],
|
||||
"groupName": "Ruby version",
|
||||
"groupSlug": "ruby-version"
|
||||
},
|
||||
{
|
||||
"matchDepNames": ["node", "docker.io/library/node"],
|
||||
"groupName": "Node version",
|
||||
"groupSlug": "node-version"
|
||||
"matchFileNames": [".cypress/package.json"],
|
||||
"labels": ["cypress"]
|
||||
},
|
||||
{
|
||||
"matchCategories": ["js"],
|
||||
@@ -131,12 +74,6 @@
|
||||
"groupSlug": "eslint",
|
||||
"matchPackageNames": ["/eslint/"]
|
||||
},
|
||||
{
|
||||
"matchCategories": ["js"],
|
||||
"groupName": "Oxc packages",
|
||||
"groupSlug": "oxc",
|
||||
"matchPackageNames": ["oxlint", "oxfmt", "eslint-plugin-oxlint"]
|
||||
},
|
||||
{
|
||||
"matchCategories": ["js"],
|
||||
"groupName": "Stylelint packages",
|
||||
@@ -181,8 +118,7 @@
|
||||
"/^@vue/",
|
||||
"/^vue/",
|
||||
"!@vue/eslint-config-typescript",
|
||||
"!@vuepic/vue-datepicker",
|
||||
"!/^@vueuse/"
|
||||
"!@vuepic/vue-datepicker"
|
||||
],
|
||||
"groupName": "Vue packages",
|
||||
"groupSlug": "vue"
|
||||
|
||||
@@ -2,7 +2,24 @@
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"sortTailwindcss": {
|
||||
"stylesheet": "./app/frontend/apps/desktop/styles/main.css"
|
||||
},
|
||||
"sortPackageJson": false,
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["./app/frontend/apps/desktop/**"],
|
||||
"options": {
|
||||
"sortTailwindcss": { "stylesheet": "./app/frontend/apps/desktop/styles/main.css" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["./app/frontend/apps/mobile/**"],
|
||||
"options": {
|
||||
"sortTailwindcss": { "stylesheet": "./app/frontend/apps/mobile/styles/main.css" }
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"app/frontend/**/graphql/**/*.ts",
|
||||
"!app/frontend/tests/graphql/**/*.ts",
|
||||
|
||||
14
.pkgr.yml
14
.pkgr.yml
@@ -35,6 +35,20 @@ targets:
|
||||
# EPEL packages can only be installed after enabling the EPEL repo (see before.sh).
|
||||
- epel-release
|
||||
- shared-mime-info
|
||||
debian-11:
|
||||
dependencies:
|
||||
- curl
|
||||
- elasticsearch|elasticsearch-oss
|
||||
- nginx|apache2
|
||||
- postgresql
|
||||
- libimlib2
|
||||
- libjemalloc2
|
||||
- shared-mime-info
|
||||
- redis-server
|
||||
build_dependencies:
|
||||
- libimlib2
|
||||
- libimlib2-dev
|
||||
- shared-mime-info
|
||||
debian-12:
|
||||
dependencies:
|
||||
- curl
|
||||
|
||||
@@ -2,32 +2,6 @@
|
||||
|
||||
## Upcoming releases
|
||||
|
||||
### `String#utf8_encode` and `Object#to_utf8` will be removed
|
||||
|
||||
**Who is affected?** Developers of third-party packages, patches or add-ons that still call
|
||||
`String#utf8_encode` or `Object#to_utf8`.
|
||||
|
||||
Both core extensions, deprecated since Zammad 7.3, will be removed in Zammad 8.0. Code still calling
|
||||
them will then raise `NoMethodError`.
|
||||
|
||||
⚠️ Switch such code to `TextEncoding.utf8_encode` before updating to Zammad 8.0.
|
||||
|
||||
**Related issue:** [#6371](https://github.com/zammad/zammad/issues/6371)
|
||||
|
||||
### Debian 11 will no longer be supported
|
||||
|
||||
**Who is affected?** Admins of instances installed from the Zammad package repository on Debian 11
|
||||
("bullseye").
|
||||
|
||||
Debian 11 reached its LTS end of life on 2026-08-31 and no longer receives security updates. A future
|
||||
release will therefore no longer be built for it, and the package repository will provide no Debian 11
|
||||
packages for that release and later ones. Zammad 7.1 keeps receiving Debian 11 packages until it goes
|
||||
out of maintenance.
|
||||
|
||||
⚠️ Upgrade the operating system to a supported Debian release before updating.
|
||||
|
||||
**Related issue:** [#6360](https://github.com/zammad/zammad/issues/6360)
|
||||
|
||||
### Inline attachments will be listed separately in ticket article API responses
|
||||
|
||||
**Who is affected?** Integrations that read inline images from the `attachments` list of ticket article
|
||||
@@ -41,6 +15,32 @@ will be returned in a dedicated `inline_attachments` key instead.
|
||||
|
||||
**Related issue:** [#6254](https://github.com/zammad/zammad/issues/6254)
|
||||
|
||||
### Deleting organizations via API will require the `admin.organization` permission
|
||||
|
||||
**Who is affected?** Integrations that call `DELETE /api/v1/organizations/:id` with a token that only
|
||||
has the `ticket.agent` permission.
|
||||
|
||||
The endpoint has historically been permitted for users with only the `ticket.agent` permission. That is
|
||||
deprecated and will be restricted to `admin.organization` in a future release; agent tokens will then
|
||||
receive `403 Forbidden`.
|
||||
|
||||
⚠️ Switch such integrations to an account with the `admin.organization` permission.
|
||||
|
||||
**Related issue:** [#6315](https://github.com/zammad/zammad/issues/6315)
|
||||
|
||||
### Import mode will also enable maintenance mode
|
||||
|
||||
**Who is affected?** Admins of instances that are left in import mode while users are expected to work
|
||||
in them.
|
||||
|
||||
Import mode was never intended for productive environments. In a future release, an instance running in
|
||||
import mode will automatically run in maintenance mode as well, which prevents non-admin users from
|
||||
logging in.
|
||||
|
||||
⚠️ Disable import mode before letting users work in the instance.
|
||||
|
||||
**Related issue:** [#6237](https://github.com/zammad/zammad/issues/6237)
|
||||
|
||||
### `Exceptions::UnprocessableEntity` will be removed
|
||||
|
||||
**Who is affected?** Developers of custom packages, patches or add-ons that still reference
|
||||
@@ -71,86 +71,6 @@ instead.
|
||||
|
||||
**Related issue:** [#5580](https://github.com/zammad/zammad/issues/5580)
|
||||
|
||||
## 7.3
|
||||
|
||||
### `String#utf8_encode` and `Object#to_utf8` were deprecated in favour of `TextEncoding.utf8_encode`
|
||||
|
||||
**Who is affected?** Developers of third-party packages, patches or add-ons that call
|
||||
`String#utf8_encode`, `String#utf8_encode!` or `Object#to_utf8`.
|
||||
|
||||
Encoding resolution moved out of `lib/core_ext/string.rb` into a dedicated class, `TextEncoding`,
|
||||
which takes the string as an argument: `string.utf8_encode(from: 'iso-8859-1')` became
|
||||
`TextEncoding.utf8_encode(string, from: 'iso-8859-1')`, and `object.to_utf8` became
|
||||
`TextEncoding.utf8_encode(object.to_s)`. `String` no longer requires the `rchardet` and `mail` gems.
|
||||
|
||||
`String#utf8_encode` and `Object#to_utf8` still work and now emit a deprecation warning.
|
||||
`String#utf8_encode!` was removed without a deprecation period, since `TextEncoding.utf8_encode`
|
||||
never modifies its argument and always returns a new string.
|
||||
|
||||
⚠️ Replace calls to `String#utf8_encode` and `Object#to_utf8` with `TextEncoding.utf8_encode`, and
|
||||
replace `String#utf8_encode!` with an assignment from it.
|
||||
|
||||
**Related issue:** [#6371](https://github.com/zammad/zammad/issues/6371)
|
||||
|
||||
### Import mode also enables maintenance mode
|
||||
|
||||
**Who is affected?** Admins of instances that are left in import mode while users are expected to work
|
||||
in them.
|
||||
|
||||
Import mode was never intended for productive environments. An instance running in import mode now
|
||||
automatically runs in maintenance mode as well: while the `import_mode` setting is enabled, every
|
||||
authenticated request of a user without the `admin.maintenance` permission is refused. REST and API
|
||||
requests get `403 Forbidden`, and GraphQL treats the session as logged out. This covers new logins,
|
||||
sessions that were already open, and API access via token or HTTP basic authentication alike. An
|
||||
impersonated session is only exempt when the administrator who switched into it holds
|
||||
`admin.maintenance`; this also applies to the classic maintenance mode.
|
||||
|
||||
⚠️ Disable import mode before letting users work in the instance.
|
||||
|
||||
**Related issue:** [#6237](https://github.com/zammad/zammad/issues/6237)
|
||||
|
||||
### The knowledge base search index was switched from HTML-escaped text to plain text
|
||||
|
||||
**Who is affected?** Admins of instances with Elasticsearch enabled that use the knowledge base, and
|
||||
integrations that call `POST /api/v1/knowledge_bases/search`.
|
||||
|
||||
Knowledge base titles and answer bodies were written into the search index HTML-escaped, so a
|
||||
category named `Warranty & Returns` was indexed as `Warranty & Returns`. The escape sequences
|
||||
were searchable in their own right: `amp`, `lt`, `gt` and `nbsp` matched content that contains no
|
||||
such word, and a search matching one of them, the wildcard `*` among them, highlighted it and left
|
||||
the sequence visible in the result list ([#6369](https://github.com/zammad/zammad/issues/6369)).
|
||||
Both texts are now indexed as plain text. Markup in a title is still dropped on its way into the
|
||||
index, and the title columns themselves keep what was written to them.
|
||||
|
||||
The details returned by `POST /api/v1/knowledge_bases/search` changed with it: `title`, `body` and
|
||||
`subtitle` are now always HTML, with every character escaped and, when `highlight_enabled` is on,
|
||||
`<em>` marking the matched runs. Previously only a highlighted fragment was guaranteed to look like
|
||||
this. A detail without a match in its field came back the way its fallback produced it: HTML-escaped
|
||||
for the answer `body`, the category and knowledge base `title` and the `subtitle`, and as written
|
||||
for the answer `title`, with highlighting on or off.
|
||||
|
||||
The `result` list no longer carries the `highlight` key of each hit. The raw fragments it held mark
|
||||
their matches with characters that only the `details` rendering above knows how to interpret.
|
||||
|
||||
⚠️ Integrations that read the answer `title` as text have to decode it as HTML, like every other detail.
|
||||
|
||||
⚠️ Rebuild the search index after the update: `zammad run rake zammad:searchindex:rebuild`
|
||||
|
||||
**Related issue:** [#6399](https://github.com/zammad/zammad/issues/6399)
|
||||
|
||||
### Deleting organizations via API requires the `admin.organization` permission
|
||||
|
||||
**Who is affected?** Integrations that call `DELETE /api/v1/organizations/:id` with a token that only
|
||||
has the `ticket.agent` permission.
|
||||
|
||||
The endpoint has historically been permitted for users with only the `ticket.agent` permission, which
|
||||
contradicted the API documentation. That behaviour was deprecated in Zammad 7.2: the endpoint now
|
||||
requires `admin.organization`, and agent tokens receive `403 Forbidden`.
|
||||
|
||||
⚠️ Switch such integrations to an account with the `admin.organization` permission.
|
||||
|
||||
**Related issue:** [#6315](https://github.com/zammad/zammad/issues/6315)
|
||||
|
||||
## 7.2
|
||||
|
||||
### Verifying a signup email address no longer signs the user in
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,8 +1,8 @@
|
||||
# Change Log for Zammad 7.3.x
|
||||
# Change Log for Zammad 7.2.1
|
||||
|
||||
- [Release notes](https://zammad.com/en/product/releases/zammad-7-3-x)
|
||||
- [Breaking changes](BREAKING_CHANGES.md#73)
|
||||
- [Implemented enhancements](https://github.com/zammad/zammad/issues?q=is%3Aclosed+milestone%3A7.3+(-type%3ABug+AND+-label%3Abug))
|
||||
- [Closed bugs](https://github.com/zammad/zammad/issues?q=is%3Aclosed+milestone%3A7.3+(type%3ABug+OR+label%3Abug))
|
||||
- [Full commit log](https://github.com/zammad/zammad/compare/7.2.0...7.3.x)
|
||||
- [File tree](https://github.com/zammad/zammad/tree/7.3.x)
|
||||
- [Release notes](https://zammad.com/en/product/releases/7-2-1)
|
||||
- [Breaking changes](BREAKING_CHANGES.md#72)
|
||||
- [Implemented enhancements](https://github.com/zammad/zammad/issues?q=is%3Aclosed+milestone%3A7.2+(-type%3ABug+AND+-label%3Abug))
|
||||
- [Closed bugs](https://github.com/zammad/zammad/issues?q=is%3Aclosed+milestone%3A7.2+(type%3ABug+OR+label%3Abug))
|
||||
- [Full commit log](https://github.com/zammad/zammad/compare/7.2.0...7.2.1)
|
||||
- [File tree](https://github.com/zammad/zammad/tree/7.2.1)
|
||||
|
||||
@@ -18,7 +18,7 @@ WORKDIR /opt/zammad
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -y postgresql-common && \
|
||||
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \
|
||||
apt-get install -y --no-install-recommends libjemalloc2 curl libimlib2 nginx gnupg postgresql-client && \
|
||||
apt-get install -y --no-install-recommends libjemalloc2 curl libimlib2 libpq5 nginx gnupg postgresql-client && \
|
||||
apt-get remove -y --purge exim4-base exim4-config bsd-mailx && \
|
||||
apt-get autoremove -y --purge && \
|
||||
rm -rf /var/lib/apt/lists /var/cache/apt/archives
|
||||
@@ -48,7 +48,7 @@ SHELL ["/bin/bash", "-o", "errexit", "-o", "pipefail", "-c"]
|
||||
|
||||
# Install packages needed to build gems and node modules
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install --no-install-recommends -y build-essential git libimlib2-dev libssl-dev libyaml-dev && \
|
||||
apt-get install --no-install-recommends -y build-essential git libimlib2-dev libpq-dev libyaml-dev && \
|
||||
rm -rf /var/lib/apt/lists /var/cache/apt/archives
|
||||
|
||||
# Install application gems
|
||||
|
||||
12
Gemfile
12
Gemfile
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
|
||||
|
||||
# core - base
|
||||
ruby '3.4.9'
|
||||
gem 'rails', '~> 8.1.0'
|
||||
gem 'rails', '~> 8.0.0'
|
||||
gem 'rake'
|
||||
|
||||
# core - rails additions
|
||||
@@ -21,7 +21,6 @@ gem 'puma', group: :puma
|
||||
gem 'pg', '~> 1.5', '>= 1.5.4', group: :postgres
|
||||
|
||||
# core - asynchrous task execution
|
||||
gem 'benchmark' # undeclared delayed_job dependency
|
||||
gem 'daemons'
|
||||
gem 'delayed_job', git: 'https://github.com/zammad-deps/delayed_job', branch: 'threadsafe'
|
||||
gem 'delayed_job_active_record', git: 'https://github.com/zammad-deps/delayed_job_active_record', branch: 'update-limit-143'
|
||||
@@ -217,7 +216,6 @@ gem 'elasticsearch', '8.11.2', require: false
|
||||
group :development, :test do
|
||||
|
||||
# test frameworks
|
||||
gem 'rspec_junit_formatter'
|
||||
gem 'rspec-rails'
|
||||
gem 'rspec-retry'
|
||||
gem 'shoulda-matchers'
|
||||
@@ -229,11 +227,8 @@ group :development, :test do
|
||||
gem 'capybara'
|
||||
gem 'selenium-webdriver'
|
||||
|
||||
# Playwright pilot (throwaway evaluation). playwright-ruby-client is pulled in
|
||||
# by the driver; it is declared here so Renovate sees it and can keep it in
|
||||
# lockstep with the playwright npm package.
|
||||
# Playwright pilot (throwaway evaluation)
|
||||
gem 'capybara-playwright-driver'
|
||||
gem 'playwright-ruby-client'
|
||||
|
||||
# code QA
|
||||
gem 'brakeman', require: false
|
||||
@@ -273,6 +268,9 @@ group :development, :test do
|
||||
# Self-signed localhost certificates for puma / capybara.
|
||||
gem 'localhost'
|
||||
|
||||
# Keycloak admin tool for setting up SAML auth tests
|
||||
gem 'ruby-keycloak-admin'
|
||||
|
||||
# Debugging and profiling
|
||||
gem 'pry-doc', require: false # This gem is very large, so don't include it in production.
|
||||
|
||||
|
||||
272
Gemfile.lock
272
Gemfile.lock
@@ -32,31 +32,29 @@ GEM
|
||||
simple_po_parser (~> 1.1.6)
|
||||
aasm (6.0.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
action_text-trix (2.1.19)
|
||||
railties
|
||||
actioncable (8.1.4)
|
||||
actionpack (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
actioncable (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (8.1.4)
|
||||
actionpack (= 8.1.4)
|
||||
activejob (= 8.1.4)
|
||||
activerecord (= 8.1.4)
|
||||
activestorage (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
actionmailbox (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activestorage (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
mail (>= 2.8.0)
|
||||
actionmailer (8.1.4)
|
||||
actionpack (= 8.1.4)
|
||||
actionview (= 8.1.4)
|
||||
activejob (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
actionmailer (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
actionview (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
mail (>= 2.8.0)
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (8.1.4)
|
||||
actionview (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
actionpack (8.0.5.1)
|
||||
actionview (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
nokogiri (>= 1.8.5)
|
||||
rack (>= 2.2.4)
|
||||
rack-session (>= 1.0.1)
|
||||
@@ -64,28 +62,27 @@ GEM
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
useragent (~> 0.16)
|
||||
actiontext (8.1.4)
|
||||
action_text-trix (~> 2.1.15)
|
||||
actionpack (= 8.1.4)
|
||||
activerecord (= 8.1.4)
|
||||
activestorage (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
actiontext (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activestorage (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
actionview (8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
activejob (8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
activejob (8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
activerecord (8.1.4)
|
||||
activemodel (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
activemodel (8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
activerecord (8.0.5.1)
|
||||
activemodel (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
timeout (>= 0.4.0)
|
||||
activerecord-import (2.3.0)
|
||||
activerecord (>= 4.2)
|
||||
@@ -95,20 +92,20 @@ GEM
|
||||
cgi (>= 0.3.6)
|
||||
rack (>= 2.0.8, < 4)
|
||||
railties (>= 7.1)
|
||||
activestorage (8.1.4)
|
||||
actionpack (= 8.1.4)
|
||||
activejob (= 8.1.4)
|
||||
activerecord (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
activestorage (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
marcel (~> 1.0)
|
||||
activesupport (8.1.4)
|
||||
activesupport (8.0.5.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
json
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
securerandom (>= 0.3)
|
||||
@@ -133,8 +130,8 @@ GEM
|
||||
autoprefixer-rails (10.4.21.0)
|
||||
execjs (~> 2)
|
||||
aws-eventstream (1.4.0)
|
||||
aws-partitions (1.1292.0)
|
||||
aws-sdk-core (3.257.0)
|
||||
aws-partitions (1.1282.0)
|
||||
aws-sdk-core (3.254.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
@@ -142,12 +139,11 @@ GEM
|
||||
bigdecimal
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
logger
|
||||
rexml (~> 3.4, >= 3.4.2)
|
||||
aws-sdk-kms (1.132.0)
|
||||
aws-sdk-core (~> 3, >= 3.256.0)
|
||||
aws-sdk-kms (1.130.0)
|
||||
aws-sdk-core (~> 3, >= 3.254.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.233.1)
|
||||
aws-sdk-core (~> 3, >= 3.256.0)
|
||||
aws-sdk-s3 (1.229.0)
|
||||
aws-sdk-core (~> 3, >= 3.254.1)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.12.1)
|
||||
@@ -157,16 +153,16 @@ GEM
|
||||
samovar (~> 2.1)
|
||||
base64 (0.3.0)
|
||||
benchmark (0.5.0)
|
||||
bigdecimal (4.1.3)
|
||||
bigdecimal (4.1.2)
|
||||
bindata (2.5.1)
|
||||
binding_of_caller (2.0.0)
|
||||
debug_inspector (>= 1.2.0)
|
||||
biz (1.8.2)
|
||||
clavius (~> 1.0)
|
||||
tzinfo
|
||||
bootsnap (1.26.0)
|
||||
bootsnap (1.25.0)
|
||||
msgpack (~> 1.5)
|
||||
brakeman (8.1.0)
|
||||
brakeman (8.0.6)
|
||||
racc
|
||||
browser (6.2.0)
|
||||
builder (3.3.0)
|
||||
@@ -181,7 +177,7 @@ GEM
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
capybara-playwright-driver (0.5.12)
|
||||
capybara-playwright-driver (0.5.10)
|
||||
addressable
|
||||
capybara
|
||||
playwright-ruby-client (>= 1.16.0)
|
||||
@@ -206,7 +202,7 @@ GEM
|
||||
coffee-script-source (1.12.2)
|
||||
concurrent-ruby (1.3.8)
|
||||
connection_pool (3.0.2)
|
||||
console (1.38.0)
|
||||
console (1.37.0)
|
||||
fiber-annotation
|
||||
fiber-local (~> 1.1)
|
||||
json
|
||||
@@ -219,7 +215,7 @@ GEM
|
||||
crass (1.0.7)
|
||||
csv (3.3.6)
|
||||
daemons (1.4.1)
|
||||
dalli (5.2.2)
|
||||
dalli (5.1.1)
|
||||
logger
|
||||
dartsass-rails (0.5.1)
|
||||
railties (>= 6.0.0)
|
||||
@@ -233,7 +229,7 @@ GEM
|
||||
activesupport (>= 7.0)
|
||||
diff-lcs (1.6.2)
|
||||
diffy (3.4.4)
|
||||
doorkeeper (5.9.9)
|
||||
doorkeeper (5.9.6)
|
||||
railties (>= 5)
|
||||
drb (2.2.3)
|
||||
dry-cli (1.4.1)
|
||||
@@ -290,7 +286,7 @@ GEM
|
||||
railties (>= 6.1.0)
|
||||
faker (3.8.0)
|
||||
i18n (>= 1.8.11, < 2)
|
||||
faraday (2.14.4)
|
||||
faraday (2.14.3)
|
||||
faraday-net_http (>= 2.0, < 3.5)
|
||||
json
|
||||
logger
|
||||
@@ -304,10 +300,6 @@ GEM
|
||||
faraday-net_http (3.4.4)
|
||||
net-http (~> 0.5)
|
||||
ffi (1.17.4)
|
||||
ffi (1.17.4-aarch64-linux-gnu)
|
||||
ffi (1.17.4-arm64-darwin)
|
||||
ffi (1.17.4-x86_64-darwin)
|
||||
ffi (1.17.4-x86_64-linux-gnu)
|
||||
ffi-compiler (1.4.2)
|
||||
ffi (>= 1.15.5)
|
||||
rake
|
||||
@@ -319,22 +311,10 @@ GEM
|
||||
ostruct
|
||||
globalid (1.4.0)
|
||||
activesupport (>= 6.1)
|
||||
google-protobuf (4.36.2)
|
||||
google-protobuf (4.36.0)
|
||||
bigdecimal
|
||||
rake (~> 13.3)
|
||||
google-protobuf (4.36.2-aarch64-linux-gnu)
|
||||
bigdecimal
|
||||
rake (~> 13.3)
|
||||
google-protobuf (4.36.2-arm64-darwin)
|
||||
bigdecimal
|
||||
rake (~> 13.3)
|
||||
google-protobuf (4.36.2-x86_64-darwin)
|
||||
bigdecimal
|
||||
rake (~> 13.3)
|
||||
google-protobuf (4.36.2-x86_64-linux-gnu)
|
||||
bigdecimal
|
||||
rake (~> 13.3)
|
||||
graphql (2.6.11)
|
||||
graphql (2.6.10)
|
||||
base64
|
||||
fiber-storage
|
||||
logger
|
||||
@@ -350,11 +330,15 @@ GEM
|
||||
redis-client (= 0.30.1)
|
||||
htmlentities (4.4.2)
|
||||
http_parser.rb (0.8.1)
|
||||
httparty (0.24.2)
|
||||
csv
|
||||
mini_mime (>= 1.0.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.15.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
icalendar (2.12.5)
|
||||
icalendar (2.12.4)
|
||||
base64
|
||||
ice_cube (~> 0.16)
|
||||
logger
|
||||
@@ -368,14 +352,14 @@ GEM
|
||||
inflection (1.0.0)
|
||||
iniparse (1.5.0)
|
||||
interception (0.5)
|
||||
io-console (0.9.4)
|
||||
io-console (0.9.2)
|
||||
irb (1.18.0)
|
||||
pp (>= 0.6.0)
|
||||
prism (>= 1.3.0)
|
||||
rdoc (>= 4.0.0)
|
||||
reline (>= 0.4.2)
|
||||
jmespath (1.6.2)
|
||||
json (3.0.2)
|
||||
json (2.21.2)
|
||||
json-jwt (1.17.2)
|
||||
activesupport (>= 4.2)
|
||||
aes_key_wrap
|
||||
@@ -383,7 +367,7 @@ GEM
|
||||
bindata
|
||||
faraday (~> 2.0)
|
||||
faraday-follow_redirects
|
||||
jwt (3.3.0)
|
||||
jwt (3.2.0)
|
||||
base64
|
||||
koala (3.7.0)
|
||||
addressable
|
||||
@@ -396,7 +380,7 @@ GEM
|
||||
rexml
|
||||
language_server-protocol (3.17.0.6)
|
||||
lint_roller (1.1.0)
|
||||
listen (3.10.1)
|
||||
listen (3.10.0)
|
||||
logger
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
@@ -426,14 +410,14 @@ GEM
|
||||
mime-types (3.7.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
||||
mime-types-data (3.2026.0929)
|
||||
mime-types-data (3.2026.0701)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (6.0.6)
|
||||
drb (~> 2.0)
|
||||
prism (~> 1.5)
|
||||
msgpack (1.8.5)
|
||||
multi_json (1.21.2)
|
||||
msgpack (1.8.4)
|
||||
multi_json (1.21.1)
|
||||
multi_xml (0.9.1)
|
||||
bigdecimal (>= 3.1, < 5)
|
||||
multipart-post (2.4.1)
|
||||
@@ -441,7 +425,7 @@ GEM
|
||||
nestful (1.1.4)
|
||||
net-http (0.9.1)
|
||||
uri (>= 0.11.1)
|
||||
net-imap (0.6.7)
|
||||
net-imap (0.6.6)
|
||||
date
|
||||
net-protocol
|
||||
net-ldap (0.20.0)
|
||||
@@ -449,23 +433,15 @@ GEM
|
||||
ostruct
|
||||
net-pop (0.1.2)
|
||||
net-protocol
|
||||
net-protocol (0.4.0)
|
||||
net-protocol (0.3.0)
|
||||
timeout
|
||||
net-smtp (0.5.2)
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
nio4r (2.7.5)
|
||||
nkf (0.3.0)
|
||||
nokogiri (1.19.4)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-aarch64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-x86_64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nori (2.9.1)
|
||||
bigdecimal
|
||||
stringio
|
||||
@@ -504,8 +480,8 @@ GEM
|
||||
omniauth-gitlab (4.1.0)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-oauth2 (~> 1.8.0)
|
||||
omniauth-google-oauth2 (1.2.3)
|
||||
jwt (>= 2.9.2, < 4)
|
||||
omniauth-google-oauth2 (1.2.2)
|
||||
jwt (>= 2.9.2)
|
||||
oauth2 (~> 2.0)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-oauth2 (~> 1.8)
|
||||
@@ -553,20 +529,16 @@ GEM
|
||||
openssl-signature_algorithm (1.3.0)
|
||||
openssl (> 2.0)
|
||||
ostruct (0.6.3)
|
||||
overcommit (0.73.0)
|
||||
overcommit (0.72.0)
|
||||
childprocess (>= 0.6.3, < 6)
|
||||
iniparse (~> 1.4)
|
||||
rexml (>= 3.4.2)
|
||||
parallel (2.3.0)
|
||||
parallel (2.1.0)
|
||||
parser (3.3.12.0)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
pg (1.7.0)
|
||||
pg (1.7.0-aarch64-linux)
|
||||
pg (1.7.0-arm64-darwin)
|
||||
pg (1.7.0-x86_64-darwin)
|
||||
pg (1.7.0-x86_64-linux)
|
||||
playwright-ruby-client (1.63.0)
|
||||
pg (1.6.3)
|
||||
playwright-ruby-client (1.62.0)
|
||||
base64
|
||||
concurrent-ruby (>= 1.1.6)
|
||||
mime-types (>= 3.0)
|
||||
@@ -620,7 +592,7 @@ GEM
|
||||
base64 (>= 0.1.0)
|
||||
logger (>= 1.6.0)
|
||||
rack (>= 3.0.0, < 4)
|
||||
rack-proxy (2.0.1)
|
||||
rack-proxy (1.0.3)
|
||||
rack (>= 2.0, < 4)
|
||||
rack-session (2.1.2)
|
||||
base64 (>= 0.1.0)
|
||||
@@ -629,20 +601,20 @@ GEM
|
||||
rack (>= 1.3)
|
||||
rackup (2.3.1)
|
||||
rack (>= 3)
|
||||
rails (8.1.4)
|
||||
actioncable (= 8.1.4)
|
||||
actionmailbox (= 8.1.4)
|
||||
actionmailer (= 8.1.4)
|
||||
actionpack (= 8.1.4)
|
||||
actiontext (= 8.1.4)
|
||||
actionview (= 8.1.4)
|
||||
activejob (= 8.1.4)
|
||||
activemodel (= 8.1.4)
|
||||
activerecord (= 8.1.4)
|
||||
activestorage (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
rails (8.0.5.1)
|
||||
actioncable (= 8.0.5.1)
|
||||
actionmailbox (= 8.0.5.1)
|
||||
actionmailer (= 8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
actiontext (= 8.0.5.1)
|
||||
actionview (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activemodel (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activestorage (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 8.1.4)
|
||||
railties (= 8.0.5.1)
|
||||
rails-dom-testing (2.3.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
@@ -650,9 +622,9 @@ GEM
|
||||
rails-html-sanitizer (1.7.1)
|
||||
loofah (~> 2.25, >= 2.25.2)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
railties (8.1.4)
|
||||
actionpack (= 8.1.4)
|
||||
activesupport (= 8.1.4)
|
||||
railties (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
irb (~> 1.13)
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
@@ -669,7 +641,7 @@ GEM
|
||||
prism (>= 1.6.0)
|
||||
tsort
|
||||
rchardet (1.10.2)
|
||||
rdoc (8.1.0)
|
||||
rdoc (8.0.0)
|
||||
erb
|
||||
prism (>= 1.6.0)
|
||||
rbs (>= 4.0.0)
|
||||
@@ -678,7 +650,7 @@ GEM
|
||||
redis-client (>= 0.22.0)
|
||||
redis-client (0.30.1)
|
||||
connection_pool
|
||||
regexp_parser (2.13.1)
|
||||
regexp_parser (2.12.0)
|
||||
reline (0.7.0)
|
||||
io-console (~> 0.5)
|
||||
rexml (3.4.4)
|
||||
@@ -702,10 +674,8 @@ GEM
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.13.7)
|
||||
rspec_junit_formatter (0.6.0)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
rszr (1.5.0)
|
||||
rubocop (1.91.0)
|
||||
rubocop (1.90.0)
|
||||
json (>= 2.3)
|
||||
language_server-protocol (~> 3.17.0.2)
|
||||
lint_roller (~> 1.1.0)
|
||||
@@ -740,7 +710,7 @@ GEM
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (>= 1.89.0, < 2.0)
|
||||
rubocop-ast (>= 1.47.1, < 2.0)
|
||||
rubocop-rails (2.38.0)
|
||||
rubocop-rails (2.37.0)
|
||||
activesupport (>= 4.2.0)
|
||||
lint_roller (~> 1.1)
|
||||
rack (>= 1.1)
|
||||
@@ -757,6 +727,9 @@ GEM
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rspec (~> 3.5)
|
||||
ruby-keycloak-admin (26.5.2)
|
||||
hashie (>= 5.0.0)
|
||||
httparty (>= 0.21, < 0.25)
|
||||
ruby-lsp (0.26.11)
|
||||
language_server-protocol (~> 3.17.0)
|
||||
prism (>= 1.2, < 2.0)
|
||||
@@ -769,34 +742,27 @@ GEM
|
||||
ruby-saml (1.18.1)
|
||||
nokogiri (>= 1.13.10)
|
||||
rexml
|
||||
rubyntlm (0.6.8)
|
||||
rubyntlm (0.6.5)
|
||||
base64
|
||||
rubyzip (3.7.0)
|
||||
rubyzip (3.5.0)
|
||||
safety_net_attestation (0.5.0)
|
||||
jwt (>= 2.0, < 4.0)
|
||||
samovar (2.5.1)
|
||||
console (~> 1.0)
|
||||
sass-embedded (1.105.1)
|
||||
google-protobuf (~> 4.31)
|
||||
rake (~> 13.3)
|
||||
sass-embedded (1.105.1-aarch64-linux-gnu)
|
||||
google-protobuf (~> 4.31)
|
||||
sass-embedded (1.105.1-arm64-darwin)
|
||||
google-protobuf (~> 4.31)
|
||||
sass-embedded (1.105.1-x86_64-darwin)
|
||||
google-protobuf (~> 4.31)
|
||||
sass-embedded (1.105.1-x86_64-linux-gnu)
|
||||
sass-embedded (1.103.1)
|
||||
google-protobuf (~> 4.31)
|
||||
rake (>= 13)
|
||||
securerandom (0.4.1)
|
||||
selenium-webdriver (4.50.0)
|
||||
selenium-webdriver (4.48.0)
|
||||
base64 (~> 0.2)
|
||||
logger (~> 1.4)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 4.0)
|
||||
websocket (~> 1.0)
|
||||
shoulda-matchers (8.0.1)
|
||||
activesupport (>= 7.2)
|
||||
simple_po_parser (1.1.6)
|
||||
simpleidn (0.3.0)
|
||||
simpleidn (0.2.3)
|
||||
slack-ruby-client (3.2.0)
|
||||
faraday (>= 2.0.1)
|
||||
faraday-mashify
|
||||
@@ -841,7 +807,7 @@ GEM
|
||||
openssl (> 2.0)
|
||||
openssl-signature_algorithm (~> 1.0)
|
||||
tsort (0.2.0)
|
||||
twilio-ruby (7.11.3)
|
||||
twilio-ruby (7.11.1)
|
||||
faraday (>= 2.0, < 3.0)
|
||||
jwt (>= 1.5, < 4.0)
|
||||
nokogiri (>= 1.6, < 2.0)
|
||||
@@ -852,11 +818,11 @@ GEM
|
||||
tzinfo
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
tzinfo-data (1.2026.5)
|
||||
tzinfo-data (1.2026.3)
|
||||
tzinfo (>= 1.0.0)
|
||||
unicode-display_width (3.3.0)
|
||||
unicode-emoji (~> 4.3)
|
||||
unicode-emoji (4.3.0)
|
||||
unicode-display_width (3.2.0)
|
||||
unicode-emoji (~> 4.1)
|
||||
unicode-emoji (4.2.0)
|
||||
uri (1.1.1)
|
||||
useragent (0.16.11)
|
||||
validate_url (1.0.15)
|
||||
@@ -874,7 +840,7 @@ GEM
|
||||
vite_rails (3.11.1)
|
||||
railties (>= 5.1, < 9)
|
||||
vite_ruby (~> 3.0, >= 3.2.2)
|
||||
vite_ruby (3.11.1)
|
||||
vite_ruby (3.10.5)
|
||||
dry-cli (>= 0.7, < 2)
|
||||
logger (~> 1.6)
|
||||
mutex_m
|
||||
@@ -901,11 +867,11 @@ GEM
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
whatsapp_sdk (1.2.0)
|
||||
whatsapp_sdk (1.1.0)
|
||||
faraday (~> 2.0, > 2.0.1)
|
||||
faraday-multipart (~> 1)
|
||||
zeitwerk (~> 2)
|
||||
write_xlsx (1.15.1)
|
||||
write_xlsx (1.15.0)
|
||||
nkf
|
||||
rubyzip (>= 2.4.0, < 4.0)
|
||||
xpath (3.2.0)
|
||||
@@ -922,11 +888,7 @@ GEM
|
||||
multipart-post (~> 2.0)
|
||||
|
||||
PLATFORMS
|
||||
aarch64-linux-gnu
|
||||
arm64-darwin
|
||||
ruby
|
||||
x86_64-darwin
|
||||
x86_64-linux-gnu
|
||||
|
||||
DEPENDENCIES
|
||||
PoParser
|
||||
@@ -938,7 +900,6 @@ DEPENDENCIES
|
||||
autodiscover!
|
||||
autoprefixer-rails
|
||||
aws-sdk-s3
|
||||
benchmark
|
||||
biz
|
||||
bootsnap
|
||||
brakeman
|
||||
@@ -1004,7 +965,6 @@ DEPENDENCIES
|
||||
overcommit
|
||||
parallel
|
||||
pg (~> 1.5, >= 1.5.4)
|
||||
playwright-ruby-client
|
||||
pry-doc
|
||||
pry-rails
|
||||
pry-remote
|
||||
@@ -1015,14 +975,13 @@ DEPENDENCIES
|
||||
pundit
|
||||
pundit-matchers
|
||||
rack-attack
|
||||
rails (~> 8.1.0)
|
||||
rails (~> 8.0.0)
|
||||
rake
|
||||
rchardet (>= 1.8.0)
|
||||
redis (< 6)
|
||||
rotp
|
||||
rspec-rails
|
||||
rspec-retry
|
||||
rspec_junit_formatter
|
||||
rszr
|
||||
rubocop
|
||||
rubocop-capybara
|
||||
@@ -1035,6 +994,7 @@ DEPENDENCIES
|
||||
rubocop-rake
|
||||
rubocop-rspec
|
||||
rubocop-rspec_rails
|
||||
ruby-keycloak-admin
|
||||
ruby-lsp
|
||||
ruby-lsp-rails
|
||||
ruby-lsp-rspec
|
||||
|
||||
@@ -133,12 +133,6 @@ Copyright: Faruk Ates (https://twitter.com/KuraFire)
|
||||
Richard Herrera (https://twitter.com/doctyper)
|
||||
License: MIT license & BSD license
|
||||
-----------------------------------------------------------------------------
|
||||
playwright_visible_text.js
|
||||
Source: https://github.com/SeleniumHQ/selenium
|
||||
Copyright: 2011-2026 Software Freedom Conservancy
|
||||
2004-2011 Selenium committers
|
||||
License: Apache License, Version 2.0
|
||||
-----------------------------------------------------------------------------
|
||||
qrcodegen.js
|
||||
Source: https://www.nayuki.io/page/qr-code-generator-library
|
||||
Copyright: 2022, Project Nayuki
|
||||
|
||||
@@ -39,10 +39,10 @@ class App.ControllerAIFeatureBase extends App.ControllerSubContent
|
||||
|
||||
# Injects a provider modal into .page-header-meta for the given feature identifier;
|
||||
# selecting the default entry deletes the feature's routing row. Shown only to provider
|
||||
# administrators — the backing APIs require admin.ai_provider. The AI provider switch does not
|
||||
# matter here: routing is configuration and may be prepared while the switch is off.
|
||||
# administrators — the backing APIs require admin.ai_provider.
|
||||
renderProviderModal: (identifier) =>
|
||||
return unless identifier
|
||||
return unless App.Config.get('ai_provider')
|
||||
return unless @permissionCheck('admin.ai_provider')
|
||||
|
||||
@el.find('.js-featureProviderButton').remove()
|
||||
|
||||
@@ -41,15 +41,27 @@ class App.ControllerAIFeatureProviderModal extends App.ControllerModal
|
||||
@controller?.releaseController()
|
||||
@controller = new App.ControllerForm(
|
||||
model: { configure_attributes: @buildProviderAttributes() }
|
||||
params: { provider_connection_id: App.AIFeatureProvider.valueFor(@row) }
|
||||
params: @row
|
||||
autofocus: true
|
||||
)
|
||||
|
||||
@controller.form
|
||||
|
||||
buildProviderAttributes: =>
|
||||
defaultChatProvider = _.find(@providers, (provider) -> provider.default_chat)
|
||||
|
||||
options = _.map(@providers, (c) ->
|
||||
value: c.id
|
||||
name: c.name
|
||||
)
|
||||
|
||||
options.unshift(
|
||||
value: ''
|
||||
name: App.i18n.translateInline('Default (%s)', defaultChatProvider?.name or App.i18n.translateInline('none'))
|
||||
)
|
||||
|
||||
[
|
||||
{ name: 'provider_connection_id', display: __('Provider'), tag: 'select', null: false, options: App.AIFeatureProvider.options(@providers) }
|
||||
{ name: 'provider_connection_id', display: __('Provider'), tag: 'select', null: false, options: options }
|
||||
]
|
||||
|
||||
onSubmit: (e) =>
|
||||
@@ -59,20 +71,49 @@ class App.ControllerAIFeatureProviderModal extends App.ControllerModal
|
||||
@formDisable(e)
|
||||
params = @formParam(e.target)
|
||||
|
||||
App.AIFeatureProvider.save(
|
||||
identifier: @featureIdentifier
|
||||
row: @row
|
||||
value: params.provider_connection_id
|
||||
success: =>
|
||||
@notify(
|
||||
type: 'success'
|
||||
msg: App.i18n.translateInline('Provider updated successfully.')
|
||||
)
|
||||
@close()
|
||||
error: (msg) =>
|
||||
@formEnable(e)
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: msg
|
||||
)
|
||||
)
|
||||
connectionId = parseInt(params.provider_connection_id, 10) or null
|
||||
@formEnable(e)
|
||||
|
||||
done = =>
|
||||
@notify(
|
||||
type: 'success'
|
||||
msg: App.i18n.translateInline('Provider updated successfully.')
|
||||
)
|
||||
@close()
|
||||
|
||||
fail = (data) =>
|
||||
details = data?.responseJSON or {}
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: details.error_human or details.error or __('The provider could not be updated.')
|
||||
)
|
||||
|
||||
if not connectionId
|
||||
return @close() if not @row?.id
|
||||
|
||||
# Back to the default connection = remove the routing row.
|
||||
@ajax(
|
||||
id: 'remove_feature_provider'
|
||||
type: 'DELETE'
|
||||
url: App.Config.get('api_path') + '/ai/feature_providers/' + @row.id
|
||||
success: done
|
||||
error: fail
|
||||
)
|
||||
else if @row?.id
|
||||
@ajax(
|
||||
id: 'update_feature_provider'
|
||||
type: 'PUT'
|
||||
url: App.Config.get('api_path') + '/ai/feature_providers/' + @row.id
|
||||
data: JSON.stringify(provider_connection_id: connectionId)
|
||||
success: done
|
||||
error: fail
|
||||
)
|
||||
else
|
||||
@ajax(
|
||||
id: 'create_feature_provider'
|
||||
type: 'POST'
|
||||
url: App.Config.get('api_path') + '/ai/feature_providers'
|
||||
data: JSON.stringify(identifier: @featureIdentifier, provider_connection_id: connectionId)
|
||||
success: done
|
||||
error: fail
|
||||
)
|
||||
|
||||
@@ -27,10 +27,38 @@ class FeedbackAndLogs extends App.ControllerAIFeatureBase
|
||||
# Feedback & Logs works independently of any configured provider connection.
|
||||
showAlert: -> false
|
||||
|
||||
downloadFeedback: ->
|
||||
App.AIAnalyticsDownload.request(type: 'with_usages', button: @$('.js-downloadFeedback'))
|
||||
sendDownloadRequest: (type) ->
|
||||
isFeedback = type is 'with_usages'
|
||||
|
||||
downloadErrorLogs: ->
|
||||
App.AIAnalyticsDownload.request(type: 'errors', button: @$('.js-downloadErrorLogs'))
|
||||
button = @$(if isFeedback then '.js-downloadFeedback' else '.js-downloadErrorLogs')
|
||||
|
||||
disableButton = (disabled) -> button.prop('disabled', disabled)
|
||||
disableButton(true)
|
||||
|
||||
fallbackFilename = if isFeedback then 'ai_analytics_with_usages.xlsx' else 'ai_analytics_errors.xlsx'
|
||||
|
||||
App.Ajax.request(
|
||||
id: 'ai-analytics-download'
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/ai/analytics/download/#{type}"
|
||||
processData: true
|
||||
dataType: 'binary'
|
||||
contentType: 'application/octet-stream'
|
||||
xhrFields:
|
||||
responseType: 'blob'
|
||||
success: (data, status, xhr) ->
|
||||
App.Utils.downloadFileFromBlob(data, xhr, { fallbackFilename: fallbackFilename })
|
||||
disableButton(false)
|
||||
error: (xhr, status, error) =>
|
||||
@log 'error', error || status
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: __('The download could not be started. Please try again later.')
|
||||
)
|
||||
disableButton(false)
|
||||
)
|
||||
|
||||
downloadFeedback: -> @sendDownloadRequest('with_usages')
|
||||
downloadErrorLogs: -> @sendDownloadRequest('errors')
|
||||
|
||||
App.Config.set('FeedbackAndLogs', { prio: 1060, name: __('Feedback & Logs'), parent: '#ai', target: '#ai/feedback_logs', controller: FeedbackAndLogs, permission: ['admin.ai_feedback_logs'] }, 'NavBarAdmin')
|
||||
|
||||
@@ -67,18 +67,34 @@ class TextTool extends App.ControllerAIFeatureBase
|
||||
|
||||
@controllerBind('config_update', @configHasChanged)
|
||||
|
||||
downloadFeedbackReport: (id) ->
|
||||
downloadFeedbackReport: (id) =>
|
||||
text_tool = App.AITextTool.find(id)
|
||||
|
||||
filters =
|
||||
triggered_by_type: 'AI::TextTool'
|
||||
triggered_by_id: id
|
||||
url = "#{@apiPath}/ai/analytics/download/with_usages?filters[triggered_by_type]=AI::TextTool&filters[triggered_by_id]=#{id}"
|
||||
|
||||
# Only limit the report to feedback since the last reset if one happened;
|
||||
# otherwise the report should collect everything.
|
||||
filters.created_after = text_tool.analytics_stats_reset_at if text_tool.analytics_stats_reset_at
|
||||
if text_tool.analytics_stats_reset_at
|
||||
url += "&filters[created_after]=#{text_tool.analytics_stats_reset_at}"
|
||||
|
||||
App.AIAnalyticsDownload.request(type: 'with_usages', filters: filters)
|
||||
@ajax(
|
||||
id: 'download_feedback_report'
|
||||
type: 'GET'
|
||||
url: url
|
||||
processData: true
|
||||
dataType: 'binary'
|
||||
contentType: 'application/octet-stream'
|
||||
xhrFields:
|
||||
responseType: 'blob'
|
||||
success: (data, status, xhr) ->
|
||||
App.Utils.downloadFileFromBlob(data, xhr, { fallbackFilename: 'ai_analytics_with_usages.xlsx' })
|
||||
error: (xhr, status, error) =>
|
||||
@log 'error', error || status
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: __('The download could not be started. Please try again later.')
|
||||
)
|
||||
)
|
||||
|
||||
resetFeedbackTimestamp: (id) =>
|
||||
@ajax(
|
||||
|
||||
@@ -35,7 +35,6 @@ class App.ControllerTabs extends App.Controller
|
||||
|
||||
@html App.view('generic/tabs')(
|
||||
header: @header
|
||||
description: @description
|
||||
subHeader: @subHeader
|
||||
tabs: displayTabs
|
||||
addTab: @addTab
|
||||
|
||||
@@ -1,368 +0,0 @@
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
class ContentTranslation extends App.ControllerTabs
|
||||
@requiredPermission: 'admin.integration'
|
||||
header: __('Translation services')
|
||||
description: __('This service allows agents to translate articles to their configured UI language or other languages of their choice.')
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@title __('Translation services'), true
|
||||
|
||||
@tabs = [
|
||||
{ name: __('Provider Settings'), target: 'provider-settings', controller: ProviderSettings }
|
||||
{ name: __('Ticket Articles'), target: 'ticket-articles', controller: TicketArticles }
|
||||
{ name: __('Logs'), target: 'logs', controller: Logs }
|
||||
{ name: __('Feedback'), target: 'feedback', controller: Feedback }
|
||||
]
|
||||
|
||||
# The tabs read settings while rendering, and App.ControllerTabs#render never releases the
|
||||
# tab controllers, so the page is rendered once after the settings are loaded.
|
||||
App.Setting.fetchFull((=> @render()), force: false)
|
||||
|
||||
class ProviderSettings extends App.Controller
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
'change [name=provider]': 'changeProvider'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@config = App.Setting.get('content_translation_service_config') || {}
|
||||
|
||||
# The connection may be chosen while the AI provider is switched off: routing is configuration,
|
||||
# the switch only decides whether it is used.
|
||||
if @permissionCheck('admin.ai_provider')
|
||||
@fetchAIFeatureProviders()
|
||||
else
|
||||
@render()
|
||||
|
||||
# The connections to choose from.
|
||||
fetchAIFeatureProviders: =>
|
||||
App.AIProviderConnection.fetchFull(
|
||||
=>
|
||||
@ajax(
|
||||
id: 'content_translation_ai_feature_providers'
|
||||
type: 'GET'
|
||||
url: "#{App.Config.get('api_path')}/ai/feature_providers"
|
||||
success: (rows) =>
|
||||
@aiFeatureProviders = rows
|
||||
@render()
|
||||
error: =>
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: __('The providers could not be loaded.')
|
||||
)
|
||||
@render()
|
||||
)
|
||||
force: false
|
||||
)
|
||||
|
||||
render: =>
|
||||
provider = @availableProvider()
|
||||
attributes = @configurationAttributes(provider)
|
||||
|
||||
@html App.view('integration/content_translation_provider_settings')(attributes: attributes)
|
||||
|
||||
# The AI service stays selectable while the AI provider is switched off, so that its
|
||||
# configuration survives the switch. The alert says why nothing translates in the meantime.
|
||||
if @service('ai').available() and provider is 'ai' and not App.Config.get('ai_provider')
|
||||
@el.prepend(App.view('ai/missing_provider_alert')(visible: true))
|
||||
|
||||
defaults = { ai_provider_connection_id: App.AIFeatureProvider.valueFor(@aiFeatureProvider(provider)) }
|
||||
params = _.extend(defaults, @config, provider: provider)
|
||||
|
||||
@forms = [
|
||||
new App.ControllerForm(
|
||||
el: @$('.js-serviceForm')
|
||||
model: { configure_attributes: [@serviceAttribute()] }
|
||||
params: params
|
||||
autofocus: false
|
||||
)
|
||||
]
|
||||
|
||||
for attribute in attributes
|
||||
@forms.push(new App.ControllerForm(
|
||||
el: @$("[data-name='#{attribute.name}']")
|
||||
model: { configure_attributes: [_.extend({}, attribute, class: 'form-control--small', label_class: 'sr-only')] }
|
||||
params: params
|
||||
autofocus: false
|
||||
))
|
||||
|
||||
# Only the service and the AI connection survive the switch: credentials belong to the service
|
||||
# they were entered for, so a field both services ask for, like the API key, would stay filled.
|
||||
changeProvider: =>
|
||||
params = _.extend({}, @config, @formParam(@$('form')))
|
||||
@config = _.pick(params, 'provider', 'ai_provider_connection_id')
|
||||
|
||||
@render()
|
||||
|
||||
service: (key) ->
|
||||
App.Config.get('ContentTranslationServices')[key]
|
||||
|
||||
# Only a service that is still offered is kept as the selection: a service that is gone would
|
||||
# otherwise end up in the select as its raw value.
|
||||
availableProvider: ->
|
||||
provider = @config.provider
|
||||
return if !provider
|
||||
return if !@service(provider)?.available()
|
||||
|
||||
provider
|
||||
|
||||
serviceOptions: ->
|
||||
services = _.filter(_.values(App.Config.get('ContentTranslationServices')), (service) -> service.available())
|
||||
|
||||
_.map(_.sortBy(services, (service) -> service.prio), (service) -> { name: service.label, value: service.key })
|
||||
|
||||
# customsort keeps the services in the prio order the options were built in.
|
||||
serviceAttribute: ->
|
||||
{ name: 'provider', display: __('Translation service provider'), tag: 'select', options: @serviceOptions(), null: true, nulloption: true, translate: true, customsort: 'on' }
|
||||
|
||||
configurationAttributes: (provider) ->
|
||||
(@service(provider)?.credential_attributes or []).concat(@aiProviderAttributes(provider))
|
||||
|
||||
# The AI feature the given service runs as, declared on the service entry.
|
||||
aiFeatureIdentifier: (provider) ->
|
||||
@service(provider)?.ai_feature_identifier
|
||||
|
||||
# The routing row serving that feature, while the admin has pointed it at a connection.
|
||||
aiFeatureProvider: (provider) ->
|
||||
identifier = @aiFeatureIdentifier(provider)
|
||||
return if !identifier
|
||||
|
||||
_.find(@aiFeatureProviders, (row) -> row.identifier is identifier)
|
||||
|
||||
aiProviderAttributes: (provider) ->
|
||||
return [] if !@aiFeatureProviders
|
||||
return [] if !@aiFeatureIdentifier(provider)
|
||||
|
||||
[
|
||||
{ name: 'ai_provider_connection_id', display: __('Provider'), tag: 'select', options: @aiProviderOptions() }
|
||||
]
|
||||
|
||||
aiProviderOptions: ->
|
||||
App.AIFeatureProvider.options(App.AIProviderConnection.all())
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
params = @formParam(e.target)
|
||||
|
||||
errors = {}
|
||||
for form in @forms
|
||||
_.extend(errors, form.validate(params))
|
||||
|
||||
if !_.isEmpty(errors)
|
||||
@formValidate(form: e.target, errors: errors)
|
||||
return
|
||||
|
||||
# The routing row is written first: the settings announce the success of the whole form, so
|
||||
# they must not run while the row this form also changed is still the old one.
|
||||
@submitAIFeatureProvider(params.provider, params.ai_provider_connection_id, => @submitConfig(params))
|
||||
|
||||
# The flag follows the config only once the config is saved, so a refused config leaves the flag
|
||||
# alone and the admin sees one error instead of an error next to a success.
|
||||
submitConfig: (params) ->
|
||||
# Without a service there is nothing to keep, not even the credentials of the previous one.
|
||||
config = if params.provider then _.omit(params, 'ai_provider_connection_id') else {}
|
||||
hasProvider = !!params.provider
|
||||
form = @$('form')
|
||||
|
||||
App.ControllerForm.disable(form)
|
||||
|
||||
App.Setting.set('content_translation_service_config', config,
|
||||
notify: false
|
||||
failLocal: -> App.ControllerForm.enable(form)
|
||||
doneLocal: =>
|
||||
App.ControllerForm.enable(form)
|
||||
|
||||
if App.Config.get('content_translation_service') is hasProvider
|
||||
@notify(type: 'success', msg: __('Update successful.'), timeout: 2000)
|
||||
return
|
||||
|
||||
App.Setting.set('content_translation_service', hasProvider, notify: true)
|
||||
)
|
||||
|
||||
# Calls back only once the row is written, so a failure stops the submit instead of ending in a
|
||||
# success and an error notification next to each other.
|
||||
submitAIFeatureProvider: (provider, value, done) =>
|
||||
return done() if !value
|
||||
|
||||
identifier = @aiFeatureIdentifier(provider)
|
||||
|
||||
App.AIFeatureProvider.save(
|
||||
identifier: identifier
|
||||
row: @aiFeatureProvider(provider)
|
||||
value: value
|
||||
success: (updated) =>
|
||||
@replaceAIFeatureProvider(identifier, updated)
|
||||
done()
|
||||
error: (msg) =>
|
||||
@notify(type: 'error', msg: msg)
|
||||
)
|
||||
|
||||
# Keeps the rows in step with what was just written, so a second submit updates the row it
|
||||
# created instead of trying to create it again.
|
||||
replaceAIFeatureProvider: (identifier, row) =>
|
||||
@aiFeatureProviders = _.reject(@aiFeatureProviders, (existing) -> existing.identifier is identifier)
|
||||
@aiFeatureProviders.push(row) if row
|
||||
|
||||
class TicketArticles extends App.Controller
|
||||
events:
|
||||
'change .js-ticketArticleSetting input': 'toggleTicketArticle'
|
||||
'change .js-ticketArticleAutoSetting input': 'toggleTicketArticleAuto'
|
||||
'submit form': 'submit'
|
||||
|
||||
elements:
|
||||
'.js-ticketArticleSetting input': 'ticketArticleSetting'
|
||||
'.js-ticketArticleAutoSetting input': 'ticketArticleAutoSetting'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@render()
|
||||
|
||||
# Follow the switches in place instead of rendering again, so a pushed setting change (also the
|
||||
# one a switch on this page caused) does not discard an unsaved role selection.
|
||||
@controllerBind('config_update', (data) =>
|
||||
switch data.name
|
||||
when 'content_translation_ticket_article'
|
||||
@ticketArticleSetting.prop('checked', App.Config.get(data.name))
|
||||
when 'content_translation_ticket_article_auto'
|
||||
@ticketArticleAutoSetting.prop('checked', App.Config.get(data.name))
|
||||
)
|
||||
|
||||
# The roles and the language detection are no frontend settings, so they are followed via the
|
||||
# collection. Only a role change from elsewhere is drawn; the own submit already shows what it saved.
|
||||
@subscribeId = App.Setting.subscribe(@settingsChanged, initFetch: true, clear: false)
|
||||
|
||||
settingsChanged: =>
|
||||
@renderAlert()
|
||||
|
||||
return if _.isEqual(App.Setting.get('content_translation_ticket_article_auto_role_ids'), @renderedRoleIds)
|
||||
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
@html App.view('integration/content_translation_ticket_articles')(
|
||||
ticketArticle: App.Config.get('content_translation_ticket_article')
|
||||
ticketArticleAuto: App.Config.get('content_translation_ticket_article_auto')
|
||||
alert: App.i18n.translateContent('The article language detection is disabled. Enable it to avoid translating articles that are already in the target language. %l', '#settings/ticket')
|
||||
)
|
||||
|
||||
@renderAlert()
|
||||
|
||||
@renderedRoleIds = App.Setting.get('content_translation_ticket_article_auto_role_ids')
|
||||
|
||||
new App.ControllerForm(
|
||||
el: @$('.js-form')
|
||||
model:
|
||||
configure_attributes: [
|
||||
{ name: 'content_translation_ticket_article_auto_role_ids', display: __('Available for the following roles'), tag: 'column_select', null: true, relation: 'Role', translate: true }
|
||||
]
|
||||
params:
|
||||
content_translation_ticket_article_auto_role_ids: @renderedRoleIds
|
||||
autofocus: false
|
||||
)
|
||||
|
||||
toggleTicketArticle: =>
|
||||
App.Setting.set('content_translation_ticket_article', @ticketArticleSetting.prop('checked'), failLocal: @render, notify: true)
|
||||
|
||||
toggleTicketArticleAuto: =>
|
||||
App.Setting.set('content_translation_ticket_article_auto', @ticketArticleAutoSetting.prop('checked'), failLocal: @render, notify: true)
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
roleIds = @formParam(e.target).content_translation_ticket_article_auto_role_ids || []
|
||||
|
||||
# Known as shown before the request, so neither the local change nor the push redraws the form.
|
||||
@renderedRoleIds = roleIds
|
||||
App.Setting.set('content_translation_ticket_article_auto_role_ids', roleIds, failLocal: @render, notify: true)
|
||||
|
||||
renderAlert: =>
|
||||
@$('.js-languageDetectionAlert').toggleClass('hide', !!App.Setting.get('language_detection_article'))
|
||||
|
||||
release: =>
|
||||
App.Setting.unsubscribe(@subscribeId)
|
||||
|
||||
class Logs extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@render()
|
||||
|
||||
@subscribeId = App.Setting.subscribe(@renderAiState, initFetch: true, clear: false)
|
||||
|
||||
render: =>
|
||||
@html App.view('integration/content_translation_logs')(hint: @aiHint())
|
||||
|
||||
# The heading belongs to the tab, so it stays while the log itself makes way for the AI hint.
|
||||
@httpLog = new App.HttpLog(
|
||||
el: @$('.js-log')
|
||||
facility: 'content_translation'
|
||||
header: false
|
||||
)
|
||||
|
||||
# Linked only for whoever may open that screen: the link would otherwise just bounce off
|
||||
# permissionCheckRedirect.
|
||||
aiHint: ->
|
||||
if @permissionCheck('admin.ai_feedback_logs')
|
||||
return App.i18n.translateContent('You can find relevant AI provider logs under AI > Feedback & Logs. %l', '#ai/feedback_logs')
|
||||
|
||||
App.i18n.translateContent('You can find relevant AI provider logs under AI > Feedback & Logs.')
|
||||
|
||||
renderAiState: =>
|
||||
isAI = App.Setting.get('content_translation_service_config')?.provider is 'ai'
|
||||
|
||||
@$('.js-aiHint').toggleClass('hide', !isAI)
|
||||
@$('.js-log').toggleClass('hide', isAI)
|
||||
|
||||
release: =>
|
||||
App.Setting.unsubscribe(@subscribeId)
|
||||
|
||||
@httpLog?.releaseController()
|
||||
@httpLog = null
|
||||
|
||||
class Feedback extends App.Controller
|
||||
# The page asks for admin.integration only, but the download answers to admin.ai_feedback_logs, so
|
||||
# App.ControllerTabs leaves out the tab for whoever lacks it instead of offering a failing button.
|
||||
@requiredPermission: 'admin.ai_feedback_logs'
|
||||
|
||||
events:
|
||||
'click .js-downloadFeedback': 'downloadFeedback'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
@html App.view('integration/content_translation_feedback')()
|
||||
|
||||
# Hardcoded, as Service::ContentTranslation::StoredTranslation::IDENTIFIER does not reach the
|
||||
# frontend. It covers the AI service and the others alike.
|
||||
downloadFeedback: =>
|
||||
App.AIAnalyticsDownload.request(
|
||||
type: 'with_usages'
|
||||
filters: { identifier: 'translate' }
|
||||
button: @$('.js-downloadFeedback')
|
||||
)
|
||||
|
||||
class State
|
||||
@current: ->
|
||||
not _.isEmpty(App.Setting.get('content_translation_service_config'))
|
||||
|
||||
App.Config.set(
|
||||
'IntegrationContentTranslation'
|
||||
{
|
||||
name: __('Translation services')
|
||||
target: '#system/integration/content_translation'
|
||||
description: __('Translate ticket articles into another language.')
|
||||
controller: ContentTranslation
|
||||
state: State
|
||||
permission: ['admin.integration']
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
)
|
||||
@@ -62,10 +62,13 @@ class Form extends App.Controller
|
||||
)
|
||||
|
||||
# placeholder
|
||||
configure_attributes = [
|
||||
{ name: 'user_ids', display: '', tag: 'column_select', multiple: true, null: true, relation: 'User', sortBy: 'displayName' },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.js-userSelectorBlank')
|
||||
model:
|
||||
configure_attributes: @userSelectorAttributes()
|
||||
configure_attributes: configure_attributes,
|
||||
params:
|
||||
user_ids: []
|
||||
autofocus: false
|
||||
@@ -96,35 +99,18 @@ class Form extends App.Controller
|
||||
)
|
||||
|
||||
for row in @config.notify_map
|
||||
configure_attributes = [
|
||||
{ name: 'user_ids', display: '', tag: 'column_select', multiple: true, null: true, relation: 'User', sortBy: 'displayName' },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$("[name=queue][value='#{row.queue}']").closest('tr').find('.js-userSelector')
|
||||
model:
|
||||
configure_attributes: @userSelectorAttributes()
|
||||
configure_attributes: configure_attributes,
|
||||
params:
|
||||
user_ids: row.user_ids
|
||||
autofocus: false
|
||||
)
|
||||
|
||||
# Only a user with the cti.agent permission ever sees a caller log, so the
|
||||
# filter offers no one else. The form runs it twice, over the records and
|
||||
# over the built options, so an entry carries the user as id or as value.
|
||||
userSelectorAttributes: ->
|
||||
[
|
||||
{
|
||||
name: 'user_ids'
|
||||
display: ''
|
||||
tag: 'column_select'
|
||||
multiple: true
|
||||
null: true
|
||||
relation: 'User'
|
||||
sortBy: 'displayName'
|
||||
filter: (entries) ->
|
||||
entries.filter (entry) ->
|
||||
user = App.User.find(entry.id || entry.value)
|
||||
user && user.permission('cti.agent')
|
||||
}
|
||||
]
|
||||
|
||||
updateCurrentConfig: =>
|
||||
config = @config
|
||||
cleanupInput = @cleanupInput
|
||||
|
||||
@@ -24,16 +24,6 @@ class Maintenance extends App.Controller
|
||||
@maintenanceForceRefresh(data)
|
||||
)
|
||||
|
||||
# Import mode is switched by the import controllers and background services,
|
||||
# never via the websocket maintenance event, so react to the setting itself.
|
||||
@controllerBind('config_update_local', (data) =>
|
||||
return if data.name isnt 'import_mode'
|
||||
return if @permissionCheck('admin.maintenance')
|
||||
# A switched session is judged by the switching user, which only the backend knows.
|
||||
return if @Config.get('switch_back_to_possible')
|
||||
@maintenanceMode(on: data.value)
|
||||
)
|
||||
|
||||
showMessage: (message = {}) =>
|
||||
if message.reload
|
||||
@disconnectClient()
|
||||
|
||||
@@ -27,10 +27,6 @@ class App.UiElement.postmaster_set extends App.UiElement.ApplicationAction
|
||||
if !row.readonly
|
||||
config = _.clone(row)
|
||||
|
||||
# values may contain placeholders like #{regexp.NAME}, which fail the native field validation
|
||||
if config.type is 'email' || config.type is 'tel' || config.type is 'url'
|
||||
config.type = 'text'
|
||||
|
||||
switch config.tag
|
||||
when 'date'
|
||||
config.operator = ['static', 'relative']
|
||||
|
||||
@@ -120,11 +120,6 @@ class App.CustomerChat extends App.Controller
|
||||
chat_sessions: list
|
||||
)
|
||||
|
||||
# Bootstrap's popover sanitizer has no <time> in its allowlist and would drop
|
||||
# the relative time rendered by the humanTime helper together with its text.
|
||||
chatSessionListWhiteList: ->
|
||||
$.extend({}, $.fn.popover.Constructor.DEFAULTS.whiteList, time: ['datetime', 'title'])
|
||||
|
||||
|
||||
show: (params) =>
|
||||
@title(__('Customer Chat'), true)
|
||||
@@ -258,7 +253,6 @@ class App.CustomerChat extends App.Controller
|
||||
@popovers.push @el.find(".js-waitingCustomers[data-chat-id=#{chat.id}] .js-info").popover(
|
||||
trigger: 'hover'
|
||||
html: true
|
||||
whiteList: @chatSessionListWhiteList()
|
||||
animation: false
|
||||
delay: 0
|
||||
placement: 'bottom'
|
||||
@@ -273,7 +267,6 @@ class App.CustomerChat extends App.Controller
|
||||
@popovers.push @el.find('.js-waitingCustomers .js-totalInfo').popover(
|
||||
trigger: 'hover'
|
||||
html: true
|
||||
whiteList: @chatSessionListWhiteList()
|
||||
animation: false
|
||||
delay: 0
|
||||
placement: 'bottom'
|
||||
@@ -296,7 +289,6 @@ class App.CustomerChat extends App.Controller
|
||||
@popovers.push @el.find('.js-chattingCustomers .js-info').popover(
|
||||
trigger: 'hover'
|
||||
html: true
|
||||
whiteList: @chatSessionListWhiteList()
|
||||
animation: false
|
||||
delay: 0
|
||||
placement: 'bottom'
|
||||
|
||||
@@ -66,8 +66,7 @@ class Login extends App.ControllerFullPage
|
||||
data.name != 'product_name' &&
|
||||
data.name != 'product_logo' &&
|
||||
data.name != 'fqdn' &&
|
||||
data.name != 'user_show_password_login' &&
|
||||
data.name != 'import_mode'
|
||||
data.name != 'user_show_password_login'
|
||||
@render()
|
||||
'rerender'
|
||||
)
|
||||
|
||||
@@ -166,7 +166,6 @@ class App.Search extends App.Controller
|
||||
parent: @
|
||||
parentEl: elLocal
|
||||
appEl: @appEl
|
||||
dragEnabled: => @model is 'Ticket'
|
||||
batchSuccess: =>
|
||||
@search(0, true)
|
||||
)
|
||||
@@ -362,7 +361,6 @@ class App.Search extends App.Controller
|
||||
'click': callbackCheckbox
|
||||
select_all: callbackCheckbox
|
||||
sortClickCallback: @saveOrderBy
|
||||
callbackHeader: [ @markRelationHeadersUnsortable ]
|
||||
pagerAjax: true
|
||||
)
|
||||
|
||||
@@ -425,7 +423,6 @@ class App.Search extends App.Controller
|
||||
events:
|
||||
'click': openObject
|
||||
sortClickCallback: @saveOrderBy
|
||||
callbackHeader: [ @markRelationHeadersUnsortable ]
|
||||
pagerEnabled: false
|
||||
orderEnabled: false
|
||||
pagerAjax: true
|
||||
@@ -471,11 +468,9 @@ class App.Search extends App.Controller
|
||||
newColumn = $(e.currentTarget).closest('[data-column-key]').attr('data-column-key')
|
||||
|
||||
config = _.find App[@model].configure_attributes, (elem) -> elem.name == newColumn
|
||||
return if !config
|
||||
|
||||
# Search results are sorted by Elasticsearch, which can only sort a relation by
|
||||
# its raw reference (e.g. customer_id) and not by the displayed name.
|
||||
return if config.relation
|
||||
# There's no reliable way to sort to-many relations. Sorry.
|
||||
return if config.multiple && config.relation
|
||||
|
||||
current = @getSavedOrderBy()
|
||||
|
||||
@@ -544,11 +539,6 @@ class App.Search extends App.Controller
|
||||
getSavedOrderBy: =>
|
||||
@savedOrderBy[@model]
|
||||
|
||||
markRelationHeadersUnsortable: (headers) ->
|
||||
for header in headers when header.relation
|
||||
header.unsortable = true
|
||||
headers
|
||||
|
||||
saveOrderBy: (table) =>
|
||||
return if !table
|
||||
|
||||
|
||||
@@ -248,7 +248,6 @@ class App.TicketOverviewTable extends App.Controller
|
||||
attribute =
|
||||
name: 'icon_priority'
|
||||
display: ''
|
||||
parentClass: 'table-priority-icon'
|
||||
translation: false
|
||||
width: '24px'
|
||||
displayWidth: 24
|
||||
|
||||
@@ -37,14 +37,12 @@ class App.TicketZoomTimeAccountingModal extends App.ControllerModal
|
||||
{ name: 'time_unit', display: __('Accounted Time'), tag: 'input', type: 'text', null: false, placeholder: __('Enter the time you want to record'), appendText: @timeAccountingDisplayUnit() }
|
||||
]
|
||||
|
||||
activeTypes = App.TicketTimeAccountingType.search(filter: { active: true })
|
||||
if @Config.get('time_accounting_types')
|
||||
|
||||
# An empty type list would only render an empty select, so the field needs an active type
|
||||
# next to the enabled setting.
|
||||
if @Config.get('time_accounting_types') and _.isEmpty(activeTypes) is false
|
||||
|
||||
# Pre-select the default activity type, but only if it's still active.
|
||||
defaultTypeId = _.findWhere(activeTypes, { id: @Config.get('time_accounting_type_default') })?.id
|
||||
# Pre-select the default activity type, but only if it's active.
|
||||
if @Config.get('time_accounting_type_default')
|
||||
defaultType = App.TicketTimeAccountingType.find(@Config.get('time_accounting_type_default'))
|
||||
defaultTypeId = defaultType.active and defaultType.id
|
||||
|
||||
configure_attributes.push
|
||||
name: 'accounted_time_type_id'
|
||||
|
||||
@@ -33,7 +33,6 @@ class App.HttpLog extends App.Controller
|
||||
|
||||
@html App.view('widget/http_log')(
|
||||
records: @records
|
||||
header: @header # false when the embedding screen draws the heading itself
|
||||
description: @description
|
||||
relatedObjects: relatedObjects
|
||||
hasRelatedObjects: !_.isEmpty(relatedObjects)
|
||||
|
||||
@@ -75,8 +75,6 @@ class App.TicketBatch extends App.Controller
|
||||
))
|
||||
|
||||
startDragItem: (event) =>
|
||||
return if @dragEnabled && !@dragEnabled()
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
App.TicketOverviewCollection.fetch()
|
||||
|
||||
@@ -78,7 +78,6 @@ class App.TicketList extends App.Controller
|
||||
attribute =
|
||||
name: 'icon_priority'
|
||||
display: ''
|
||||
parentClass: 'table-priority-icon'
|
||||
translation: false
|
||||
width: '22px'
|
||||
displayWidth: 22
|
||||
@@ -112,9 +111,6 @@ class App.TicketList extends App.Controller
|
||||
callbackHeader = [ callbackIconHeader, callbackIconPriorityHeader ]
|
||||
callbackAttributes.icon_priority = [ callbackIconPriority ]
|
||||
|
||||
if @callbackHeader
|
||||
callbackHeader = callbackHeader.concat(@callbackHeader)
|
||||
|
||||
list = []
|
||||
for ticket_id in @ticket_ids
|
||||
ticketItem = App.Ticket.fullLocal(ticket_id)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
class App.AIAnalyticsDownload
|
||||
# @param type [String] the report type, `with_usages` or `errors`
|
||||
# @param filters [Object] narrows the report down, keyed like the filters of the endpoint
|
||||
# @param button [jQuery, undefined] disabled while the request runs
|
||||
@request: ({ type, filters = {}, button }) ->
|
||||
button?.prop('disabled', true)
|
||||
|
||||
App.Ajax.request(
|
||||
type: 'GET'
|
||||
url: "#{App.Config.get('api_path')}/ai/analytics/download/#{type}"
|
||||
data: { filters: filters }
|
||||
processData: true
|
||||
dataType: 'binary'
|
||||
contentType: 'application/octet-stream'
|
||||
xhrFields:
|
||||
responseType: 'blob'
|
||||
success: (data, status, xhr) ->
|
||||
App.Utils.downloadFileFromBlob(data, xhr, { fallbackFilename: "ai_analytics_#{type}.xlsx" })
|
||||
button?.prop('disabled', false)
|
||||
error: (xhr, status, error) ->
|
||||
App.Log.error('App.AIAnalyticsDownload', error || status)
|
||||
App.Event.trigger('notify',
|
||||
type: 'error'
|
||||
msg: __('The download could not be started. Please try again later.')
|
||||
)
|
||||
button?.prop('disabled', false)
|
||||
)
|
||||
@@ -1,70 +0,0 @@
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
# Routes an AI feature to a provider connection: the options an admin picks from, and the routing
|
||||
# row written behind the pick. Shared by the provider modal of the AI feature pages and the
|
||||
# translation integration.
|
||||
class App.AIFeatureProvider
|
||||
# The option that stands for "no routing row" - the default connection serves the feature.
|
||||
@defaultValue: 'default'
|
||||
|
||||
# @param connections [Array<App.AIProviderConnection>]
|
||||
# @return [Array<Object>] select options, the default entry first
|
||||
@options: (connections) ->
|
||||
connections = _.sortBy(connections, 'name')
|
||||
defaultConnection = _.find(connections, (connection) -> connection.default_chat)
|
||||
|
||||
# String values, because the form hands every value back as a string. A numeric value would
|
||||
# stop matching after a re-render, and the select would invent a "historical" option for it.
|
||||
options = _.map(connections, (connection) -> { name: connection.name, value: connection.id.toString() })
|
||||
|
||||
options.unshift(
|
||||
name: App.i18n.translateInline('Default (%s)', defaultConnection?.name or App.i18n.translateInline('none'))
|
||||
value: @defaultValue
|
||||
)
|
||||
|
||||
options
|
||||
|
||||
# @param row [Object, undefined] the routing row of the feature, if there is one
|
||||
# @return [String] the option value that preselects it
|
||||
@valueFor: (row) ->
|
||||
row?.provider_connection_id?.toString() or @defaultValue
|
||||
|
||||
# Writes the routing row the picked option stands for. `success` receives the row as the server
|
||||
# returned it, or null once the default entry removed the row; `error` receives a message.
|
||||
@save: ({ identifier, row, value, success, error }) ->
|
||||
failed = (xhr) ->
|
||||
details = xhr?.responseJSON or {}
|
||||
error(details.error_human or details.error or __('The provider could not be updated.'))
|
||||
|
||||
if value is @defaultValue
|
||||
return success(null) if !row
|
||||
|
||||
# Back to the default connection = remove the routing row.
|
||||
return App.Ajax.request(
|
||||
id: 'ai_feature_provider_save'
|
||||
type: 'DELETE'
|
||||
url: "#{App.Config.get('api_path')}/ai/feature_providers/#{row.id}"
|
||||
success: -> success(null)
|
||||
error: failed
|
||||
)
|
||||
|
||||
data = { provider_connection_id: parseInt(value, 10) }
|
||||
|
||||
if row
|
||||
App.Ajax.request(
|
||||
id: 'ai_feature_provider_save'
|
||||
type: 'PUT'
|
||||
url: "#{App.Config.get('api_path')}/ai/feature_providers/#{row.id}"
|
||||
data: JSON.stringify(data)
|
||||
success: success
|
||||
error: failed
|
||||
)
|
||||
else
|
||||
App.Ajax.request(
|
||||
id: 'ai_feature_provider_save'
|
||||
type: 'POST'
|
||||
url: "#{App.Config.get('api_path')}/ai/feature_providers"
|
||||
data: JSON.stringify(_.extend({ identifier }, data))
|
||||
success: success
|
||||
error: failed
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
# Keep in sync with the backends in app/services/service/content_translation/backend/.
|
||||
App.Config.set('ai', {
|
||||
key: 'ai'
|
||||
label: __('AI provider')
|
||||
prio: 1000
|
||||
|
||||
# ControllerForm attributes for the credentials of this service. AI keeps its credentials in
|
||||
# the AI provider manager, so it has nothing of its own to ask for.
|
||||
credential_attributes: []
|
||||
|
||||
ai_feature_identifier: 'translate'
|
||||
|
||||
# An installation without AI at all deactivates its permission - then the service is not offered
|
||||
# either. A switched-off AI provider is a different case: the switch can come back, so the
|
||||
# service stays selectable and the integration warns about the switch instead.
|
||||
available: -> App.Permission.findByAttribute('name', 'admin.ai_provider')?.active isnt false
|
||||
}, 'ContentTranslationServices')
|
||||
@@ -1,26 +0,0 @@
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
# Keep in sync with the backends in app/services/service/content_translation/backend/.
|
||||
App.Config.set('deepl', {
|
||||
key: 'deepl'
|
||||
label: __('DeepL')
|
||||
prio: 3000
|
||||
|
||||
credential_attributes: [
|
||||
{
|
||||
name: 'tier'
|
||||
display: __('API plan')
|
||||
tag: 'select'
|
||||
null: false
|
||||
nulloption: true
|
||||
translate: true
|
||||
options: [
|
||||
{ name: __('Developer API (api-free.deepl.com)'), value: 'free' }
|
||||
{ name: __('Growth/Enterprise API (api.deepl.com)'), value: 'pro' }
|
||||
]
|
||||
}
|
||||
{ name: 'api_key', display: __('API key'), tag: 'input', type: 'text', input_type: 'password', null: false }
|
||||
]
|
||||
|
||||
available: -> true
|
||||
}, 'ContentTranslationServices')
|
||||
@@ -1,19 +0,0 @@
|
||||
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
# Keep in sync with the backends in app/services/service/content_translation/backend/.
|
||||
App.Config.set('libre_translate', {
|
||||
key: 'libre_translate'
|
||||
label: __('LibreTranslate')
|
||||
prio: 2000
|
||||
|
||||
# ControllerForm attributes for the credentials of this service. The names are the keys the
|
||||
# backend reads from the service config, and 'api_key' is also the spelling the settings
|
||||
# controller masks on.
|
||||
credential_attributes: [
|
||||
{ name: 'url', display: __('URL'), tag: 'input', type: 'url', null: false, placeholder: 'https://libretranslate.com' }
|
||||
{ name: 'api_key', display: __('API key'), tag: 'input', type: 'text', input_type: 'password', null: true }
|
||||
]
|
||||
|
||||
# Unlike AI, LibreTranslate has no part of the installation it could be missing with.
|
||||
available: -> true
|
||||
}, 'ContentTranslationServices')
|
||||
@@ -27,10 +27,10 @@ class App.PopoverProvider
|
||||
|
||||
build: (buildParams) ->
|
||||
return if !@checkPermissions()
|
||||
@clear()
|
||||
@clear(@popovers)
|
||||
@bind() if !buildParams.doNotBind
|
||||
return if buildParams.isTouchDevice is true
|
||||
@buildPopovers()
|
||||
@popovers = @buildPopovers()
|
||||
|
||||
checkPermissions: ->
|
||||
@params.parentController.permissionCheck(@constructor.permission)
|
||||
@@ -49,7 +49,7 @@ class App.PopoverProvider
|
||||
|
||||
selector = supplementaryData.selector || ".#{@cssClass()}"
|
||||
|
||||
elements = @params.parentController.el.find(selector).popover('destroy').popover(
|
||||
@params.parentController.el.find(selector).popover('destroy').popover(
|
||||
trigger: 'hover'
|
||||
container: 'body'
|
||||
html: true
|
||||
@@ -62,21 +62,16 @@ class App.PopoverProvider
|
||||
content: ->
|
||||
context.buildContentFor(@, supplementaryData)
|
||||
)
|
||||
elements.on('show.bs.popover', (e) -> context.onShow(e, @))
|
||||
elements.on('hide.bs.popover', (e) -> context.onHide(e, @))
|
||||
|
||||
# A re-render strips the old trigger elements' data, so `popover('destroy')` on them is a no-op
|
||||
# and leaves an already shown tip behind in the body.
|
||||
@popoverInstances = elements.map(-> $(@).data('bs.popover')).get()
|
||||
@params.parentController.el.find(selector).on('show.bs.popover', (e) -> context.onShow(e, @))
|
||||
@params.parentController.el.find(selector).on('hide.bs.popover', (e) -> context.onHide(e, @))
|
||||
|
||||
clear: ->
|
||||
return if !@popoverInstances
|
||||
popover.destroy() for popover in @popoverInstances when popover.$element
|
||||
@popoverInstances = null
|
||||
return if !@popovers
|
||||
@popovers.popover('destroy')
|
||||
|
||||
hide: ->
|
||||
return if !@popoverInstances
|
||||
popover.hide() for popover in @popoverInstances
|
||||
return if !@popovers
|
||||
@popovers.popover('hide')
|
||||
|
||||
buildTitleFor: (elem) ->
|
||||
'title'
|
||||
|
||||
@@ -19,9 +19,8 @@ class UserTicket extends App.PopoverProviderAjax
|
||||
|
||||
build: (buildParams) ->
|
||||
return if !@checkPermissions()
|
||||
@clear()
|
||||
@buildParams = buildParams
|
||||
@buildPopovers(ticketList: {}, selector: buildParams.selector)
|
||||
@popovers = @buildPopovers(ticketList: {}, selector: buildParams.selector)
|
||||
|
||||
buildContentFor: (elem, supplementaryData) ->
|
||||
return super if _.isEmpty(supplementaryData.ticketList)
|
||||
|
||||
@@ -109,14 +109,13 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
|
||||
renderResponseItemAjax: (elem, data) ->
|
||||
result = _.find(data.details, (detailElem) -> detailElem.type == elem.type and detailElem.id == elem.id)
|
||||
|
||||
# The details are escaped HTML, while the option template escapes what it is given.
|
||||
category = undefined
|
||||
if result.type is 'KnowledgeBase::Answer::Translation' && result.subtitle
|
||||
category = App.Utils.html2text(result.subtitle)
|
||||
category = result.subtitle
|
||||
if result
|
||||
{
|
||||
category: category
|
||||
name: App.Utils.html2text(result.title)
|
||||
name: result.title
|
||||
value: elem.id
|
||||
}
|
||||
|
||||
|
||||
@@ -686,10 +686,9 @@
|
||||
.result
|
||||
.map(function(elem) {
|
||||
if(result = _.find(data.details, function(detailElem) { return detailElem.type == elem.type && detailElem.id == elem.id })) {
|
||||
// The details are escaped HTML, while the list below shows them as text.
|
||||
return {
|
||||
'category': App.Utils.html2text(result.subtitle),
|
||||
'name': App.Utils.html2text(result.title),
|
||||
'category': result.subtitle,
|
||||
'name': result.title,
|
||||
'value': elem.id,
|
||||
'url': result.url
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
<%# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/ %>
|
||||
|
||||
<p><%- @T('Semantic search will stop working until another provider is selected for it.') %></p>
|
||||
<p><%- @T('The knowledge base index is kept, so selecting the same provider again requires no re-index.') %></p>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<div class="js-missingProviderAlert alert alert--warning <% if !@visible: %>hide<% end %>">
|
||||
<%- @T('The AI provider configuration is disabled. Before proceeding, please set up at least one provider in |AI > Providers|. %l', '#ai/providers') %>
|
||||
<%- @T('The provider configuration is disabled. Before proceeding, please set up at least one provider in |AI > Providers|.') %>
|
||||
</div>
|
||||
@@ -1,3 +1,4 @@
|
||||
<%# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/ %>
|
||||
<div class="zammad-switch zammad-switch--small js-ai-provider-toggle">
|
||||
<input name="ai_provider" type="checkbox" id="setting-ai_provider" aria-label="<%- @T('Enable AI provider') %>" <% if @ai_provider: %>checked<% end %>>
|
||||
<label for="setting-ai_provider" aria-hidden="true"></label>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user