+ Converts {subject} from manual {formatRu(target?.current_ru)} to native Cosmos autoscale. The + autoscale maximum keeps the current RU/s, rounded up to Cosmos autoscale increments, within + the saved guardrails. +
++ SimpleChat does not convert throughput back to manual; that is done in the Azure portal. +
+ > + ) : blocked ? ( ++ {estimate?.error} +
+ ) : ( + <> ++ Scales {subject} {action.direction} from{' '} + {formatRu(target?.current_ru)} to about{' '} + {formatRu(estimate?.target)}. +
++ {action.direction === 'up' + ? `Uses the saved step of ${formatRu(policy.scale_up_step_ru)}${policy.ignore_max_limit ? ', ignoring the maximum guardrail' : ` and stops at the ${formatRu(policy.max_ru)} maximum`}. SimpleChat never scales above 10,000 RU/s.` + : `Uses the saved step of ${formatRu(policy.scale_down_step_ru)}${policy.ignore_min_limit ? ', ignoring the minimum guardrail' : ` and stops at the ${formatRu(policy.min_ru)} minimum`}.`}{' '} + The change is made in Azure immediately and recorded in the admin activity log. +
+ > + )} + {unsavedThroughputEdits ? ( ++ You have unsaved throughput changes. This uses the saved policy; save first if the change depends + on them. +
+ ) : null} ++ Showing {visible.length} of {containers.length} containers · {windowMinutes} min window +
++ Azure Monitor sent no utilization percentage for this window, so it is estimated from request + units against current RU/s. +
+ ) : null} + {container.error ?{actionReason}
: null} ++ This container shares the database's throughput, so it has no policy of its own. Database + automation covers it. +
+ ) : editable ? ( +Automation policy
++ {error} +
+ ) : null} +| Category | +Candidates | +Deleted | +Failed | +
|---|---|---|---|
| {humanizeStatus(category.category || 'unknown')} | +{formatCount(category.candidate_count ?? 0)} | +{formatCount(category.deleted_count ?? 0)} | +{formatCount(category.failed_count ?? 0)} | +
+ Adds the missing expected composite indexes to the hot Cosmos containers. Existing included + and excluded paths, default indexes, TTL settings and full-text policies are kept. +
++ Composite indexes speed up supported lookups and ordered queries, but Cosmos maintains them + on every later write and may run an index transformation after the policy changes. +
++ Apply them only if the extra write-index overhead is worth the faster queries shown in the + maintenance status. +
++ Deletes one bounded batch of allowlisted stale cache artifacts from the settings container, + such as retired conversation cache version documents and obsolete volatile cache payloads. +
++ App settings, active cache-version documents, DAI state, maintenance state, source documents + and user data are never deleted. Run a dry run first to see the candidate count. +
+Database capacity
++ {capacityReason} + {containerScoped ? ( + <> + {' '} + + > + ) : null} +
+ ) : ( ++ One step at a time, within the saved guardrails. Each change asks for confirmation first. +
+ )} + {unsavedEdits ? ( ++ You have unsaved throughput changes. Validate access uses them; scaling and conversion + use the saved policy until you save. +
+ ) : null} ++ Validate access runs the same read checks automation depends on, using the values on + screen: resource identity, Azure Resource Manager throughput reads, container discovery, + and Azure Monitor metrics. +
+Required Azure access
+SimpleChat Cosmos Throughput Operator{' '}
+ role to that identity at the resource group that holds the Cosmos DB account, or on
+ the account itself.
+ throughputSettings; run{' '}
+ migrateToAutoscale; read throughput operation
+ results; and read Microsoft.Insights/metrics.
+ Capacity scope
+Metrics
++ The next batch starts again from the first source scope, then one batch runs at the saved + size. The work is idempotent, but documents that already have projection rows may be + processed again. +
++ Source documents and projection rows are not deleted. Only backfill progress is reset. +
+{description}
+ ) : null} + {children} ++ + {children} +
+ ); +} + +/** A readout with nothing to show yet, and what would change that. */ +export function OpsEmptyState({ title, children }: { title: string; children?: ReactNode }) { + return ( +{title}
+ {children ? ( +{label}
+ {help ?{help}
: null} +Loading the preview…
+ ) : preview ? ( + <> +{preview.key || selectedKey}
++ {preview.resolution.label || humanizeStatus(preview.resolution.kind)} +
+{describeResolutionEntity(preview.resolution)}
+ {preview.resolution.scope_key || preview.resolution.cache_hash || preview.resolution.scope_hash ? ( ++ {preview.resolution.scope_key || + preview.resolution.cache_hash || + preview.resolution.scope_hash} +
+ ) : null} + {preview.resolution.note ? ( +{preview.resolution.note}
+ ) : null} +Sanitized preview
+
+ {preview.preview || 'No preview available.'}
+
+ + + Used by + {dependents.map((dependent, index) => ( + + {index > 0 ? : null} + {onNavigate ? ( + + ) : ( + {dependent.label} + )} + + ))} +
+ ); +} + /** * Lay out a run of fields, flowing consecutive independent switches into a grid. * @@ -348,6 +390,7 @@ export function SettingsSection({ guide, runtimeFlags, onNavigate, + dependents, children, }: SettingsSectionProps) { const capability = useMemo(() => findCapabilityField(fields), [fields]); @@ -358,8 +401,8 @@ export function SettingsSection({ ); const derivedStatus = useMemo( - () => computeSectionStatus(fields, settings, draft, statusRule, fieldsByKey), - [statusRule, fields, settings, draft, fieldsByKey], + () => computeSectionStatus(fields, settings, draft, statusRule, fieldsByKey, runtimeFlags), + [statusRule, fields, settings, draft, fieldsByKey, runtimeFlags], ); const status = statusProp ?? derivedStatus; @@ -375,8 +418,8 @@ export function SettingsSection({ // A section states each distinct prerequisite once, at the top, rather than repeating // it on every field that carries it. const requirements = useMemo( - () => collectRequirements(fields, settings, draft, fieldsByKey), - [fields, settings, draft, fieldsByKey], + () => collectRequirements(fields, settings, draft, fieldsByKey, runtimeFlags), + [fields, settings, draft, fieldsByKey, runtimeFlags], ); const groups = useMemo( @@ -566,6 +609,13 @@ export function SettingsSection({