Add workspace DDL lock env var and maintenance mode UI (#19130)
## Summary - Add `WORKSPACE_SCHEMA_DDL_LOCKED` env-only boolean config variable that blocks all workspace schema DDL changes when set to `true`. This is intended for hot upgrades where logical replication cannot handle DDL changes. Enforced at two chokepoints: - `WorkspaceMigrationRunnerService.run` — blocks all metadata-driven DDL (object/field/index CRUD, app sync/uninstall, standard app sync, upgrade commands) - `WorkspaceDataSourceService.createWorkspaceDBSchema` / `deleteWorkspaceDBSchema` — blocks workspace creation (sign-up) and hard deletion. Uses a dedicated `WorkspaceDataSourceException` (not ForbiddenException) - Add maintenance mode feature with Admin Panel UI and user-facing banner: - **Backend**: `MaintenanceModeService` stores maintenance window (startAt, endAt, optional link) in `core.keyValuePair` as `CONFIG_VARIABLE`. Validates endAt > startAt. Uses `GraphQLISODateTime` scalar for date fields. Exposed via `clientConfig` REST endpoint and admin GraphQL mutations (`setMaintenanceMode`, `clearMaintenanceMode`) - **Admin Panel**: New "Maintenance Mode" section in Health tab with UTC datetime pickers and activate/deactivate controls - **Banner**: `InformationBannerMaintenance` displayed at the top of `DefaultLayout` for all users, using Temporal API for timezone-aware formatting with an optional "Learn more" link These two features are **independent** — the DDL lock is controlled via env var for operational use, while maintenance mode is a UI notification mechanism controlled from the admin panel.
This commit is contained in:
+8
-3
@@ -2,9 +2,11 @@ import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdat
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { getActiveFieldMetadataItems } from '@/object-metadata/utils/getActiveFieldMetadataItems';
|
||||
import { objectMetadataItemSchema } from '@/object-metadata/validation-schemas/objectMetadataItemSchema';
|
||||
import { isDDLLockedState } from '@/client-config/states/isDDLLockedState';
|
||||
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useMemo } from 'react';
|
||||
@@ -43,9 +45,12 @@ const StyledContainer = styled.div`
|
||||
export const SettingsDataModelObjectIdentifiersForm = ({
|
||||
objectMetadataItem,
|
||||
}: SettingsDataModelObjectIdentifiersFormProps) => {
|
||||
const readonly = isObjectMetadataReadOnly({
|
||||
objectMetadataItem,
|
||||
});
|
||||
const isDDLLocked = useAtomStateValue(isDDLLockedState);
|
||||
|
||||
const readonly =
|
||||
isObjectMetadataReadOnly({
|
||||
objectMetadataItem,
|
||||
}) || isDDLLocked;
|
||||
const formConfig = useForm<SettingsDataModelObjectIdentifiersFormValues>({
|
||||
mode: 'onTouched',
|
||||
resolver: zodResolver(settingsDataModelObjectIdentifiersFormSchema),
|
||||
|
||||
Reference in New Issue
Block a user