Skip to content

Dev to release - #506

Merged
KelvinTegelaar merged 502 commits into
mainfrom
dev
Sep 7, 2026
Merged

KelvinTegelaar merged 502 commits into
mainfrom
dev

Conversation

@KelvinTegelaar

Copy link
Copy Markdown
Contributor

No description provided.

rvdwegen and others added 30 commits September 2, 2026 11:56
- Introduced new cache type for OneDrive long paths, allowing for per-user counts of paths exceeding Windows sync limits.
- Implemented Push-DBCacheOneDriveLongPaths function to handle path recounting for personal sites.
- Added Get-CIPPAlertOneDriveLongPaths for alerting on accounts with over-long paths.
- Created tests for the new functionality and alerts to ensure reliability.
- Updated frontend alert configurations to include OneDriveLongPaths alerting.
- Changed inputProps to slotProps in various components to align with MUI v9 standards.
- Updated QueryField, CippAutocomplete, CippFormComponent, CippMobileTenantPicker, CippMobileTableControls, and MobileNav for consistency.
- Added mobile-web-app-capable meta tag in _document.jsx for improved mobile support.
…mobile navigation

- Implemented a flattening function for inputProps and InputProps in CippAutocomplete to comply with MUI v9 standards.
- Updated slotProps structure for MemoTextField and CippAutoComplete components to ensure proper integration with MUI v9.
- Refactored mobile navigation to streamline the search input component, improving accessibility with aria-label.
fix(auth): empty IPRange on api client set Any
chore(frontend): regenerate msw worker script for msw 2.15.0
chore(frontend): declare missing dev deps, drop test stub
test: update suites to run on shared context
…selection

Fix: Fix calendar permission folder selection
Covers the Set Sign In State and Delete Guest table actions added in
7dba7fd, both gated behind user write access.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers the Hide/Show MyApps portal table actions and the "Hidden from
MyApps portal" filter added to Enterprise Applications in 69c3eb2.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix an infinite render loop in CippRoleAddEdit caused by unstable object/array references feeding effects, and add a regression test. Improve mobile responsiveness across several pages (mail flow statistics, baseline alignment, community repos, report builder) by wrapping toolbars and action rows on small viewports instead of clipping. Replace the deprecated Cancel icon with Close in get-cipp-formatting.jsx.
Audited every list/table page against the house style guide's Filters
section rule (documenting code-defined filterName presets). Adds the
missing ## Filters table to the 11 pages that define presets but had
no section for them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Tenant Mapping table gained a per-tenant Sync Now row action
(55dbb4d), so document it alongside Delete Mapping. Also corrects a
pre-existing inaccuracy: the page claimed the Integration Sync page
lets a single tenant be queued, but that page explicitly excludes
NinjaOne since it syncs through its own orchestrator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Identity/Devices/Custom rows on the Assessment card now link to the
matching dashboard tab, keeping the selected test suite (b38b1c9).
Matches the existing Tenant metrics and All users auth methods cards,
which already document their own click-through behaviour.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Craft serialises string bodies as JSON unless the response declares a
non-JSON content type, so the subscription validation reply went out
quoted and Graph rejected every new subscription with 'did not return
the expected validation token'.
A delta query that ended without a deltaLink persisted an empty DeltaUrl,
and every later trigger evaluation failed binding it. Treat a blank link
like a missing row and never persist one without a link.
Get-TeamsProtectionPolicy returns 403 on tenants without Defender for
Office 365. Check the licence up front and report a 403 as a licensing
gap instead of logging an error on every run.
…e wrote them

Report rows carry the id of the template whose merged settings ran the
standard, so filtering on that id hid every standard an AllTenants
template shares with a tenant-specific one and the page reported the
data as never collected. Match rows on the standard key and read the
selected template's definition for its own scope.
…emplates

The batch wrote the licence row without LicenseAvailable and the
missing-template row without current/expected values, both of which the
standards page renders as 'data has not yet been collected'. Also accept
the GUID column when loading a template, like the standard itself does.
The standard, scheduled task and baseline log drawers queried today's
partition only, so a run that finished overnight showed an empty log for
most of the next day. ListLogs accepts Days=N for filtered queries.
…wKey or GUID

