fix(tests): fix test failures
- Fix Prettier formatting in 8 files - Fix useProvisionedRequestHandler.test.ts by mocking config.bootData - Ensures ContextSrv can be instantiated in tests
This commit is contained in:
@@ -65,8 +65,12 @@ export function BrowseActions({ folderDTO }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onDelete = async () => {
|
const onDelete = async () => {
|
||||||
const selectedDashboards = Object.keys(selectedItemsForActions.dashboard).filter((uid) => selectedItemsForActions.dashboard[uid]);
|
const selectedDashboards = Object.keys(selectedItemsForActions.dashboard).filter(
|
||||||
const selectedFolders = Object.keys(selectedItemsForActions.folder).filter((uid) => selectedItemsForActions.folder[uid]);
|
(uid) => selectedItemsForActions.dashboard[uid]
|
||||||
|
);
|
||||||
|
const selectedFolders = Object.keys(selectedItemsForActions.folder).filter(
|
||||||
|
(uid) => selectedItemsForActions.folder[uid]
|
||||||
|
);
|
||||||
await deleteDashboards({ dashboardUIDs: selectedDashboards });
|
await deleteDashboards({ dashboardUIDs: selectedDashboards });
|
||||||
await deleteFolders({ folderUIDs: selectedFolders });
|
await deleteFolders({ folderUIDs: selectedFolders });
|
||||||
trackAction('delete', selectedItemsForActions);
|
trackAction('delete', selectedItemsForActions);
|
||||||
@@ -74,8 +78,12 @@ export function BrowseActions({ folderDTO }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onMove = async (destinationUID: string) => {
|
const onMove = async (destinationUID: string) => {
|
||||||
const selectedDashboards = Object.keys(selectedItemsForActions.dashboard).filter((uid) => selectedItemsForActions.dashboard[uid]);
|
const selectedDashboards = Object.keys(selectedItemsForActions.dashboard).filter(
|
||||||
const selectedFolders = Object.keys(selectedItemsForActions.folder).filter((uid) => selectedItemsForActions.folder[uid]);
|
(uid) => selectedItemsForActions.dashboard[uid]
|
||||||
|
);
|
||||||
|
const selectedFolders = Object.keys(selectedItemsForActions.folder).filter(
|
||||||
|
(uid) => selectedItemsForActions.folder[uid]
|
||||||
|
);
|
||||||
|
|
||||||
await moveFolders({ folderUIDs: selectedFolders, destinationUID });
|
await moveFolders({ folderUIDs: selectedFolders, destinationUID });
|
||||||
await moveDashboards({ dashboardUIDs: selectedDashboards, destinationUID });
|
await moveDashboards({ dashboardUIDs: selectedDashboards, destinationUID });
|
||||||
|
|||||||
@@ -133,13 +133,13 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props)
|
|||||||
try {
|
try {
|
||||||
// Collect all dashboards under this folder and its children
|
// Collect all dashboards under this folder and its children
|
||||||
const dashboardUIDs = await collectAllDashboardsUnderFolder(folder.uid);
|
const dashboardUIDs = await collectAllDashboardsUnderFolder(folder.uid);
|
||||||
|
|
||||||
// Create selected items object with all dashboards
|
// Create selected items object with all dashboards
|
||||||
const selectedDashboards: Record<string, boolean> = {};
|
const selectedDashboards: Record<string, boolean> = {};
|
||||||
dashboardUIDs.forEach((uid) => {
|
dashboardUIDs.forEach((uid) => {
|
||||||
selectedDashboards[uid] = true;
|
selectedDashboards[uid] = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
setExportSelectedDashboards(selectedDashboards);
|
setExportSelectedDashboards(selectedDashboards);
|
||||||
setShowExportFolderDrawer(true);
|
setShowExportFolderDrawer(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -183,9 +183,7 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props)
|
|||||||
label={deleteLabel}
|
label={deleteLabel}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{provisioningEnabled && isUnmanagedFolder && (
|
{provisioningEnabled && isUnmanagedFolder && <MenuItem onClick={handleExportFolder} label={exportLabel} />}
|
||||||
<MenuItem onClick={handleExportFolder} label={exportLabel} />
|
|
||||||
)}
|
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -91,10 +91,7 @@ export const refetchChildren = createAsyncThunk(
|
|||||||
|
|
||||||
export const selectFolderWithAllDashboards = createAsyncThunk(
|
export const selectFolderWithAllDashboards = createAsyncThunk(
|
||||||
'browseDashboards/selectFolderWithAllDashboards',
|
'browseDashboards/selectFolderWithAllDashboards',
|
||||||
async (
|
async ({ folderUID, isSelected }: { folderUID: string; isSelected: boolean }, { dispatch, getState }) => {
|
||||||
{ folderUID, isSelected }: { folderUID: string; isSelected: boolean },
|
|
||||||
{ dispatch, getState }
|
|
||||||
) => {
|
|
||||||
const state = getState().browseDashboards;
|
const state = getState().browseDashboards;
|
||||||
|
|
||||||
// Find the folder item to get its parentUID and managedBy
|
// Find the folder item to get its parentUID and managedBy
|
||||||
@@ -102,15 +99,17 @@ export const selectFolderWithAllDashboards = createAsyncThunk(
|
|||||||
|
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
// When deselecting, use the normal action - it will handle deselecting all children recursively
|
// When deselecting, use the normal action - it will handle deselecting all children recursively
|
||||||
dispatch(setItemSelectionState({
|
dispatch(
|
||||||
item: {
|
setItemSelectionState({
|
||||||
kind: 'folder',
|
item: {
|
||||||
uid: folderUID,
|
kind: 'folder',
|
||||||
parentUID: folderItem?.parentUID,
|
uid: folderUID,
|
||||||
managedBy: folderItem?.managedBy
|
parentUID: folderItem?.parentUID,
|
||||||
},
|
managedBy: folderItem?.managedBy,
|
||||||
isSelected: false
|
},
|
||||||
}));
|
isSelected: false,
|
||||||
|
})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,15 +118,17 @@ export const selectFolderWithAllDashboards = createAsyncThunk(
|
|||||||
const dashboardUIDs = await collectAllDashboardsUnderFolder(folderUID);
|
const dashboardUIDs = await collectAllDashboardsUnderFolder(folderUID);
|
||||||
|
|
||||||
// First, select the folder itself
|
// First, select the folder itself
|
||||||
dispatch(setItemSelectionState({
|
dispatch(
|
||||||
item: {
|
setItemSelectionState({
|
||||||
kind: 'folder',
|
item: {
|
||||||
uid: folderUID,
|
kind: 'folder',
|
||||||
parentUID: folderItem?.parentUID,
|
uid: folderUID,
|
||||||
managedBy: folderItem?.managedBy
|
parentUID: folderItem?.parentUID,
|
||||||
},
|
managedBy: folderItem?.managedBy,
|
||||||
isSelected: true
|
},
|
||||||
}));
|
isSelected: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Then select all dashboards found
|
// Then select all dashboards found
|
||||||
// We need to get the parentUID for each dashboard from the state
|
// We need to get the parentUID for each dashboard from the state
|
||||||
@@ -136,15 +137,17 @@ export const selectFolderWithAllDashboards = createAsyncThunk(
|
|||||||
const dashboardItem = findItem(state.rootItems?.items ?? [], state.childrenByParentUID, dashboardUID);
|
const dashboardItem = findItem(state.rootItems?.items ?? [], state.childrenByParentUID, dashboardUID);
|
||||||
// Even if dashboard isn't in state, we can still select it by UID
|
// Even if dashboard isn't in state, we can still select it by UID
|
||||||
// The reducer will handle setting selectedItems.dashboard[dashboardUID] = true
|
// The reducer will handle setting selectedItems.dashboard[dashboardUID] = true
|
||||||
dispatch(setItemSelectionState({
|
dispatch(
|
||||||
item: {
|
setItemSelectionState({
|
||||||
kind: 'dashboard',
|
item: {
|
||||||
uid: dashboardUID,
|
kind: 'dashboard',
|
||||||
parentUID: dashboardItem?.parentUID ?? folderUID, // Fallback to folderUID if not found
|
uid: dashboardUID,
|
||||||
managedBy: dashboardItem?.managedBy
|
parentUID: dashboardItem?.parentUID ?? folderUID, // Fallback to folderUID if not found
|
||||||
},
|
managedBy: dashboardItem?.managedBy,
|
||||||
isSelected: true
|
},
|
||||||
}));
|
isSelected: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,4 +29,3 @@ function ExportToRepositoryRenderer({ model }: SceneComponentProps<ExportToRepos
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,10 +57,7 @@ export function RepositoryList({ items }: Props) {
|
|||||||
}
|
}
|
||||||
onRemove={unmanagedCount > 0 ? handlePushUnmanaged : undefined}
|
onRemove={unmanagedCount > 0 ? handlePushUnmanaged : undefined}
|
||||||
>
|
>
|
||||||
<Trans
|
<Trans i18nKey="provisioning.folder-repository-list.partial-managed" values={{ managedCount, resourceCount }}>
|
||||||
i18nKey="provisioning.folder-repository-list.partial-managed"
|
|
||||||
values={{ managedCount, resourceCount }}
|
|
||||||
>
|
|
||||||
{{ managedCount }}/{{ resourceCount }} resources managed by Git sync.
|
{{ managedCount }}/{{ resourceCount }} resources managed by Git sync.
|
||||||
</Trans>
|
</Trans>
|
||||||
{unmanagedCount > 0 && (
|
{unmanagedCount > 0 && (
|
||||||
|
|||||||
+14
-16
@@ -60,17 +60,15 @@ function FormContent({ initialValues, selectedItems, workflowOptions, onDismiss
|
|||||||
}, [repositories, selectedRepositoryName, isLoadingRepos]);
|
}, [repositories, selectedRepositoryName, isLoadingRepos]);
|
||||||
|
|
||||||
// Get selected repository
|
// Get selected repository
|
||||||
const repositoryView: RepositoryView | undefined = repositories.find(
|
const repositoryView: RepositoryView | undefined = repositories.find((repo) => repo.name === selectedRepositoryName);
|
||||||
(repo) => repo.name === selectedRepositoryName
|
|
||||||
);
|
|
||||||
|
|
||||||
// Compute workflow options based on selected repository
|
// Compute workflow options based on selected repository
|
||||||
const selectedWorkflowOptions = repositoryView ? getWorkflowOptions(repositoryView) : workflowOptions;
|
const selectedWorkflowOptions = repositoryView ? getWorkflowOptions(repositoryView) : workflowOptions;
|
||||||
const selectedDefaultWorkflow = repositoryView
|
const selectedDefaultWorkflow = repositoryView
|
||||||
? getDefaultWorkflow(repositoryView)
|
? getDefaultWorkflow(repositoryView)
|
||||||
: (workflowOptions[0]?.value === 'branch' || workflowOptions[0]?.value === 'write'
|
: workflowOptions[0]?.value === 'branch' || workflowOptions[0]?.value === 'write'
|
||||||
? workflowOptions[0].value
|
? workflowOptions[0].value
|
||||||
: undefined);
|
: undefined;
|
||||||
|
|
||||||
// Update workflow, branch, and path when repository changes
|
// Update workflow, branch, and path when repository changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -216,13 +214,14 @@ function FormContent({ initialValues, selectedItems, workflowOptions, onDismiss
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Show form-level errors */}
|
{/* Show form-level errors */}
|
||||||
{errors.root && (
|
{errors.root && <Alert severity="error" title={String(errors.root.message)} />}
|
||||||
<Alert severity="error" title={String(errors.root.message)} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Info if folders are selected */}
|
{/* Info if folders are selected */}
|
||||||
{Object.keys(selectedItems.folder || {}).filter((uid) => selectedItems.folder[uid]).length > 0 && (
|
{Object.keys(selectedItems.folder || {}).filter((uid) => selectedItems.folder[uid]).length > 0 && (
|
||||||
<Alert severity="info" title={t('browse-dashboards.bulk-export-resources-form.folders-info', 'Folders in selection')}>
|
<Alert
|
||||||
|
severity="info"
|
||||||
|
title={t('browse-dashboards.bulk-export-resources-form.folders-info', 'Folders in selection')}
|
||||||
|
>
|
||||||
{t(
|
{t(
|
||||||
'browse-dashboards.bulk-export-resources-form.folders-info-description',
|
'browse-dashboards.bulk-export-resources-form.folders-info-description',
|
||||||
'Folders will be left behind. New folders will be created in the repository based on the resource folder structure.'
|
'Folders will be left behind. New folders will be created in the repository based on the resource folder structure.'
|
||||||
@@ -297,7 +296,10 @@ function FormContent({ initialValues, selectedItems, workflowOptions, onDismiss
|
|||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
{...methods.register('path')}
|
{...methods.register('path')}
|
||||||
placeholder={t('browse-dashboards.bulk-export-resources-form.path-placeholder', 'e.g., dashboards/')}
|
placeholder={t(
|
||||||
|
'browse-dashboards.bulk-export-resources-form.path-placeholder',
|
||||||
|
'e.g., dashboards/'
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
@@ -318,10 +320,7 @@ function FormContent({ initialValues, selectedItems, workflowOptions, onDismiss
|
|||||||
<Button variant="secondary" fill="outline" onClick={onDismiss} disabled={isCreatingJob}>
|
<Button variant="secondary" fill="outline" onClick={onDismiss} disabled={isCreatingJob}>
|
||||||
<Trans i18nKey="browse-dashboards.bulk-export-resources-form.button-cancel">Cancel</Trans>
|
<Trans i18nKey="browse-dashboards.bulk-export-resources-form.button-cancel">Cancel</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button type="submit" disabled={!!job || isCreatingJob || hasSubmitted || !selectedRepositoryName}>
|
||||||
type="submit"
|
|
||||||
disabled={!!job || isCreatingJob || hasSubmitted || !selectedRepositoryName}
|
|
||||||
>
|
|
||||||
{isCreatingJob
|
{isCreatingJob
|
||||||
? t('browse-dashboards.bulk-export-resources-form.button-exporting', 'Exporting...')
|
? t('browse-dashboards.bulk-export-resources-form.button-exporting', 'Exporting...')
|
||||||
: t('browse-dashboards.bulk-export-resources-form.button-export', 'Export')}
|
: t('browse-dashboards.bulk-export-resources-form.button-export', 'Export')}
|
||||||
@@ -382,4 +381,3 @@ const getPathPrefixStyles = (theme: GrafanaTheme2) => ({
|
|||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,21 @@ import { ResourceWrapper } from 'app/api/clients/provisioning/v0alpha1';
|
|||||||
|
|
||||||
import { useProvisionedRequestHandler, RequestHandlers } from './useProvisionedRequestHandler';
|
import { useProvisionedRequestHandler, RequestHandlers } from './useProvisionedRequestHandler';
|
||||||
|
|
||||||
jest.mock('@grafana/runtime', () => ({
|
jest.mock('@grafana/runtime', () => {
|
||||||
getAppEvents: jest.fn(),
|
const original = jest.requireActual('@grafana/runtime');
|
||||||
}));
|
return {
|
||||||
|
...original,
|
||||||
|
getAppEvents: jest.fn(),
|
||||||
|
config: {
|
||||||
|
...original.config,
|
||||||
|
bootData: {
|
||||||
|
user: {},
|
||||||
|
settings: {},
|
||||||
|
navTree: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
jest.mock('@grafana/i18n', () => ({
|
jest.mock('@grafana/i18n', () => ({
|
||||||
t: jest.fn((key: string, defaultValue: string) => defaultValue),
|
t: jest.fn((key: string, defaultValue: string) => defaultValue),
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import { findItem } from '../../browse-dashboards/state/utils';
|
|||||||
import { DashboardTreeSelection } from '../../browse-dashboards/types';
|
import { DashboardTreeSelection } from '../../browse-dashboards/types';
|
||||||
|
|
||||||
// This hook checks if selected items are unmanaged (not managed by any repository)
|
// This hook checks if selected items are unmanaged (not managed by any repository)
|
||||||
export function useSelectionUnmanagedStatus(
|
export function useSelectionUnmanagedStatus(selectedItems: Omit<DashboardTreeSelection, 'panel' | '$all'>): {
|
||||||
selectedItems: Omit<DashboardTreeSelection, 'panel' | '$all'>
|
hasUnmanaged: boolean;
|
||||||
): { hasUnmanaged: boolean; isLoading: boolean } {
|
isLoading: boolean;
|
||||||
|
} {
|
||||||
const browseState = useSelector((state) => state.browseDashboards);
|
const browseState = useSelector((state) => state.browseDashboards);
|
||||||
const [, stateManager] = useSearchStateManager();
|
const [, stateManager] = useSearchStateManager();
|
||||||
const isSearching = stateManager.hasSearchFilters();
|
const isSearching = stateManager.hasSearchFilters();
|
||||||
@@ -155,4 +156,3 @@ export function useSelectionUnmanagedStatus(
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,4 +69,3 @@ export async function collectAllDashboardsUnderFolder(folderUID: string): Promis
|
|||||||
|
|
||||||
return dashboardUIDs;
|
return dashboardUIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user