diff --git a/apps/sv/frontend/src/__tests__/governance/proposal-details-content.test.tsx b/apps/sv/frontend/src/__tests__/governance/proposal-details-content.test.tsx
index b79df961b7..7ab545460a 100644
--- a/apps/sv/frontend/src/__tests__/governance/proposal-details-content.test.tsx
+++ b/apps/sv/frontend/src/__tests__/governance/proposal-details-content.test.tsx
@@ -422,6 +422,91 @@ describe('Proposal Details Content', () => {
expect(jsonDiffsToggle).toHaveAttribute('aria-expanded', 'false');
expect(screen.queryByText('JSON')).not.toBeInTheDocument();
expect(screen.getByTestId('json-diffs-details')).not.toBeVisible();
+
+ expect(
+ screen.queryByTestId('proposal-details-disabled-fields-warning')
+ ).not.toBeInTheDocument();
+ });
+
+ test('should warn when disabled fields were altered in an amulet rules config proposal', () => {
+ const amuletRulesConfigDetails = {
+ actionName: 'Set Amulet Rules Config',
+ action: 'CRARC_SetConfig',
+ proposal: {
+ configChanges: [
+ {
+ fieldName: 'transferConfigCreateFee',
+ label: 'Transfer (Create Fee)',
+ currentValue: '0.03',
+ newValue: '0.04',
+ },
+ {
+ fieldName: 'decentralizedSynchronizerActiveSynchronizer',
+ label: 'The currently active synchronizer',
+ currentValue: 'global-domain::12',
+ newValue: 'global-domain::13',
+ isId: true,
+ disabled: true,
+ },
+ ],
+ },
+ } as ProposalDetails;
+
+ render(
+
+
+
+ );
+
+ const warning = screen.getByTestId('proposal-details-disabled-fields-warning');
+ expect(warning).toBeInTheDocument();
+ expect(warning.textContent).toMatch(/Disabled fields have been altered in this vote proposal/);
+
+ const changes = screen.getAllByTestId('config-change');
+ expect(changes[1]).toHaveAttribute('data-disabled', 'true');
+ expect(within(changes[1]).getByTestId('config-change-disabled-label')).toHaveTextContent(
+ 'Disabled field'
+ );
+ });
+
+ test('should warn when disabled fields were altered in a dso rules config proposal', () => {
+ const dsoRulesConfigDetails = {
+ actionName: 'Set DSO Rules Configuration',
+ action: 'SRARC_SetConfig',
+ proposal: {
+ configChanges: [
+ {
+ fieldName: 'decentralizedSynchronizerActiveSynchronizerId',
+ label: 'Decentralized synchronizer: Active synchronizer identifier',
+ currentValue: 'global-domain::12',
+ newValue: 'global-domain::13',
+ isId: true,
+ disabled: true,
+ },
+ ],
+ },
+ } as ProposalDetails;
+
+ render(
+
+
+
+ );
+
+ expect(screen.getByTestId('proposal-details-disabled-fields-warning')).toBeInTheDocument();
+ expect(screen.getByTestId('config-change-disabled-label')).toHaveTextContent('Disabled field');
});
test('should render dso rules config changes', () => {
diff --git a/apps/sv/frontend/src/components/form-components/ConfigField.tsx b/apps/sv/frontend/src/components/form-components/ConfigField.tsx
index 61a0216eaa..45b011c6b2 100644
--- a/apps/sv/frontend/src/components/form-components/ConfigField.tsx
+++ b/apps/sv/frontend/src/components/form-components/ConfigField.tsx
@@ -72,10 +72,12 @@ export const ConfigField: React.FC = props => {
sx={{
display: 'flex',
justifyContent: 'space-between',
- alignItems: 'center',
+ alignItems: 'flex-start',
+ gap: 2,
+ minWidth: 0,
}}
>
-
+
{configChange.label}
@@ -89,9 +91,10 @@ export const ConfigField: React.FC = props => {
-
+
= props => {
Current Configuration: {configChange.currentValue}
@@ -140,24 +149,46 @@ export const PendingConfigDisplay: React.FC = ({ pend
effectiveDate === 'Threshold' ? 'at Threshold' : dayjs(effectiveDate).fromNow();
return (
-
- Pending Configuration: {pendingValue}
- This{' '}
-
- pending configuration
- {' '}
- will go into effect {effectiveText}
-
+ Pending Configuration:{' '}
+
+ {pendingValue}
+
+
+
+ This{' '}
+
+ pending configuration
+ {' '}
+ will go into effect {effectiveText}
+
+
);
};
diff --git a/apps/sv/frontend/src/components/governance/ConfigValuesChanges.tsx b/apps/sv/frontend/src/components/governance/ConfigValuesChanges.tsx
index 530e0d4b1c..5151f5705a 100644
--- a/apps/sv/frontend/src/components/governance/ConfigValuesChanges.tsx
+++ b/apps/sv/frontend/src/components/governance/ConfigValuesChanges.tsx
@@ -31,17 +31,36 @@ export const ConfigValuesChanges: React.FC = props =>
{changes.map((change, index) => (
-
- {change.label}
-
+
+
+ {change.label}
+
+ {change.disabled && (
+
+ Disabled field
+
+ )}
+
{change.currentValue && (
<>
diff --git a/apps/sv/frontend/src/components/governance/ProposalDetailsContent.tsx b/apps/sv/frontend/src/components/governance/ProposalDetailsContent.tsx
index 06ca0387df..3e1cf13269 100644
--- a/apps/sv/frontend/src/components/governance/ProposalDetailsContent.tsx
+++ b/apps/sv/frontend/src/components/governance/ProposalDetailsContent.tsx
@@ -8,7 +8,7 @@ import {
} from '@daml.js/splice-dso-governance/lib/Splice/DsoRules';
import { ContractId } from '@daml/types';
import { ChevronLeft, Edit } from '@mui/icons-material';
-import { Box, Button, Divider, Stack, Tab, Tabs, Typography } from '@mui/material';
+import { Alert, Box, Button, Divider, Stack, Tab, Tabs, Typography } from '@mui/material';
import React, { PropsWithChildren, useEffect, useMemo, useRef, useState } from 'react';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
@@ -20,6 +20,7 @@ import {
} from '@canton-network/splice-common-frontend';
import { Link as RouterLink } from 'react-router';
import {
+ ConfigChange,
ProposalDetails,
ProposalVote,
ProposalVotingInformation,
@@ -35,6 +36,11 @@ import { CopyableIdentifier, CopyableUrl, MemberIdentifier, VoteStats } from '..
import { useQuery } from '@tanstack/react-query';
import { useSvAdminClient } from '../../contexts/SvAdminServiceContext';
+/** True when a proposal changed fields that are locked/disabled in the create UI (e.g. emergency API). */
+export function hasAlteredDisabledFields(changes: ConfigChange[]): boolean {
+ return changes.some(c => c.disabled && c.currentValue !== c.newValue);
+}
+
dayjs.extend(relativeTime);
export interface ProposalDetailsContentProps {
@@ -246,6 +252,15 @@ export const ProposalDetailsContent: React.FC = pro
{proposalDetails.action === 'CRARC_SetConfig' && (
<>
+ {hasAlteredDisabledFields(proposalDetails.proposal.configChanges) && (
+
+ Disabled fields have been altered in this vote proposal.
+
+ )}
}
@@ -267,6 +282,15 @@ export const ProposalDetailsContent: React.FC = pro
{proposalDetails.action === 'SRARC_SetConfig' && (
<>
+ {hasAlteredDisabledFields(proposalDetails.proposal.configChanges) && (
+
+ Disabled fields have been altered in this vote proposal.
+
+ )}
}