A standards or drift template that still points at a deleted Intune, CA
or reusable-settings template sat at NOT FOUND forever with only a bare
id to go on. Alignment now reports which template no longer exists, the
drift page falls back to the label the template carries, and the Intune
standard and compare endpoint accept either the RowKey or the GUID
column. The compare dialog also runs the standard's assignment check so
it cannot report a match while drift reports the assignments differ, and
Get-CIPPDrift no longer writes or prunes decisions when the existing
states could not be read.
…ache

With All Tenants selected the create endpoint skipped the Exchange
cmdlets but still logged success. The Safe Links pages now opt out of
All Tenants, the endpoint rejects it, the cache collection skips tenants
without Defender for Office 365 instead of logging an error twice a day,
and a template made from a policy gets the policy name.
…p identity

Managed-device app configuration policies target apps by mobileApp id,
which only exists in the tenant the template was captured from, so
deploying elsewhere failed. Templates now record each targeted app's
bundle/package id and name, deployment resolves them in the target
tenant (naming any app that is missing), and the policy read used by
reporting supports this policy type.
…liases

Templates created from a tenant were matched on the exact tenant string
used by the sync task, so a second task for the same tenant under its
onmicrosoft name created a full duplicate set on every run. Match on
every name the tenant is known by, write the default domain as Source
and show the source on the template lists.
…eset

The user query refetches after a save and the reset wiped the manual
entry custom data fields; the refetch can also read Graph before the
write replicated and be cached. Keep the submitted values through the
reset and re-seed the fields whenever a reset changes them.
Reading the selected standards template inside the entrypoint added a
second table read, which made the OpenAPI generator drop the storage
derived response schema for ListStandardsCompare. The lookup lives in
Get-CIPPStandardsTemplateScope now, so the entrypoint reads its report
table only and the generated spec keeps describing the rows.
Picks up the ListLogs Days parameter, the optional Name on Safe Links
policy templates, the 400 response on Safe Links policy creation and the
updated compare and template list field descriptions.
The single-template path wrote 'could not be loaded from the template
store' while the batch path already names the template, its id and what
to do about it. Use the same wording in both so the standards page shows
which template is gone.
…ages

Next.js served src/pages/tenant/manage/driftManagementActions.jsx as a route. The module exports
action definitions rather than a page, so opening the URL threw "Objects are not valid as a React
child" in the dev overlay. Move it next to the other action helpers under components and repoint
its four importers.
Zacgoose and others added 23 commits September 7, 2026 17:26
Casting the runManually values of several templates to bool is always true, as
is the string 'false', so a wildcard run flipped to manual-only, matched no
scheduled template and reported success while doing nothing.
…ed group failures

The deploy drawer sends 'leave' for 'Leave the groups and users as is', which
matched no replacement case. A template that stores groups by display name then
reached Graph unchanged and failed with an opaque '1054: Invalid group value'.
Treat 'leave' like 'none', fail with an actionable message when named groups
are present, and preselect 'Replace by display name' in the drawer.
…ng silently

The application list request swallowed every failure, so a tenant missing
the permission to read app registrations looked identical to a tenant with
no expiring secrets. Log the normalized error against the tenant before
returning, matching the mailbox quota alert.

Also documents the reporting window (30 days before expiry through 7 days
after) in the alert description.
DisableSharedMailbox captured the offending mailboxes before the disable
loop and wrote that same list to the compare field afterwards, so a run
that successfully disabled every shared mailbox account still reported
all of them as non-compliant. On the drift page the deviation came
straight back after each remediation. The report and alert blocks now run
on what is left once the bulk PATCH has been applied.

The single try/catch around both the cached user read and the Exchange
mailbox list only ever said "Could not get the DisableSharedMailbox
state", which made a cold cache indistinguishable from an Exchange
failure. Split it in two with distinct messages, and return early with a
warning when the user cache is empty instead of reporting every shared
mailbox as a deviation.

The mailbox type test is now parenthesised for clarity - this is not a
behaviour change: -and and -or share one precedence level in PowerShell
and associate left to right, so the filter always meant "(shared or
scheduling) and still enabled". The note in the baselines hook claimed
the opposite and is corrected.
…y flavour

"Rerun standard to align with template", on both the denied and the
compliant cards, posted status 'Denied' to ExecUpdateDriftDeviation. That
endpoint only schedules a remediation for 'DeniedRemediate', so the item
re-marked the row and did nothing else - which is what people were
clicking when a denied deviation never went away. Both menus already
carry "Deny - Remediate to align with template", which does schedule the
run and is hidden for tenant-only policies that have nothing to rerun, so
the dead item is removed rather than rewired into a duplicate.

