Commit Graph
27945 Commits
Author SHA1 Message Date
Lord VB | Evernix 15fd2639c8 fix(time-off): apply the requested sort order in time off pagination (#10335)
* fix(time-off): apply the requested sort order in time off pagination

The Time Off table sorts on the server (ServerDataSource sends
order[start]=ASC etc.), but TimeOffRequestService.pagination builds its
own query and ignored options.order in both the TypeORM and MikroORM
branches, so sorting by Start, End or Request Date had no effect.

Pass the requested order to the ORM, keeping only the sortable date
columns (start, end, requestDate) with an ASC/DESC direction.

Closes #1941

* fix(time-off): only accept string sort directions

Read the direction only when the query value is a string instead of
stringifying any value (Sonar S6551: objects would become '[object Object]').

* fix(time-off): keep the client's sort key precedence

Iterate the requested order keys instead of the allowlist, so a
multi-column sort keeps the order the client asked for.
v111.44.81
2026-09-29 20:07:20 +02:00
joel kalema a73de1d121 Feat/add employee dialog polish (#10336)
* feat(i18n): add strings for the add-employee dialog and form sections

* feat(user-forms): upload the profile photo through the shared avatar uploader

* feat(user-forms): group basic info fields into profile, account and employment sections

* feat(employees): track queued employees and the current entry in the add dialog

* feat(employees): redesign the add-employee dialog with labelled steps, review list and fixed footer

* style(employees): style the add-employee dialog header, steps, list and footer

* feat(tags): draw the picker checkbox and show selected tags as tinted labels

* style(tags): compact rows for the tag picker dropdown panel

* fix(employees): vertically centre the Show Deleted toggle in the header

* fix(employees): give Status and Screen Capture columns room from Name and Email

* fix(employees): address review feedback on the add-employee dialog

- mark template-only members protected
- translate the step bar's aria-label
- clear loading in a finally block so a failed create can be retried
- fit the step bar on narrow dialogs by naming only the current step

* fix(employees): resolve SonarCloud reliability issues in touched files

- mark fire-and-forget promises with void (typescript:S9383)
- drop async from delete(), which awaits nothing (typescript:S7503)

* fix(user-forms): hide SUPER_ADMIN from the role picker once the permission check resolves

excludeRoles() resolves after the role field may already have rendered its
options, and it mutated the excludes array in place, so the field kept
offering SUPER_ADMIN to users without that role.

- basic info form: assign a new excludes array instead of pushing
- role field: cache the fetched roles and re-filter them whenever excludes
  changes, clearing a selection that is no longer allowed

* fix(user-forms): keep a preselected role until the role list has loaded

applyExcludes() also runs from the excludes setter, which can fire before
getAll() returns. With no roles loaded every preselected role looked
disallowed and was cleared. Only check the selection once the roles have
loaded; renderRoles() re-runs the check at that point.
v111.44.80
2026-09-29 20:06:44 +02:00
Sairaj-24 b00a36df4f fix(timer): toast a setting change only when the value changes (#10315)
* fix(timer): toast a setting change only when the value changes

Re-clicking the same Desktop Timer setting wrote it again and stacked another success alert. Skip the write and the toast when the stored value is unchanged.

Fixes #8479

* fix(timer): compare settings against the last saved value

SSL and auto-start edit the stored object before the equality check, so those saves were skipped.
v111.44.79
2026-09-29 14:59:47 +02:00
Ruslan KonviserandClaude Opus 5.5 74d538b770 test(core): pin what the tenant-isolation guards actually do (#10328)
* test(core): pin what the tenant-isolation guards actually do

TenantBaseGuard and TenantPermissionGuard gate most controllers
(@UseGuards(TenantPermissionGuard, PermissionGuard)), yet no spec exercised
them: every other suite mocks or overrides them. This adds 39 behavioural
tests covering the tenant from the request context, the tenant-id header
path, the GET/DELETE query and data.findInput paths, the POST/PUT/PATCH body
paths, @Public, the super-admin switch, handler-over-controller permission
metadata, de-duplication, and the 5-minute permission cache (hit, miss,
per-role key).

Two current behaviours are pinned deliberately and documented in the spec,
not changed: a matching tenant-id header is the whole check (a body or
query tenantId naming another tenant passes the guard, so services must take
the tenant from context), and a permission verdict is cached for 5 minutes.

Mutation-checked: making the header or body comparison always pass,
ignoring the base guard's verdict, dropping the allowSuperAdminRole switch,
or changing the cache TTL each turns the suite red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(core): follow the house let/const rule and drop the lint findings in the guard spec

Review follow-up (Greptile). The context helper now declares the request
headers with let and rebuilds them instead of mutating a const, per the
repository's rule. Also clears the ESLint error (empty stub function) and
the nine no-explicit-any warnings the new spec added: typed casts through
unknown, and one typed handle on env.allowSuperAdminRole. Still 39/39, and
all five guard mutations are still caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
v111.44.78
2026-09-29 13:42:21 +02:00
Joe HuberandRuslan Konviser 72604aef90 chore(git): add github issue templates (#10330)
* chore(git): add github issue templates

* Update config.yml

* Reorder community links in issue template

---------

Co-authored-by: Ruslan Konviser <evereq@gmail.com>
v111.44.77
2026-09-29 13:41:28 +02:00
joel kalema 4c0d30c4e1 Feat/task details polish (#10329)
* feat(record-view): add opt-in wide input to the record drawer

* feat(record-view): toggle the wide drawer class from the input

* style(record-view): size and pad the wide drawer for long-form content

* feat(tasks): render task descriptions from GitHub-flavoured markdown and safe HTML

* feat(tasks): add task view component deriving pills, people and description

* feat(tasks): lay out task view like an issue tracker with a collapsible details panel

* style(tasks): style task view details, avatars and markdown content

* feat(tasks): declare the task view component

* feat(tasks): show the task view in the wide drawer

* refactor(tasks): drop the record-view descriptor now served by the task view

* feat(record-view): add markdown and status field types, section variants and row icons

* feat(record-view): render panels, person chips, status and markdown in the shared view

* feat(tasks): describe the task view through the shared record view

* refactor(tasks): remove the separate task view component

* refactor(record-view): split markdown block rendering into per-block renderers

* refactor(record-view): derive avatar hue without bitwise truncation

* fix(record-view): keep fenced code intact when stripping comments and split list parsing

* fix(record-view): guard meta rows by permission and use inject() with class bindings

* fix(tasks): honour done statuses when flagging an overdue task

* fix(record-view): close code fences only on a matching fence and resolve Sonar findings in the markdown renderer

* style(record-view): merge the duplicate wide drawer selector

* fix(record-view): detect tilde fences, keep terminal # in headings and make placeholder restoration terminate

* fix(record-view): strip placeholder marks from reference URLs and restore placeholders in one pass
v111.44.76
2026-09-29 13:34:28 +02:00
Ruslan KonviserandClaude Opus 5.5 c12fc11a50 fix(auth): make email verification work end to end and stop register dead-ends (#10332)
* fix(auth): make email verification work end to end and stop register dead-ends

Verification link and notice
- /auth/confirm-email no longer sits behind NoAuthGuard. Registering signs the
  user in, so the emailed link was opened by a signed-in user, redirected to the
  dashboard before the resolver ran, and never verified anything. The token is
  still required and still single use (the API clears it on success).
- A refused or expired link now shows its message instead of an endless spinner,
  and a successful one marks the signed-in user verified in the store.
- New "verify your email" notice with Resend (POST /auth/email/verify/resend-link,
  already throttled 3/min) in the main layout and on tenant onboarding. It shows
  only when GET /auth/email/verify/status (new, same feature flag, so 404 where
  verification is off) confirms the user is unverified.
- Settings > Billing: an unverified admin with no linked subscription is told a
  paid plan connects once the address is verified.

Email sending
- Templates fall back to English when the recipient's locale has none, instead
  of rendering an empty email (verification exists only in en/bg/he/ru).
- Send failures are logged with the provider code, SMTP reply code and command,
  every address masked; verification sends are now recorded in email_sent with
  status SENT/FAILED (subject only, never the link). A transport that fails
  verification throws instead of returning undefined.
- resend-link answers 503 when the provider refused the message, not "OK".
- The verification link encodes the address (plus-addressing survived as a space).
- A caller-supplied appEmailConfirmationUrl is honoured only on an origin this
  deployment serves (CLIENT_BASE_URL, the configured links, EMAIL_LINK_ALLOWED_ORIGINS;
  "*" disables the check).
- Auth emails carry X-PM-TrackLinks: None so Postmark stops storing tokens as clicks.
- {{appLink}} falls back to CLIENT_BASE_URL when APP_LINK is empty: every
  hosted deployment has APP_LINK empty, so welcome emails linked to localhost:4200.

Register
- A refused sign-up shows the API's 4xx message (e.g. "A subscription is
  required...") instead of "Something went wrong", and the 403 checkoutUrl is
  offered as a "Continue to checkout" button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(auth): confirm-email trusts the API, not the link, for who was verified

Review follow-ups on the confirm-email page:
- After a successful confirmation, re-read GET /auth/email/verify/status
  instead of comparing the link's email parameter with the signed-in user.
  The token decides which account was confirmed; the email parameter is not
  bound to it.
- A request that got no HTTP answer (status 0) is shown as a connection
  problem, not as an invalid link.
- ActivatedRoute, Store and AuthService come from inject().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(auth): apply a verification status only to the user it was asked for

If a different user signs in while the status or resend request is in flight,
the answer no longer updates the new user's verification state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui-core): drop a resend answer once another user has signed in

The verification notice now tracks the user it speaks for. A different user
signing in cancels the pending resend and resets its state, and a late answer
for the previous user changes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui-core): a dismissed verification notice stays dismissed only for that user

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
v111.44.75
2026-09-29 12:32:46 +02:00
Ruslan KonviserandClaude Opus 5.5 c213fb3ea6 chore(cspell): ignore the malformed-session-id fixture word in the billing spec (#10334)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v111.44.74
2026-09-29 11:48:24 +02:00
Ruslan KonviserandClaude Opus 5.5 ba62a02001 fix(billing): scope Stripe linking, paywall and billing pages to this deployment's product (#10331)
Product-scoped (hosted plan only) Stripe webhook linking, signup paywall, lazy tenant link and /billing routes; checkout-session proof at register/onboarding; BILLING_PRODUCT, BILLING_SIGNUP_PAYWALL and BILLING_WEBHOOK_LINKING (default off); 402 payment_method_required on a paid upgrade without a card. See the PR description for details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v111.44.73
2026-09-29 11:34:26 +02:00
Lord VB | Evernix 367a01a66d fix(desktop): use a single ErrorHandler that forwards to Sentry and ErrorHandlerService (#10326)
* fix(desktop): use a single ErrorHandler that forwards to Sentry and ErrorHandlerService

The desktop, agent and desktop-timer apps registered two ErrorHandler
providers. Angular only keeps the last one, so either Sentry never saw
uncaught errors (desktop) or the app toast/logging handler was dead
(agent, desktop-timer).

Replace both with one factory provider that delegates to the Sentry
handler and then to ErrorHandlerService. Sentry console logging is
disabled since ErrorHandlerService already logs the error.

Closes #9106

* refactor(desktop-ui-lib): extract provideGlobalErrorHandler to remove duplicated provider

Move the combined ErrorHandler factory into desktop-ui-lib so the three
desktop apps share one implementation. The reporting handler (Sentry) is
passed in, so desktop-ui-lib does not need a Sentry dependency.

* fix(desktop-ui-lib): always run ErrorHandlerService and guard nullish errors in global handler

Run ErrorHandlerService in a finally block so a throwing reporting handler
cannot skip it, and wrap nullish values in an Error before passing them to
ErrorHandlerService. The value sent to the reporting handler is unchanged.
v111.44.72
2026-09-28 19:54:07 +02:00
joel kalema a15f8536cd Feat/accounting dashboard polish (#10327)
* feat(i18n): add English strings for the accounting dashboard view

* feat(dashboard): redesign the accounting dashboard with KPIs, cash-flow chart and sortable breakdown

* fix(dashboard): keep employee chart legend items at the list font size

* feat(i18n): add Acholi strings for the accounting dashboard view

* feat(i18n): add Arabic and Hebrew strings for the accounting dashboard view

* feat(i18n): add Bulgarian strings for the accounting dashboard view

* feat(i18n): add German strings for the accounting dashboard view

* feat(i18n): add Spanish strings for the accounting dashboard view

* feat(i18n): add French strings for the accounting dashboard view

* feat(i18n): add Italian strings for the accounting dashboard view

* feat(i18n): add Dutch strings for the accounting dashboard view

* feat(i18n): add Polish strings for the accounting dashboard view

* feat(i18n): add Portuguese strings for the accounting dashboard view

* feat(i18n): add Russian strings for the accounting dashboard view

* feat(i18n): add Chinese strings for the accounting dashboard view

* fix(dashboard): address accounting dashboard review findings

- keep the signed income share for the label, clamp only the bar
- reject non-positive total income as a percentage denominator
- add a screen-reader table of the chart's daily values
- let long KPI amounts wrap instead of truncating
- format chart dates in the active UI language
- translate the accounting view strings in Hebrew and Acholi

* feat(dashboard): restore the cash-flow chart's day grid, point dots and full axis labels

- draw a vertical grid line per date, in the value grid's colour
- show a dot on every day for each series
- label the y-axis with full figures and the x-axis with full dates

* feat(dashboard): add a sort control to the earnings breakdown

- add a sort-by select and a direction toggle to the breakdown header
- sort by total expenses, highest first, by default
- start-align the money columns and trail their sort arrows
- narrow the employee column so the money columns get more room
- add the sort label and direction strings in every locale

* refactor(dashboard): inject the accounting view's theme service and currency pipe with inject()

* fix(dashboard): address accounting chart and header review findings

- keep a vertical grid line for every date; thin only the colliding labels
- format y-axis figures in the active UI language
- let the breakdown panel header and sort controls wrap on narrow screens

* fix(dashboard): read the x-axis tick font through CartesianScaleOptions
v111.44.71
2026-09-28 19:53:11 +02:00
joel kalema 702a02bb28 Fix/documents actions column (#10323)
* fix(docs-ui): let the table row kebab open its actions menu

nbContextMenu's click trigger listens on document, so stopping the click on the button meant the menu never opened. The table's row-open handler already ignores clicks from buttons.

* docs(docs-ui): update the table double-click guard comment

* fix(docs-ui): let the card kebab open its actions menu

The card body now skips clicks, double clicks and Enter coming from its kebab instead of the kebab stopping propagation, which kept nbContextMenu from ever opening.

* fix(docs-ui): keep a tree node from activating on a kebab click

Override the tree's mouse click action so a click on the node menu button does not toggle the active node.

* fix(docs-ui): let the tree node kebab open its actions menu

Drop the stopPropagation that kept nbContextMenu (and the Shift+F10 path) from opening the node menu.

* feat(docs-ui): add column icons and column chooser strings

Per-column Eva icons and the DOCS.TABLE strings for the column count, the locked and auto-hidden hints, Show all and Reset to default.

* feat(docs-ui): add show-all, reset and visibility state to the column chooser

Visible-column count, whether any preference is stored, which columns the narrow-viewport defaults hid, and actions to show every column or drop the stored preferences.

* fix(docs-ui): open the column chooser and redesign it

nbTooltip and nbPopover on the same button shared one NbDynamicOverlay, so a click only ever showed the tooltip. The tooltip now sits on a wrapper.

The chooser becomes a list of switch rows with column icons, a locked Name row, an auto-hidden hint for narrow screens, a live count and Show all / Reset to default actions.

* feat(docs-ui): group the document actions menu and make it context-aware

Every item gets an icon and the menu is split into sections (open, create, organize, share, AI, destructive) with dividers only between non-empty ones. Delete is marked danger and the tree shows its F2 and Del shortcuts.

A FILE row offers Preview instead of a second, identical Open; Open on a folder or page says where it goes; Duplicate with children is dropped for a container the list reports as empty.

* feat(docs-ui): tag the table, card and tree action menus with a shared class

Pass DOCS_ACTION_MENU_CLASS through nbContextMenuClass so the three kebab menus can be styled as one.

* style(docs-ui): restyle the document actions menu

Compact rows with icons, rounded hover, section dividers, key-cap shortcut hints and a red Delete. Global on purpose: the menu renders in the CDK overlay, and the shell wraps every Documents route.

* feat(docs-ui): add the actions menu to folder cards

Folder cards had no kebab, so in card view a folder could only be drilled into. The kebab sits beside the folder card button in a wrapper, since a button may not contain another one.

* refactor(docs-ui): mark template-only members protected

Follows the Angular guideline for the column chooser members and the action menu class added in this branch.

* fix(docs-ui): keep tree key handling off the node menu button

The tree handles Enter and Space on body and calls preventDefault, which cancelled the menu button's own click. The button now stops their propagation without preventing the default. Also marks the tree's actionMenuClass protected.
v111.44.70
2026-09-28 13:39:43 +02:00
Ruslan Konviser 023811d5a3 Merge pull request #10325 from ever-co/fix/cspell-unit-test-harness
chore(cspell): declare or reword the words #10324 added
v111.44.69
2026-09-28 11:17:23 +02:00
Ruslan KonviserandClaude Opus 5.5 5c8d4e1c8c chore(cspell): declare or reword the words #10324 added
The develop push of #10324 (9a6f8787) failed "Check Spelling and Typos
with cspell" (run 36399734369): 13 issues in 5 files. PRs into develop
run no cspell, so this surfaced only after the merge.

- "Nx's" (4x) and "callables": reworded in the comments.
- "internmap" (a d3 dependency, npm package name): added to .cspell.json.
- "avascript" / "msdt" in the safe-url spec: file-level cspell:ignore,
  as the repo does elsewhere; they are the tail of the entity-encoded
  "javascript:" payloads and the ms-msdt: scheme the tests feed in.

Comment, dictionary and directive changes only; no code or config
behaviour changes. Local cspell 6.31.3 on the five files: 0 issues
(the pre-fix safe-url spec, as a control: 6 issues).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:04:48 +02:00
Ruslan Konviser 9a6f878700 Merge pull request #10324 from ever-co/fix/unit-tests-hermetic-harness
test: make the Unit Tests workflow green (97/97 projects): hermetic env, Angular jest harness, stub specs
v111.44.68
2026-09-28 10:50:02 +02:00
Ruslan KonviserandClaude Opus 5.5 89d3d51c98 test(docs-ui): check the absolute ceiling on one cold call, before the batches
A synchronous call cannot be interrupted (Jest's timeout included), so a
grossly slow isAllowedUrl is now reported after ONE call on the smaller
hostile input - the same single cold call the old 100/200 ms asserts
timed - instead of after the batches and the fourfold input have
multiplied the wait (CodeRabbit). Running each measurement in a child
process, as also suggested, is not done: a call that never returns
already ends in a failure (the job timeout), never a pass, and spawn/IPC
time would be billed to the measurements.

Known-dirty control (local): an injected O(n^2/200) scan in
isAllowedUrl makes the data: linearity test fail with a growth factor of
16.8 against the < 10 bound; the restored code passes (docs-ui 541/541).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:49:53 +02:00
Ruslan KonviserandClaude Opus 5.5 dc0897c29d test: address review findings on the unit-test harness
- docs-ui safe-url linearity tests: time each input size in batches of
  calls (doubled until a batch runs >= 50 ms, median of three) and take
  the growth ratio as measured, with no 1 ms floor that could understate
  growth for sub-millisecond samples (CodeRabbit). Keep a generous
  absolute ceiling (3 s per rejection of the smaller input, ~9x the
  slowest CI reading) so a uniformly slow validator cannot pass either.
- role-permission demo-mode suite: state its scope precisely. The reload
  only adds rows, so it never removes a deletion grant a tenant already
  holds; the seed and RolePermissionService keep demo tenants free of it,
  and PermissionGuard has no demo-mode rule (a product question, out of
  scope for this test-harness PR).
- Sonar: String.raw for the transformIgnorePatterns regex (pattern
  verified byte-identical), startsWith in jest.resolver.js, and no
  blanket eslint-disable in the new activepieces jest config (its
  template, integration-make-com, has none; eslint clean).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:26:56 +02:00
Ruslan Konviser efdba39b6b Merge remote-tracking branch 'origin/develop' into fix/unit-tests-hermetic-harness 2026-09-28 09:03:49 +02:00
Ruslan KonviserandClaude Opus 5.5 e39e9323c6 test: finish the Angular stub specs; interop for callable CJS, d3 transforms
Local runs after this commit: ui-core 45/45 suites, ui-auth 4/4, gauzy
29/29, desktop-ui-lib 41/41, gauzy-server 2/2, and every plugin UI project
that was red (integration-ai/github/hubstaff/upwork-ui, job-employee/
matching/proposal/search-ui, jobs-ui) green.

- jest.interop.js now patches every callable CommonJS package the code
  imports both ways (moment, randomcolor) with `default` + `__esModule`, so
  both import styles resolve to the function under either esModuleInterop.
  apps/gauzy's spec tsconfig turns esModuleInterop on (as ui-core, docs-ui
  and videos-ui do): ui-core's line chart default-imports
  chartjs-plugin-annotation and Chart.register received undefined.
- jest.preset.js transforms d3-* / internmap (ESM-only, reached through
  @swimlane/ngx-charts).
- desktop-ui-lib specs: section forms get the FormGroup their parent passes,
  cell renderers their rowData, dialogs their data; Settings/Setup/
  ScreenCapture get the library's GAUZY_ENV and the time tracker the
  AuthStrategy/AuthService the desktop apps bootstrap; the task table a
  signed-in session. Two test-side overrides are documented in place:
  LanguageSelectorComponent binds [(ngModel)] without FormsModule (a dead
  binding in the app too), and the plugin source forms use <nb-hint> as a
  plain styled element (Nebular has no such component).
- apps/gauzy: page specs get the date-picker config their route sets,
  the timesheet layout / job pages their route data, the task dialog a
  selected organization (its unguarded async read crashed the Jest worker)
  and a stand-in for docs-ui's links panel (docs-ui's entry point loads a
  PDF viewer that uses import.meta, which CommonJS Jest cannot parse).
- integration-upwork-ui: two hand-written specs used jasmine spies (jest
  has none) and partial Router/TranslateService mocks the template could
  not render with; they use jest.fn() and the real services now.
- gauzy-server's AppComponent spec was the 2021 CLI scaffold (title
  'desktop-web-ui', a "Welcome" h1) and declared a standalone component; it
  now imports it and asserts what the shell does (router outlet, language
  bridge started on init), with the library entry mocked to its one token.
- jobs-ui: the layout spec has asserted a main landmark since it was
  written; the layout now renders <main role="main"> around its outlet (the
  app shell defines no other main landmark).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 00:25:57 +02:00
Ruslan KonviserandClaude Opus 5.5 d3d8687ac1 test: app-wide TestBed defaults for the Angular projects; fix their stub specs (WIP)
Once the Angular suites loaded, most failures were CLI-generated
`should create` stubs that had never run, failing on the first injection
(TranslateService, NbToastrService, NbDialogRef, ActivatedRoute, the
translate pipe, the default icon pack).

- jest.angular-defaults.ts (setupFilesAfterEnv, after each project's
  test-setup): a top-level beforeEach adds what the app's root module
  provides - TranslateModule.forRoot, the Nebular forRoot modules,
  NgxPermissionsModule.forRoot, the Tabler/eva icon pack, HttpClient
  testing, router, noop animations, a NbDialogRef stub, GAUZY_ENV - and a
  matchMedia stand-in (jsdom has none). configureTestingModule merges, so a
  spec's own providers still win. It imports no ui-core/core: that would
  cache real modules a spec later jest.mock()s.
- jest.preset.js maps dayjs/esm (imported by ngx-daterangepicker-material's
  .mjs bundle) to dayjs's CommonJS build.
- Specs of non-standalone components import the NgModule that declares
  them, provide what the host feature module provides (EmployeesService,
  AuthService, NbAuthModule.forRoot, PipesModule), and set the inputs /
  route data / date-picker config the app always supplies before render.
- Two stubs imported classes their files do not export
  (GauzyRangePickerComponent, ViewComponent) and declared `undefined`.
- desktop-ui-lib's test-setup installs an inert `window.electronAPI`
  preload bridge of the shape apps/agent exposes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 22:57:14 +02:00
Ruslan Konviser 95b3529b89 Merge pull request #10321 from ever-co/ci/no-docker-build-records
ci: stop uploading Docker build records and summaries
v111.44.66
2026-09-27 21:30:14 +02:00
Ruslan KonviserandClaude Opus 5.5 e77e3130f4 ci: reword the build-record comment (cspell)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:27:58 +02:00
Ruslan KonviserandClaude Opus 5.5 02c4289f5f test: load moment under both import styles; resolve ui-core's workspace imports from source
Iteration 1 of the hermetic run (36330457608, 83 pass / 14 fail) moved the
Angular suites past TestBed init and into two load-time failures:

- "(0, moment_1.default) is not a function" in ~50 suites across 11
  projects. ui-core imports `moment` as a default import, most other code
  as a namespace import; the bundlers accept both, the TypeScript CJS emit
  Jest runs cannot under a single esModuleInterop setting. jest.interop.js
  (a preset setupFiles entry, concatenated with any project's own) gives
  the loaded module `default` and `__esModule`, so both styles resolve to
  the moment function itself, as they do in the app build.
- "Cannot find module '@gauzy/ui-config'" in 23 ui-core suites: ui-core's
  tsconfig.json maps it to the BUILT dist copy, which a test run does not
  have, and Nx's Jest resolver falls back to the spec tsconfig's paths. The
  spec tsconfig now carries the same source mappings as tsconfig.lib.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:05:39 +02:00
Ruslan KonviserandClaude Opus 5.5 6c68c1fda0 ci: stop uploading Docker build records and summaries
docker/build-push-action uploads a build record (*.dockerbuild) for every image
build. The record stores every build-arg value in plain text, and on a public
repo any signed-in GitHub user can download it. Set DOCKER_BUILD_RECORD_UPLOAD
and DOCKER_BUILD_SUMMARY to false at workflow level in every workflow that uses
the action. BuildKit secrets are never recorded, so nothing else changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:02:42 +02:00
Ruslan Konviser d0b2a8e080 Merge remote-tracking branch 'origin/develop' into fix/unit-tests-hermetic-harness 2026-09-27 20:53:10 +02:00
Ruslan KonviserandClaude Opus 5.5 ab886b135f fix(security): prove GitHub installation ownership before binding it (GHSA-4rwq) (#10318)
* fix(security): prove GitHub installation ownership before binding it (GHSA-4rwq)

POST /integration/github/install bound whatever installation_id the request
body carried, as long as the state nonce belonged to the caller's tenant. The
nonce proves which tenant started the flow, not which GitHub installation that
tenant may bind — and binding hands the tenant the App's token for every
repository in the installation. A tenant could bind another organization's
installation and read its private repositories.

The GitHub App now issues an OAuth code with the post-install redirect ("Request
user authorization (OAuth) during installation"). POST /install — the
authenticated request — exchanges it and binds only an installation the
authorizing GitHub user is entitled to in full:
- a personal installation: the user must be that account;
- an organization installation: the user must already reach every repository
  it covers (their count equals the App's own count, read before and after to
  close a create/delete race).
The code is signed with the nonce it arrived with, so a code leaked from a
post-install URL cannot be replayed against another tenant's nonce, and the
user token is revoked once checked. Without a code the install is refused with
a message naming the GitHub App setting to enable.

Also closes a sibling on the same surface: GithubMiddleware loaded an
integration's settings before authentication using ?tenantId= ahead of the
Tenant-Id header, while the tenant guard validates only the header when one is
sent. Own tenant in the header plus a victim's in the query let the repository,
metadata, issue and sync routes act on the victim's installation. The
middleware now records who owns the settings, and GithubIntegrationTenantGuard
refuses a mismatch after authentication.

The install popup now shows why a connection was refused instead of closing
after two seconds, and handles the update/request redirects GitHub sends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(security): spend the install code at the callback, compare repository ids

Two P1 review findings on the first version of this fix, both correct:

- The post-install callback is public and signed ANY code with ANY live nonce,
  so a leaked, unused victim code plus a nonce from the attacker's own tenant
  still bound the victim's installation — the code binding proved nothing. The
  callback now exchanges the code the moment it arrives (spending it, so it
  cannot be replayed from a URL, history or log), checks entitlement there, and
  hands the browser only a signed, 10-minute proof bound to this flow's nonce
  and installation. The code never reaches the browser, and POST /install binds
  nothing without a valid proof. When there is no proof, install_check tells
  the web app why (no code / not entitled / unverifiable).
- Comparing repository COUNTS could be balanced by a member who creates
  throwaway repositories and deletes them between the reads while the
  repositories hidden from them remain. Entitlement for an organization
  installation is now a set comparison: every repository id the App can reach
  must be one the user can read (user ids read first, App ids after).

Also: installation ids beyond Number.MAX_SAFE_INTEGER are refused (Octokit
takes a number and would check a different installation than the one stored),
member install requests (setup_action=request) no longer hit a raw 400, and the
popup text is translatable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
v111.44.65
2026-09-27 18:26:32 +02:00
Ruslan Konviser 93dd994149 Merge pull request #10312 from ever-co/fix/sentry-quota-flood
fix(sentry): only errors become Sentry events by default; stop logging health probes
v111.44.64
2026-09-27 17:52:30 +02:00
Ruslan Konviser 4c4e554e2b Merge remote-tracking branch 'origin/develop' into fix/sentry-quota-flood 2026-09-27 17:48:39 +02:00
Ruslan KonviserandClaude Opus 5.5 91d91ffca3 test: make the unit-test run hermetic and fix the Angular jest harness
The Unit Tests workflow has never been green (24 of 97 projects red at
develop eac7136562, run 36319732347). Causes addressed here:

- Env leak: Nx loads the committed .env.local (DEMO=true,
  WORKER_QUEUE_ENABLED=false, NODE_ENV=development) into every task.
  The test step now sets NX_LOAD_DOT_ENV_FILES=false, and the two specs
  that depend on a mode pin it themselves (role-permission counts pin
  environment.demo=false and gain a demo-mode suite asserting 209 per
  role; the worker spec clears the queue env before the constants load).
  .env.local is unchanged.
- Angular harness: nohoist gives each workspace its own @angular copy,
  so setupZoneTestEnv() initialised a different TestBed from the one the
  spec used. A workspace resolver (jest.resolver.js, wrapping Nx's) makes
  every @angular/* import in a Jest project resolve to one copy. The
  Angular projects now inherit the preset's transformIgnorePatterns,
  which gains the .mjs exception plus @datorama, @ngneat and lodash-es.
- ui-config's environment.ts is generated and gitignored; the workflow
  runs `yarn config:dev` before the tests, as the Playwright workflow does.
- Misconfigured targets: gauzy (jest.config.js -> .ts, Angular transform,
  setupFile moved into the config), integration-sim-ui (.ts -> .cts),
  integration-activepieces (config file added), mcp-auth (ran
  `node build/main.js --test`; now the jest executor like apps/mcp).
- Real failures: the openai "silence" case used a body with no `text`,
  which the shared helper rejects by contract; the toolbar spec read the
  tabIndex property, which is 0 on any button; the docs-ui linearity
  tests asserted wall-clock bounds, now a 4x-input growth ratio.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 17:39:40 +02:00
Ruslan Konviser 687e617469 Merge pull request #10316 from Sairaj-24/fix/8522-active-action-icons
fix(ui): show invoice View and Payments as active actions
v111.44.63
2026-09-27 17:07:24 +02:00
Ruslan KonviserandClaude Opus 5.5 fba9302a54 fix(sentry): Render asks for the DSN; desktop apps stop printing it
The Render blueprints declare SENTRY_DSN with sync: false, so Render prompts
the person creating the Blueprint for their own DSN instead of shipping one.
The desktop, desktop-timer, server, server-api and agent apps logged the full
DSN at startup; they now only say that Sentry is enabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:33:52 +02:00
Ruslan Konviser fb43c7a60f Merge pull request #10317 from ever-co/ci/lint-archive-off-ramdisk
ci: unpack the lint cache off the RAM disk; PRs into develop start no workflow
v111.44.62
2026-09-27 15:43:02 +02:00
Ruslan KonviserandClaude Opus 5.5 55a44b8bea fix(sentry): ship no Sentry DSN in the self-hosting templates
.env.compose (loaded by docker-compose.yml by default), .env.demo.compose,
.env.docker, render.yaml, .render/render.demo.yaml and both fly.toml files
carried the Ever Gauzy project's DSN, so every self-hosted install reported its
errors and log lines into Ever's Sentry project and spent its quota. They are
now empty, with a note to set your own DSN. Existing installs keep the value
they were created with; only rotating that key stops them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:30:06 +02:00
Ruslan KonviserandClaude Opus 5.5 f7659fd4fb fix(sentry): route fatal logs like errors
SENTRY_LOG_LEVELS accepted 'fatal', but SentryService had no fatal override, so
Nest's ConsoleLogger.fatal printed the message and Sentry never saw it (also
before this branch). A fatal log now becomes an event whenever fatal or error is
captured, and is a breadcrumb otherwise. The level list is a Set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:29:08 +02:00
Ruslan KonviserandClaude Opus 5.5 40826df61b ci: unpack the lint cache off the RAM disk; PRs into develop start no workflow
Static Checks / lint (x64-4 lane): every cache hit since the job moved to
this lane ran out of space. The 2.47 GB archive plus the tree it unpacks to
does not fit the 16Gi RAM-backed workspace, so each hit fell back to a
1.5-4 h cold install (16 of 16 runs cold since #10303). The Restore step
now moves the archive onto the disk-backed package-cache volume (the
parent of YARN_CACHE_FOLDER) before extracting, so only the tree lives in
RAM. Where YARN_CACHE_FOLDER is unset, or the move fails, it extracts in
place exactly as before. Two report-only df lines (after the restore and
at the top of Summarize) record workspace headroom and can never fail a
step.

Triggers: apply the owner decision of 2026-09-21 (already on draft #10254,
same text) directly to develop. A pull request INTO develop no longer
starts static-checks, typos (cspell), snyk-analysis (trigger removed,
restore lines kept in a comment), or build, secrets-analysis and the
external-uptime-monitor self-test (branches-ignore: develop, so PRs into
stage/master still run them). Every push trigger is unchanged, so all of
them still run when code lands on develop. develop has no required status
checks, so no PR is blocked by the missing runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:11:58 +02:00
Sairaj V 5536f7b711 fix(ui): show invoice View and Payments as active actions
Those buttons used the muted secondary style, so they looked disabled next to Edit and Download. Use the primary action style while they stay clickable.

Fixes #8522
2026-09-27 18:17:09 +05:30
Ruslan Konviser eac7136562 fix unknown employee name in creation toast (#10306) v111.44.61 2026-09-27 09:13:18 +02:00
joel kalema 0fe8348260 Merge pull request #10313 from joel-kalema/fix/screenshots-gallery-viewer-clean
Fix/screenshots gallery viewer clean
v111.44.60
2026-09-27 09:09:49 +02:00
Ruslan Konviser 47b0a55d3f Merge pull request #10311 from ever-co/fix/plugin-jest-esm-transform
test(plugins): make the videos, job-proposal and wakatime specs load and run
v111.44.59
2026-09-27 00:07:36 +02:00
joel kalema e9e6bfd9fa Merge pull request #10308 from joel-kalema/feat/contacts-pages-polish
Feat/contacts pages polish
v111.44.58
2026-09-26 20:17:45 +02:00
Ruslan KonviserandClaude Opus 5.5 c5513fc474 docs(core): say allowJs only affects repo-local .js in the idempotency README
Review follow-up (CodeRabbit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:00:54 +02:00
Ruslan KonviserandClaude Opus 5.5 69a293175a fix(sentry): only errors become Sentry events by default; stop logging health probes
The whole ever-co Sentry organisation (5,000 errors a month on the current
plan) has accepted no error after the first hours of each monthly reset:
2026-07-09, 08-09 and 09-09 are the only days with accepted errors in 90 days.
About 97% of what was accepted were info-level log lines, not errors.

- SentryService (the API's Nest logger) turned every log/warn/debug/verbose
  call into its own Sentry event and ignored the `logLevels: ['error']` the API
  passes. It now honours `logLevels`: listed levels become events, the rest
  become breadcrumbs on the next event. An unset or empty list keeps the old
  capture-everything behaviour. The API reads the list from SENTRY_LOG_LEVELS
  (default `error`), so capturing warnings or logs again is a config change.
- RequestContextMiddleware logged the start and end of every request,
  including the Kubernetes readiness probe on /api/health every 10 s on every
  pod: 2 events per probe, ~2,900 events an hour from the four Ever Teams API
  pods alone. /api/health and /api/health/* are no longer logged. This is
  decided by path only, since a client-set User-Agent must not be able to hide
  other requests.
- apps/api/src/sentry.ts printed the DSN at startup and ran the SDK in debug
  mode in production (`environment.production` is false in the published
  image), writing several SDK lines per request. Debug is now opt-in with
  SENTRY_DEBUG=true, and the DSN is no longer printed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:00:44 +02:00
Ruslan KonviserandClaude Opus 5.5 fed7700006 docs(jest): stop saying allowJs is what makes the ESM transform list work
Review follow-up (Greptile). core's and integration-zapier's
tsconfig.spec.json comments, and the idempotency README, still said allowJs
was required for transformIgnorePatterns to take effect. With the pinned
ts-jest (>= 29.3.2) that is no longer true for files under node_modules,
which is all the list covers. Reword the three comments; the allowJs
settings themselves are unchanged (identical parsed JSON).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:59:12 +02:00
Ruslan KonviserandClaude Opus 5.5 4eec30ca27 test(plugins): make the videos, job-proposal and wakatime specs load and run
Six service/controller specs in three plugins failed to load, so they ran
zero tests. Two defects were stacked, and the first hid the second.

1. Their testing modules load @gauzy/core, which imports uuid. The installed
   uuid (14.0.0) is ESM-only. The allow-list of ESM packages Jest must
   transform lived in packages/core/jest.config.ts, with a copy in
   integration-zapier, and not in the shared preset. Move it into
   jest.preset.js so inheriting projects get it, and let core inherit it
   (jest --showConfig resolves to the byte-identical pattern). zapier keeps
   its own copy, which replaces the preset's, and now points at the preset.
   No allowJs is needed: ts-jest >= 29.3.2 compiles node_modules .js to
   CommonJS regardless. All six specs pass with allowJs unset.

2. The specs are Nest CLI "should be defined" scaffolding whose testing
   modules never resolved the dependency graph of the class under test.
   Add stub providers for exactly what each class injects, and override
   the @UseGuards guards in the controller specs. Nest builds those in the
   module that owns the controller, but they are not constructor
   dependencies. The spec changes are additive only: no it/expect changed
   and nothing declared was removed.

Verified locally, before vs after on 1b2278d329:
- the three plugins go from 0 tests run to green (videos 3/3, 8 tests;
  job-proposal 2/2; wakatime 2/2)
- the other 31 plugins with specs are unchanged, suite for suite
- the 11 non-plugin projects that inherit the preset and have specs are
  unchanged
- core passes 179/179 suites, 2174 tests
- a mutation check (drop one repository stub) turns the spec red

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:53:02 +02:00
Ruslan Konviser 1b2278d329 Merge pull request #10309 from ever-co/fix/release-batch-2
fix: role_permission unique index, prod snaps to stable, desktop updater quirks
v111.44.56
2026-09-26 01:16:58 +02:00
Ruslan KonviserandClaude Opus 5.5 0da9a5d4fb fix(desktop): fix update prompt, auto-update delay and prerelease channel
The "new version available, download it?" dialog was registered with
autoUpdater.once(), so it could appear only once per app run. Since every
check now looks up the newest release again (#10305), a release published
later in the same run got no dialog. The once() listener was also used up
when the first version was found while automatic updates were off, so no
dialog appeared in that run even after they were turned back on. The
dialog now appears once for each new version. A version the user has
already answered in this run is not offered again, including the repeat
event that follows choosing Upgrade.

Only one update dialog is shown at a time. The dialog does not open while
it or the "ready to install" prompt is still showing; the next check
offers that version again. A "ready to install" prompt for a download
that finishes while the dialog is open waits until the dialog is
answered. An error showing either dialog is now logged instead of being
left as an unhandled rejection. The OS notification and the settings
page events are unchanged.

The settings page sends automatic_update_setting as { isEnabled, delay },
but the main process read automaticUpdateDelay, and AutomaticUpdate's
delay getter threw away any delay passed in and used the stored setting.
It worked only because the settings page happens to save the setting
first. The handler now accepts both names, handled on the receiving side
so existing settings pages keep working. The loop uses the delay it was
sent, falling back to the stored delay and then 1 hour. Delays that
setInterval cannot hold are ignored, since they would make it run every
millisecond.

Turning on the prerelease channel filtered the GitHub releases down to
prereleases only, so those users were never offered a newer stable
release. On the real release list they were held at v111.44.15, or even
v102.0.1, while v111.44.48 was out. The prerelease channel now means the
newest release of either kind, still preferring the newest one that
already has this platform's update file. Stable-only users are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 01:11:01 +02:00
Ruslan KonviserandClaude Opus 5.5 cec254cd35 ci(desktop): release prod snaps to the Snap Store stable channel
Every Gauzy app snap (desktop, desktop-timer, server, api-server, agent,
mcp-server; amd64 and arm64) went to the Snap Store 'edge' channel only,
from both the stage lane (stage-apps) and the prod lane (apps). The
electron-builder snap target publishes with its own snapStore config.
When the build config has no snapStore entry, that config has no
channels, and the Snap Store publisher then defaults to 'edge'.

Prod builds now release to 'stable' and stage builds to 'edge'. Each
Linux build step appends
-c.snap.publish.provider=snapStore -c.snap.publish.channels=<channel>
to its yarn command. yarn adds extra arguments to the end of the script,
which is the electron-builder call. The override is in the workflows
because the root build scripts are shared by both lanes. Only
snap.publish is overridden: a -c.publish override would be merged into
the GitHub publish entry. GitHub releases, update channels and every
other target are unchanged. Stage names 'edge' explicitly so each
prod/stage pair still differs only in the channel.

The generated snaps already use grade stable and strict confinement,
and they need no store-approved plugs, so the store accepts them on
stable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 01:10:55 +02:00
Ruslan KonviserandClaude Opus 5.5 f32a4488bd fix(core): make role permissions unique per tenant, role and permission
Nothing stopped a role from holding the same permission twice. The
*RolePermissionsReload* migrations read which permissions a role lacks
and then insert them, so two API processes running them against one
database at the same time both inserted the same rows. Any install that
ran two instances through those migrations can hold millions of such
duplicate role_permission rows.

Add migration AddRolePermissionUniqueIndex1790000017000, which creates
the unique index IDX_role_permission_unique on (tenantId, roleId,
permission) for Postgres, MySQL and SQLite:

- It builds the index first. With no duplicates that build is the only
  pass over the table and nothing is rewritten. If the build fails on a
  duplicate key, the duplicates are deleted in one statement and the
  index is built again. Each group keeps the row that actually grants
  the permission (enabled, active, not archived, not soft-deleted),
  otherwise a row the app can still see, then an enabled row, then the
  oldest one, then the smallest id. So no role loses a permission it
  has. Rows with a NULL tenantId are left alone.
- On Postgres it runs inside the migration's transaction under a
  SHARE ROW EXCLUSIVE lock with a 5 s lock_timeout. Reads keep working,
  writers wait for the build (about 5 s per 2M rows), and a second
  process starting at the same time waits, then finds the index done.
  The build does not use CONCURRENTLY: a failed CONCURRENTLY build
  leaves an INVALID index, while this one just rolls back and runs
  again on the next start. An INVALID index already using this name is
  refused with instructions instead of being accepted as done.
- On MySQL the index is looked up by name before and after the build,
  so a retry after a crash or a lost race with another process does
  not fail.
- down() drops only the index.

Declare the same index on the RolePermission entity so synchronize and
migration:generate produce the same schema. Make the batched reload
insert skip rows another process inserted first (ON CONFLICT DO NOTHING
on Postgres and SQLite, a no-op ON DUPLICATE KEY UPDATE on MySQL).
Without that, the unique violation would be caught and logged, and
every tenant after the failing one would miss its new permissions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 01:10:49 +02:00
joel kalema f1655152d5 Merge pull request #10304 from joel-kalema/fix/sidebar-active-link-on-refresh
Fix/sidebar active link on refresh
v111.44.55
2026-09-25 09:17:03 +02:00
aditya-mitra bc67c035da fix unknown employee name in creation toast 2026-09-25 08:56:57 +05:30