diff --git a/frontend/src/components/App/PluginSettings/PluginSettingsDetails.test.tsx b/frontend/src/components/App/PluginSettings/PluginSettingsDetails.test.tsx
new file mode 100644
index 00000000000..41e8023393e
--- /dev/null
+++ b/frontend/src/components/App/PluginSettings/PluginSettingsDetails.test.tsx
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2025 The Kubernetes Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ThemeProvider } from '@mui/material/styles';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import { PluginInfo, PluginSettingsDetailsProps } from '../../../plugin/pluginsSlice';
+import { TestContext } from '../../../test';
+import { theme } from '../../TestHelpers/theme';
+import { PluginSettingsDetailsPure } from './PluginSettingsDetails';
+
+function TestSettingsComponent(props: PluginSettingsDetailsProps) {
+ const { data, onDataChange } = props;
+
+ return (
+ <>
+ {data?.value || ''}
+
+ >
+ );
+}
+
+function makePlugin(displaySaveButton: boolean): PluginInfo {
+ return {
+ name: 'test-plugin',
+ description: 'Test plugin',
+ homepage: 'https://example.com',
+ settingsComponent: TestSettingsComponent,
+ displaySettingsComponentWithSaveButton: displaySaveButton,
+ };
+}
+
+describe('PluginSettingsDetailsPure', () => {
+ it('passes props and auto-saves changes when save button is disabled', async () => {
+ const onSave = vi.fn();
+
+ render(
+
+
+
+
+
+ );
+
+ expect(screen.getByTestId('current-value')).toHaveTextContent('initial');
+
+ fireEvent.click(screen.getByRole('button', { name: 'Update Value' }));
+
+ await waitFor(() => {
+ expect(onSave).toHaveBeenCalledWith({ value: 'updated' });
+ });
+ });
+
+ it('passes props but does not auto-save changes when save button is enabled', () => {
+ const onSave = vi.fn();
+
+ render(
+
+
+
+
+
+ );
+
+ expect(screen.getByTestId('current-value')).toHaveTextContent('initial');
+
+ fireEvent.click(screen.getByRole('button', { name: 'Update Value' }));
+
+ expect(onSave).not.toHaveBeenCalled();
+ });
+});
diff --git a/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx b/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx
index 1c04e26fe47..72a3c063151 100644
--- a/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx
+++ b/frontend/src/components/App/PluginSettings/PluginSettingsDetails.tsx
@@ -194,6 +194,10 @@ export function PluginSettingsDetailsPure(props: PluginSettingsDetailsPureProps)
function onDataChange(data: { [key: string]: any }) {
setData(data);
+
+ if (!plugin.displaySettingsComponentWithSaveButton && onSave) {
+ void onSave(data);
+ }
}
async function handleSave() {
@@ -223,11 +227,7 @@ export function PluginSettingsDetailsPure(props: PluginSettingsDetailsPureProps)
component = plugin.settingsComponent;
} else if (typeof plugin.settingsComponent === 'function') {
const Comp = plugin.settingsComponent;
- if (plugin.displaySettingsComponentWithSaveButton) {
- component = ;
- } else {
- component = ;
- }
+ component = ;
} else {
component = null;
}