The denied section also forced every card to read "Denied Deviation":
createDeviationItems needs the status override for the item id, and it
was winning over the row's own status as well. It now keeps the id prefix
and shows the real choice, so Denied, Denied - Remediate and Denied -
Delete are told apart on the card - the getDeviationStatusText branches
for those two were unreachable until now.
…duled

ExecUpdateDriftDeviation wrote the new deviation status first and acted
on it afterwards, so a DeniedRemediate whose scheduled task could not be
created, or a DeniedDelete whose Graph DELETE threw, still left the row
filed under Denied with nothing on the page to say the action never ran.
The write now happens at the end of the per-deviation block; anything
that throws lands in the existing catch and leaves the deviation
untouched, so it stays actionable. Statuses that carry no action
(Accepted, CustomerSpecific, plain Denied) are unaffected - they reach
the same write with nothing in between.

The plain-standard branch of the setting lookup also stayed silent when
it could not resolve the standard from the drift template, while the four
template branches all log a warning. It now logs one too.
The removal read the tenant's number assignments from beta and then unassigned
them through a Graph $batch. The gateway rejected that batch with an IIS
"Bad Request - Request Too Long / HTTP Error 400. The size of the request
headers is too long." page, and the whole HTML document was handed back as the
offboarding result for the step.

It now reads the assignments from v1.0 and posts unassignNumber once per number,
the same call the Teams voice page makes, with the number type normalised
through Get-CippTeamsNumberType. Each number has its own try/catch, so one
number that cannot be unassigned is reported on its own line and the rest still
run.

New-GraphBulkRequest no longer passes a whole HTML error page on as the error
message: an HTML body is reduced to its first line plus the HTTP Error line, so
a gateway rejection reads as "Request Too Long - HTTP Error 400. ..." instead of
a document. The failing record is also captured before the JSON parse attempt,
which was shadowing $_ inside its own catch.
…ame is empty

Both the device removal and the account-only wipe named each device by its
FriendlyName, which Exchange leaves empty for most devices, so the result read
"Successfully removed 2 mobile devices for x: ; " and said nothing about which
devices were touched. They now fall back to the device model, then the OS, then
the device id - the same fallback the ActiveSync device list uses - and the
failure path names the device it could not reach.
Get-CIPPHttpFunctions returned its error as a string and Get-CippHttpPermissions
persisted whatever it got, recomputing only when the cached row was empty. A
universe written while a worker was out of memory held a handful of names (or an
error message), every custom role then expanded to no permissions, and the row was
pinned for the life of that version while the built-in roles kept working. Fail the
enumeration instead of returning text, validate the universe on read and before
write, and serve a short result without caching it so the next request retries.
… time

Save as Template on the Applications list stored any row as a template, mapping
an uploaded win32LobApp to appType chocolateyApp with the raw Graph object in
config.IntuneBody. Nothing can deploy that: the installer is .intunewin content
living in the source tenant's Intune, and CIPP only ever uploads packages it
ships itself. Deploying such a template failed in Graph, or - once the template
drawer had backfilled a package name from the detection rule - quietly installed
a completely different Chocolatey package. winGetApp had the same problem in a
different place: the Store deploy path rebuilds from PackageName, which a Graph
body does not carry.

Only Office and Edge survive a round trip, because Get-CIPPOfficeAppBody and
Get-CIPPEdgeAppBody replay a stored body after stripping the read-only Graph
properties. mapOdataToAppType now returns null for everything else, the row
action is conditioned on it, and bulk selections template only the eligible
subset. AddAppTemplate and New-CIPPIntuneAppDeployment both reject a config
whose IntuneBody carries an id, so templates saved before this change fail with
an explanation instead of deploying the wrong software.

ExecDeployAppTemplate logged "Deployed app ..." at Info whatever the per-type
handler returned; it now checks the handler's status code and surfaces a
rejection as an error result.
Ticking "Send results to: PSA" on the offboarding wizard, or pointing an
alert at a PSA, produced no ticket and no explanation whenever the global
"Send to integration" notification setting was off. The integration's own
test button calls the PSA directly and bypasses that gate, so a passing
test proved nothing about real deliveries.

- Send-CIPPAlert now writes a Logbook warning naming the setting when the
  PSA branch is skipped, instead of only a Write-Information.
- The PSA extension reports failure in its return value rather than by
  throwing, so a failed ticket was logged as "Sent PSA alert" and returned
  as a success. Inspect the result: log it at Error and return an "Error:"
  string, otherwise keep the ticket text (which carries the ticket id) on
  the success string so it lands on the task.
- Push-CIPPOffboardingComplete counts a "Skipped:" result as failed, so the
  "Notify via PSA" progress row stops showing green for a ticket that was
  never raised.
- New-CippExtAlert logs a warning when a tenant has no HaloPSA client
  mapping and the ticket falls back to client id 1. The fallback itself is
  unchanged; it just no longer happens silently behind Write-Host.
- Send-CIPPCustomTestAlert gates its blanket PSA call on the same setting,
  matching Push-SchedulerCIPPNotifications, so the new warning only reaches
  operators who actually asked for a PSA ticket.
- The offboarding wizard hints, next to the PSA switch, that the setting
  has to be on - shown unless the notification config can be read and
  confirms it is enabled.

Adds Pester coverage for the skipped, failed and success paths of the PSA
branch.
… trimming is on

With automatic version trimming enabled the SPOVersionControl standard wrote null
placeholders for MajorVersionLimit and ExpireVersionsAfterDays into the expected
value while the current value carried the tenant-managed numbers. The applied
standards report and drift detection compare the two objects as a whole, so every
auto-trim tenant showed as non-compliant even though the standard itself considered
the state correct. In auto-trim mode both sides now carry only the trim flag, and the
alert and remediation messages no longer describe a limit that is not enforced.

Fixes #503
MCP runs under the signed-in user's role, so a role IP allow-list that omits the AI
provider's egress range silently 403s every MCP call. Warn on the API client page (page
alert + live dialog warning when MCP is toggled on). ListCustomRole now attaches IPRange
to custom roles too, so the read-only list carries the data the warning needs.
…ion cleanup functionality

- Updated CippChartCard to conditionally hide axis labels for long bar labels, improving chart readability.
- Refactored CippSharePointBrowserStorage and CippStorageCleanupDrawer to rename cleanup actions for clarity and added default values for version cleanup settings.
- Introduced a new VersionCleanupSlider component in CippSharePointVersionCleanupFields for better user interaction with version limits.
- Updated translations for version estimates and adjusted formatting for better data presentation in the UI.
- Added Tooltip functionality to CippCellText for displaying full text on hover when content overflows.
- Refactored mouse event handlers to manage tooltip visibility based on text width.
- Updated styles to ensure proper ellipsis handling and text display within the CippDataTable.
- Removed unused CippCellText references from get-cipp-formatting utility for cleaner code.
Comment thread build/tools/azurite-prestart.js Fixed
Comment thread frontend/src/components/CippTable/CIPPTableToptoolbar.jsx Fixed
Comment thread frontend/src/components/CippTable/CIPPTableToptoolbar.jsx Fixed
Comment thread frontend/src/components/CippTable/CippDataTable.jsx Fixed
Comment thread frontend/src/layouts/index.jsx Fixed
Comment thread frontend/src/utils/get-cipp-formatting.jsx Fixed
Comment thread frontend/src/utils/markdown-table.js Fixed
Comment thread frontend/src/utils/permissions.jsx Fixed
- Use matchPattern for wildcard permission/blacklist matching so every regex
  metacharacter is escaped (also fixes the template blacklist escaping order
  bug that stopped *Id / *DateTime patterns from ever matching)
- Escape backslashes in markdown table cells on both frontend and backend
- Build filterTypeMap and column visibility without computed-key property
  writes; skip prototype keys in the API column merge
- Only render info.logoUrl as an <img> for http(s) URLs
- Encode substituted row values for internal dialog links
- Strip line breaks from the scheduler not-found warning
- Check the onmicrosoft.com domain with endsWith instead of includes
- Update the MiscFields story: truncation is CSS ellipsis + tooltip now
Two workflows both named CodeQL ran on every PR, one with the frontend as
source root, so every alert appeared twice. Keep CodeQL_Analyser.yml
(security-extended), drop codeql.yml, and add a config that scans only the
frontend and skips the generated msw worker and test fixtures.
- Prototype-key guard as literal comparisons instead of a Set lookup
- Encode dialog link substitutions in a dedicated internal-link branch so the
  router.push path never sees an unencoded row value
@KelvinTegelaar
KelvinTegelaar merged commit 0e60de0 into main Sep 7, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants