Provisioning components organize (#109741)
* Provisioning components organize
This commit is contained in:
@@ -16,6 +16,7 @@ import { FolderRepo } from '../../core/components/NestedFolderPicker/FolderRepo'
|
||||
import { contextSrv } from '../../core/services/context_srv';
|
||||
import { ManagerKind } from '../apiserver/types';
|
||||
import { buildNavModel, getDashboardsTabID } from '../folders/state/navModel';
|
||||
import { ProvisionedFolderPreviewBanner } from '../provisioning/components/Folders/ProvisionedFolderPreviewBanner';
|
||||
import { useGetResourceRepositoryView } from '../provisioning/hooks/useGetResourceRepositoryView';
|
||||
import { useSearchStateManager } from '../search/state/SearchStateManager';
|
||||
import { getSearchPlaceholder } from '../search/tempI18nPhrases';
|
||||
@@ -26,7 +27,6 @@ import { BrowseFilters } from './components/BrowseFilters';
|
||||
import { BrowseView } from './components/BrowseView';
|
||||
import CreateNewButton from './components/CreateNewButton';
|
||||
import { FolderActionsButton } from './components/FolderActionsButton';
|
||||
import { ProvisionedFolderPreviewBanner } from './components/ProvisionedFolderPreviewBanner';
|
||||
import { SearchView } from './components/SearchView';
|
||||
import { getFolderPermissions } from './permissions';
|
||||
import { useHasSelection } from './state/hooks';
|
||||
|
||||
@@ -5,6 +5,9 @@ import { config, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, Drawer, Stack } from '@grafana/ui';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
import { BulkDeleteProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkDeleteProvisionedResource';
|
||||
import { BulkMoveProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkMoveProvisionedResource';
|
||||
import { useSelectionProvisioningStatus } from 'app/features/provisioning/hooks/useSelectionProvisioningStatus';
|
||||
import { useSearchStateManager } from 'app/features/search/state/SearchStateManager';
|
||||
import { ShowModalReactEvent } from 'app/types/events';
|
||||
import { FolderDTO } from 'app/types/folders';
|
||||
@@ -14,13 +17,10 @@ import { useDeleteItemsMutation, useMoveItemsMutation } from '../../api/browseDa
|
||||
import { useActionSelectionState } from '../../state/hooks';
|
||||
import { setAllSelection } from '../../state/slice';
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
import { BulkDeleteProvisionedResource } from '../BulkActions/BulkDeleteProvisionedResource';
|
||||
import { BulkMoveProvisionedResource } from '../BulkActions/BulkMoveProvisionedResource';
|
||||
|
||||
import { DeleteModal } from './DeleteModal';
|
||||
import { MoveModal } from './MoveModal';
|
||||
import { SelectedMixResourcesMsgModal } from './SelectedMixResourcesMsgModal';
|
||||
import { useSelectionProvisioningStatus } from './useSelectionProvisioningStatus';
|
||||
|
||||
export interface Props {
|
||||
folderDTO?: FolderDTO;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import { t } from '@grafana/i18n';
|
||||
import { DashboardViewItem } from 'app/features/search/types';
|
||||
|
||||
import { findItem } from '../../state/utils';
|
||||
import { DashboardViewItemCollection } from '../../types';
|
||||
|
||||
export function buildBreakdownString(
|
||||
folderCount: number,
|
||||
@@ -30,40 +26,3 @@ export function buildBreakdownString(
|
||||
}
|
||||
return breakdownString;
|
||||
}
|
||||
|
||||
// Utility: Get root folder for any item (reusing existing pattern from reducers.ts)
|
||||
export function getItemRootFolder(
|
||||
item: { uid: string; parentUID?: string; kind?: string },
|
||||
browseState: {
|
||||
rootItems?: { items: DashboardViewItem[] };
|
||||
childrenByParentUID: Record<string, DashboardViewItemCollection>;
|
||||
}
|
||||
): string | undefined {
|
||||
const rootItems = browseState.rootItems?.items || [];
|
||||
|
||||
// If it's already a root-level item, return its UID (only for folders)
|
||||
if (!item.parentUID) {
|
||||
return item.kind === 'folder' ? item.uid : undefined;
|
||||
}
|
||||
|
||||
// For nested items, traverse up to find root folder (same pattern as reducers.ts)
|
||||
let nextParentUID = item.parentUID;
|
||||
|
||||
while (nextParentUID) {
|
||||
const parent = findItem(rootItems, browseState.childrenByParentUID, nextParentUID);
|
||||
|
||||
// Safety check to prevent infinite loops (same as reducers.ts)
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Found the root folder (no parent)
|
||||
if (!parent.parentUID) {
|
||||
return parent.uid;
|
||||
}
|
||||
|
||||
nextParentUID = parent.parentUID;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ import { t } from '@grafana/i18n';
|
||||
import { Checkbox, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance';
|
||||
import { useSelectionRepoValidation } from 'app/features/provisioning/hooks/useSelectionRepoValidation';
|
||||
import { getReadOnlyTooltipText } from 'app/features/provisioning/utils/repository';
|
||||
import { useSelector } from 'app/types/store';
|
||||
|
||||
import { DashboardsTreeCellProps, SelectionState } from '../types';
|
||||
|
||||
import { useSelectionRepoValidation } from './BrowseActions/useSelectionRepoValidation';
|
||||
import { isSharedWithMe, canEditItemType } from './utils';
|
||||
|
||||
export default function CheckboxCell({
|
||||
|
||||
@@ -6,6 +6,7 @@ import { config, locationService, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
|
||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||
import { RepoType } from 'app/features/provisioning/Wizard/types';
|
||||
import { NewProvisionedFolderForm } from 'app/features/provisioning/components/Folders/NewProvisionedFolderForm';
|
||||
import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance';
|
||||
import { getReadOnlyTooltipText } from 'app/features/provisioning/utils/repository';
|
||||
import {
|
||||
@@ -20,7 +21,6 @@ import { ManagerKind } from '../../apiserver/types';
|
||||
import { useNewFolderMutation } from '../api/browseDashboardsAPI';
|
||||
|
||||
import { NewFolderForm } from './NewFolderForm';
|
||||
import { NewProvisionedFolderForm } from './NewProvisionedFolderForm';
|
||||
|
||||
interface Props {
|
||||
parentFolder?: FolderDTO;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
|
||||
import { Permissions } from 'app/core/components/AccessControl';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { RepoType } from 'app/features/provisioning/Wizard/types';
|
||||
import { DeleteProvisionedFolderForm } from 'app/features/provisioning/components/Folders/DeleteProvisionedFolderForm';
|
||||
import { getReadOnlyTooltipText } from 'app/features/provisioning/utils/repository';
|
||||
import { ShowModalReactEvent } from 'app/types/events';
|
||||
import { FolderDTO } from 'app/types/folders';
|
||||
@@ -18,7 +19,6 @@ import { getFolderPermissions } from '../permissions';
|
||||
|
||||
import { DeleteModal } from './BrowseActions/DeleteModal';
|
||||
import { MoveModal } from './BrowseActions/MoveModal';
|
||||
import { DeleteProvisionedFolderForm } from './DeleteProvisionedFolderForm';
|
||||
|
||||
interface Props {
|
||||
folder: FolderDTO;
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
import { DashboardViewItem } from 'app/features/search/types';
|
||||
import { ResourceRef } from 'app/features/provisioning/components/BulkActions/useBulkActionJob';
|
||||
|
||||
import { findItem } from '../state/utils';
|
||||
import {
|
||||
DashboardTreeSelection,
|
||||
DashboardViewItemWithUIItems,
|
||||
BrowseDashboardsPermissions,
|
||||
BrowseDashboardsState,
|
||||
} from '../types';
|
||||
|
||||
import { ResourceRef } from './BulkActions/useBulkActionJob';
|
||||
import { DashboardTreeSelection, DashboardViewItemWithUIItems, BrowseDashboardsPermissions } from '../types';
|
||||
|
||||
export function makeRowID(baseId: string, item: DashboardViewItemWithUIItems) {
|
||||
return baseId + item.uid;
|
||||
@@ -69,35 +60,3 @@ export function canSelectItems(permissions: BrowseDashboardsPermissions) {
|
||||
const canSelectDashboards = canEditDashboards || canDeleteDashboards;
|
||||
return Boolean(canSelectFolders || canSelectDashboards);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the repository name for an item by traversing up the tree to find the root provisioned folder (managed by ManagerKind.Repo)
|
||||
* This should be an edge case where user have multiple provisioned folders and try to managing resources on root folder
|
||||
*/
|
||||
export function getItemRepositoryUid(
|
||||
item: DashboardViewItem,
|
||||
rootItems: DashboardViewItem[],
|
||||
childrenByParentUID: BrowseDashboardsState['childrenByParentUID']
|
||||
): string {
|
||||
// For root provisioned folders, the UID is the repository name
|
||||
if (item.managedBy === ManagerKind.Repo && !item.parentUID && item.kind === 'folder') {
|
||||
return item.uid;
|
||||
}
|
||||
|
||||
// Traverse up the tree to find the root provisioned folder
|
||||
let currentItem = item;
|
||||
while (currentItem.parentUID) {
|
||||
const parent = findItem(rootItems, childrenByParentUID, currentItem.parentUID);
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (parent.managedBy === ManagerKind.Repo && !parent.parentUID) {
|
||||
return currentItem.parentUID;
|
||||
}
|
||||
|
||||
currentItem = parent;
|
||||
}
|
||||
|
||||
return 'non_provisioned';
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import { DashboardPageError } from 'app/features/dashboard/containers/DashboardPageError';
|
||||
import { DashboardPageRouteParams, DashboardPageRouteSearchParams } from 'app/features/dashboard/containers/types';
|
||||
import { getDashboardSceneProfiler } from 'app/features/dashboard/services/DashboardProfiler';
|
||||
import { DashboardPreviewBanner } from 'app/features/provisioning/components/Dashboards/DashboardPreviewBanner';
|
||||
import { DashboardRoutes } from 'app/types/dashboard';
|
||||
|
||||
import { DashboardPrompt } from '../saving/DashboardPrompt';
|
||||
import { DashboardPreviewBanner } from '../saving/provisioned/DashboardPreviewBanner';
|
||||
import { preserveDashboardSceneStateInLocalStorage } from '../utils/dashboardSessionState';
|
||||
|
||||
import { getDashboardScenePageStateManager } from './DashboardScenePageStateManager';
|
||||
|
||||
@@ -7,10 +7,10 @@ import { Trans, t } from '@grafana/i18n';
|
||||
import { Button, Input, Switch, Field, Label, TextArea, Stack, Alert, Box } from '@grafana/ui';
|
||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
||||
import { getProvisionedMeta } from 'app/features/provisioning/components/utils/getProvisionedMeta';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
|
||||
import { getProvisionedMeta } from './provisioned/utils/getProvisionedMeta';
|
||||
import { DashboardChangeInfo, NameAlreadyExistsError, SaveButton, isNameExistsError } from './shared';
|
||||
import { useSaveDashboard } from './useSaveDashboard';
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { t } from '@grafana/i18n';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState, SceneObjectRef } from '@grafana/scenes';
|
||||
import { Drawer, Tab, TabsBar } from '@grafana/ui';
|
||||
import { SaveDashboardDiff } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardDiff';
|
||||
import { SaveProvisionedDashboard } from 'app/features/provisioning/components/Dashboards/SaveProvisionedDashboard';
|
||||
import { useIsProvisionedNG } from 'app/features/provisioning/hooks/useIsProvisionedNG';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
@@ -9,7 +10,6 @@ import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { SaveDashboardAsForm } from './SaveDashboardAsForm';
|
||||
import { SaveDashboardForm } from './SaveDashboardForm';
|
||||
import { SaveProvisionedDashboardForm } from './SaveProvisionedDashboardForm';
|
||||
import { SaveProvisionedDashboard } from './provisioned/SaveProvisionedDashboard';
|
||||
|
||||
interface SaveDashboardDrawerState extends SceneObjectState {
|
||||
dashboardRef: SceneObjectRef<DashboardScene>;
|
||||
|
||||
@@ -6,7 +6,6 @@ import { config, isFetchError } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { Spec as DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2';
|
||||
import { Alert, Box, Button, Stack } from '@grafana/ui';
|
||||
import { WorkflowOption } from 'app/features/provisioning/types';
|
||||
|
||||
import { Diffs } from '../settings/version-history/utils';
|
||||
|
||||
@@ -24,23 +23,6 @@ export interface DashboardChangeInfo {
|
||||
hasMigratedToV2?: boolean;
|
||||
}
|
||||
|
||||
export interface BaseProvisionedFormData {
|
||||
ref?: string;
|
||||
path: string;
|
||||
comment?: string;
|
||||
repo: string;
|
||||
workflow?: WorkflowOption;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface ProvisionedDashboardFormData extends BaseProvisionedFormData {
|
||||
description: string;
|
||||
folder: {
|
||||
uid?: string;
|
||||
title?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isVersionMismatchError(error?: Error) {
|
||||
return isFetchError(error) && error.data && error.data.status === 'version-mismatch';
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { config, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, ConfirmModal, Modal, Space, Text, TextLink } from '@grafana/ui';
|
||||
import { DeleteProvisionedDashboardDrawer } from 'app/features/provisioning/components/Dashboards/DeleteProvisionedDashboardDrawer';
|
||||
|
||||
import { useDeleteItemsMutation } from '../../browse-dashboards/api/browseDashboardsAPI';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
|
||||
import { DeleteProvisionedDashboardDrawer } from './DeleteProvisionedDashboardDrawer';
|
||||
|
||||
interface ButtonProps {
|
||||
dashboard: DashboardScene;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
import { TimePickerSettings } from 'app/features/dashboard/components/DashboardSettings/TimePickerSettings';
|
||||
import { GenAIDashDescriptionButton } from 'app/features/dashboard/components/GenAI/GenAIDashDescriptionButton';
|
||||
import { GenAIDashTitleButton } from 'app/features/dashboard/components/GenAI/GenAIDashTitleButton';
|
||||
import { MoveProvisionedDashboardDrawer } from 'app/features/provisioning/components/Dashboards/MoveProvisionedDashboardDrawer';
|
||||
|
||||
import { updateNavModel } from '../pages/utils';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
@@ -31,7 +32,6 @@ import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import { getDashboardSceneFor } from '../utils/utils';
|
||||
|
||||
import { DeleteDashboardButton } from './DeleteDashboardButton';
|
||||
import { MoveProvisionedDashboardDrawer } from './MoveProvisionedDashboardDrawer';
|
||||
import { DashboardEditView, DashboardEditViewState, useDashboardEditPageNav } from './utils';
|
||||
|
||||
export interface GeneralSettingsEditViewState extends DashboardEditViewState {
|
||||
|
||||
@@ -111,30 +111,3 @@ export function createDashboardEditViewFor(editview: string): DashboardEditView
|
||||
return new GeneralSettingsEditView({});
|
||||
}
|
||||
}
|
||||
|
||||
export type ResourceBranchUrlOptions = {
|
||||
baseUrl?: string;
|
||||
paramName?: string;
|
||||
paramValue?: string;
|
||||
repoType?: string;
|
||||
};
|
||||
|
||||
export function buildResourceBranchRedirectUrl({
|
||||
baseUrl = '/dashboards',
|
||||
paramName,
|
||||
paramValue,
|
||||
repoType,
|
||||
}: ResourceBranchUrlOptions): string {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (paramName && paramValue) {
|
||||
params.set(paramName, paramValue);
|
||||
}
|
||||
|
||||
if (repoType) {
|
||||
params.set('repo_type', repoType);
|
||||
}
|
||||
|
||||
const queryString = params.toString();
|
||||
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
||||
}
|
||||
|
||||
+3
-3
@@ -3,12 +3,12 @@ import { render } from 'test/test-utils';
|
||||
|
||||
import { Job, RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
import { useSelectionRepoValidation } from '../BrowseActions/useSelectionRepoValidation';
|
||||
import { useSelectionRepoValidation } from '../../hooks/useSelectionRepoValidation';
|
||||
|
||||
import { BulkDeleteProvisionedResource } from './BulkDeleteProvisionedResource';
|
||||
import { ResponseType } from './useBulkActionJob';
|
||||
|
||||
jest.mock('../BrowseActions/DescendantCount', () => ({
|
||||
jest.mock('app/features/browse-dashboards/components/BrowseActions/DescendantCount', () => ({
|
||||
DescendantCount: jest.fn(({ selectedItems }) => (
|
||||
<div data-testid="descendant-count">
|
||||
Mocked descendant count for {Object.keys(selectedItems.folder).length} folders and{' '}
|
||||
@@ -21,7 +21,7 @@ jest.mock('app/features/provisioning/hooks/useGetResourceRepositoryView', () =>
|
||||
useGetResourceRepositoryView: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../BrowseActions/useSelectionRepoValidation', () => ({
|
||||
jest.mock('../../hooks/useSelectionRepoValidation', () => ({
|
||||
useSelectionRepoValidation: jest.fn(),
|
||||
}));
|
||||
|
||||
+7
-7
@@ -6,18 +6,18 @@ import { Trans, t } from '@grafana/i18n';
|
||||
import { getAppEvents } from '@grafana/runtime';
|
||||
import { Box, Button, Stack } from '@grafana/ui';
|
||||
import { Job, RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/dashboard-scene/saving/provisioned/defaults';
|
||||
import { generateTimestamp } from 'app/features/dashboard-scene/saving/provisioned/utils/timestamp';
|
||||
import { DescendantCount } from 'app/features/browse-dashboards/components/BrowseActions/DescendantCount';
|
||||
import { collectSelectedItems } from 'app/features/browse-dashboards/components/utils';
|
||||
import { JobStatus } from 'app/features/provisioning/Job/JobStatus';
|
||||
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
|
||||
import { GENERAL_FOLDER_UID } from 'app/features/search/constants';
|
||||
|
||||
import { DescendantCount } from '../BrowseActions/DescendantCount';
|
||||
import { useSelectionRepoValidation } from '../BrowseActions/useSelectionRepoValidation';
|
||||
import { collectSelectedItems } from '../utils';
|
||||
import { useSelectionRepoValidation } from '../../hooks/useSelectionRepoValidation';
|
||||
import { RepoInvalidStateBanner } from '../Shared/RepoInvalidStateBanner';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from '../defaults';
|
||||
import { generateTimestamp } from '../utils/timestamp';
|
||||
|
||||
import { RepoInvalidStateBanner } from './RepoInvalidStateBanner';
|
||||
import { DeleteJobSpec, useBulkActionJob } from './useBulkActionJob';
|
||||
import { BulkActionFormData, BulkActionProvisionResourceProps } from './utils';
|
||||
|
||||
+7
-7
@@ -9,18 +9,18 @@ import { Box, Button, Field, Stack } from '@grafana/ui';
|
||||
import { useGetFolderQuery } from 'app/api/clients/folder/v1beta1';
|
||||
import { RepositoryView, Job } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/dashboard-scene/saving/provisioned/defaults';
|
||||
import { generateTimestamp } from 'app/features/dashboard-scene/saving/provisioned/utils/timestamp';
|
||||
import { DescendantCount } from 'app/features/browse-dashboards/components/BrowseActions/DescendantCount';
|
||||
import { collectSelectedItems } from 'app/features/browse-dashboards/components/utils';
|
||||
import { JobStatus } from 'app/features/provisioning/Job/JobStatus';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/provisioning/components/defaults';
|
||||
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
|
||||
import { GENERAL_FOLDER_UID } from 'app/features/search/constants';
|
||||
|
||||
import { DescendantCount } from '../BrowseActions/DescendantCount';
|
||||
import { useSelectionRepoValidation } from '../BrowseActions/useSelectionRepoValidation';
|
||||
import { collectSelectedItems } from '../utils';
|
||||
import { useSelectionRepoValidation } from '../../hooks/useSelectionRepoValidation';
|
||||
import { RepoInvalidStateBanner } from '../Shared/RepoInvalidStateBanner';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
import { generateTimestamp } from '../utils/timestamp';
|
||||
|
||||
import { RepoInvalidStateBanner } from './RepoInvalidStateBanner';
|
||||
import { MoveJobSpec, useBulkActionJob } from './useBulkActionJob';
|
||||
import { BulkActionFormData, BulkActionProvisionResourceProps, getTargetFolderPathInRepo } from './utils';
|
||||
|
||||
+3
-4
@@ -2,10 +2,9 @@ import { useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
|
||||
import { rootItemsSelector, useChildrenByParentUIDState } from '../../state/hooks';
|
||||
import { findItem } from '../../state/utils';
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
import { rootItemsSelector, useChildrenByParentUIDState } from 'app/features/browse-dashboards/state/hooks';
|
||||
import { findItem } from 'app/features/browse-dashboards/state/utils';
|
||||
import { DashboardTreeSelection } from 'app/features/browse-dashboards/types';
|
||||
|
||||
// This hook retrieves the folder UID from the selection state. Because search endpoint currently does not return resource metadata
|
||||
// NOTE: This is a temporary workaround until the search endpoint is updated
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
import { Folder } from 'app/api/clients/folder/v1beta1';
|
||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { DashboardTreeSelection } from 'app/features/browse-dashboards/types';
|
||||
import { WorkflowOption } from 'app/features/provisioning/types';
|
||||
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
|
||||
export type BulkActionFormData = {
|
||||
comment: string;
|
||||
ref: string;
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { DashboardPageRouteSearchParams } from 'app/features/dashboard/container
|
||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||
import { DashboardRoutes } from 'app/types/dashboard';
|
||||
|
||||
import { PreviewBannerViewPR } from './PreviewBannerViewPR';
|
||||
import { PreviewBannerViewPR } from '../Shared/PreviewBannerViewPR';
|
||||
|
||||
export interface CommonBannerProps {
|
||||
queryParams: DashboardPageRouteSearchParams;
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
import { useProvisionedDashboardData } from '../saving/provisioned/hooks';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { useProvisionedDashboardData } from '../../hooks/useProvisionedDashboardData';
|
||||
|
||||
import { DeleteProvisionedDashboardForm } from './DeleteProvisionedDashboardForm';
|
||||
|
||||
+14
-5
@@ -4,13 +4,16 @@ import userEvent from '@testing-library/user-event';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { getAppEvents } from '@grafana/runtime';
|
||||
import { useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { useProvisionedDashboardData, ProvisionedDashboardData } from '../saving/provisioned/hooks';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { ProvisionedDashboardData, useProvisionedDashboardData } from '../../hooks/useProvisionedDashboardData';
|
||||
|
||||
import { DeleteProvisionedDashboardDrawer, Props } from './DeleteProvisionedDashboardDrawer';
|
||||
|
||||
// Mock the hooks and dependencies
|
||||
jest.mock('../../hooks/useProvisionedDashboardData', () => ({
|
||||
useProvisionedDashboardData: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('app/api/clients/provisioning/v0alpha1', () => ({
|
||||
useDeleteRepositoryFilesWithPathMutation: jest.fn(),
|
||||
provisioningAPIv0alpha1: {
|
||||
@@ -28,7 +31,13 @@ jest.mock('react-redux', () => {
|
||||
useDispatch: jest.fn(),
|
||||
};
|
||||
});
|
||||
jest.mock('../saving/provisioned/hooks');
|
||||
jest.mock('../../hooks/useProvisionedRequestHandler', () => ({
|
||||
useProvisionedRequestHandler: jest.fn(({ request, handlers }) => {
|
||||
if (request.isError && handlers.onError) {
|
||||
handlers.onError(request.error, { repoType: 'github', resourceType: 'dashboard', workflow: 'branch' });
|
||||
}
|
||||
}),
|
||||
}));
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getAppEvents: jest.fn(),
|
||||
@@ -41,7 +50,7 @@ jest.mock('react-router-dom-v5-compat', () => ({
|
||||
const mockNavigate = jest.fn();
|
||||
|
||||
// Mock shared form components
|
||||
jest.mock('../components/Provisioned/ResourceEditFormSharedFields', () => ({
|
||||
jest.mock('../Shared/ResourceEditFormSharedFields', () => ({
|
||||
ResourceEditFormSharedFields: ({ disabled }: { disabled: boolean }) => (
|
||||
<textarea data-testid="shared-fields" disabled={disabled} />
|
||||
),
|
||||
+6
-7
@@ -6,16 +6,15 @@ import { Trans, t } from '@grafana/i18n';
|
||||
import { getAppEvents } from '@grafana/runtime';
|
||||
import { Button, Drawer, Stack } from '@grafana/ui';
|
||||
import { RepositoryView, useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { RepoInvalidStateBanner } from 'app/features/browse-dashboards/components/BulkActions/RepoInvalidStateBanner';
|
||||
import { getFolderURL } from 'app/features/browse-dashboards/components/utils';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
||||
|
||||
import { ResourceEditFormSharedFields } from '../components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { ProvisionedDashboardFormData } from '../saving/shared';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { useProvisionedRequestHandler, ProvisionedOperationInfo } from '../utils/useProvisionedRequestHandler';
|
||||
|
||||
import { buildResourceBranchRedirectUrl } from './utils';
|
||||
import { ProvisionedOperationInfo, useProvisionedRequestHandler } from '../../hooks/useProvisionedRequestHandler';
|
||||
import { ProvisionedDashboardFormData } from '../../types/form';
|
||||
import { buildResourceBranchRedirectUrl } from '../../utils/redirect';
|
||||
import { RepoInvalidStateBanner } from '../Shared/RepoInvalidStateBanner';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
|
||||
export interface Props {
|
||||
dashboard: DashboardScene;
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
import { useProvisionedDashboardData } from '../saving/provisioned/hooks';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { useProvisionedDashboardData } from '../../hooks/useProvisionedDashboardData';
|
||||
|
||||
import { MoveProvisionedDashboardForm } from './MoveProvisionedDashboardForm';
|
||||
|
||||
+4
-4
@@ -8,9 +8,9 @@ import {
|
||||
useGetRepositoryFilesWithPathQuery,
|
||||
} from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { useProvisionedRequestHandler } from '../utils/useProvisionedRequestHandler';
|
||||
import { useProvisionedRequestHandler } from '../../hooks/useProvisionedRequestHandler';
|
||||
|
||||
import { MoveProvisionedDashboardForm, Props } from './MoveProvisionedDashboardForm';
|
||||
|
||||
@@ -38,7 +38,7 @@ jest.mock('app/api/clients/folder/v1beta1', () => ({
|
||||
useGetFolderQuery: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../utils/useProvisionedRequestHandler', () => ({
|
||||
jest.mock('../../hooks/useProvisionedRequestHandler', () => ({
|
||||
useProvisionedRequestHandler: jest.fn(),
|
||||
}));
|
||||
|
||||
@@ -46,7 +46,7 @@ jest.mock('react-router-dom-v5-compat', () => ({
|
||||
useNavigate: () => jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../components/Provisioned/ResourceEditFormSharedFields', () => ({
|
||||
jest.mock('../Shared/ResourceEditFormSharedFields', () => ({
|
||||
ResourceEditFormSharedFields: () => <div data-testid="resource-edit-form" />,
|
||||
}));
|
||||
|
||||
+6
-7
@@ -14,14 +14,13 @@ import {
|
||||
useGetRepositoryFilesWithPathQuery,
|
||||
} from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { getTargetFolderPathInRepo } from 'app/features/browse-dashboards/components/BulkActions/utils';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { ResourceEditFormSharedFields } from '../components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { ProvisionedDashboardFormData } from '../saving/shared';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { useProvisionedRequestHandler, ProvisionedOperationInfo } from '../utils/useProvisionedRequestHandler';
|
||||
|
||||
import { buildResourceBranchRedirectUrl } from './utils';
|
||||
import { ProvisionedOperationInfo, useProvisionedRequestHandler } from '../../hooks/useProvisionedRequestHandler';
|
||||
import { ProvisionedDashboardFormData } from '../../types/form';
|
||||
import { buildResourceBranchRedirectUrl } from '../../utils/redirect';
|
||||
import { getTargetFolderPathInRepo } from '../BulkActions/utils';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
|
||||
export interface Props {
|
||||
dashboard: DashboardScene;
|
||||
+5
-4
@@ -1,9 +1,10 @@
|
||||
import { DashboardScene } from '../../scene/DashboardScene';
|
||||
import { SaveDashboardDrawer } from '../SaveDashboardDrawer';
|
||||
import { DashboardChangeInfo } from '../shared';
|
||||
import { SaveDashboardDrawer } from 'app/features/dashboard-scene/saving/SaveDashboardDrawer';
|
||||
import { DashboardChangeInfo } from 'app/features/dashboard-scene/saving/shared';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { useProvisionedDashboardData } from '../../hooks/useProvisionedDashboardData';
|
||||
|
||||
import { SaveProvisionedDashboardForm } from './SaveProvisionedDashboardForm';
|
||||
import { useProvisionedDashboardData } from './hooks';
|
||||
|
||||
export interface SaveProvisionedDashboardProps {
|
||||
dashboard: DashboardScene;
|
||||
+5
-6
@@ -4,12 +4,11 @@ import userEvent from '@testing-library/user-event';
|
||||
import { getAppEvents } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { AnnoKeyFolder, AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { SaveDashboardDrawer } from 'app/features/dashboard-scene/saving/SaveDashboardDrawer';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
||||
import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile';
|
||||
|
||||
import { DashboardScene } from '../../scene/DashboardScene';
|
||||
import { SaveDashboardDrawer } from '../SaveDashboardDrawer';
|
||||
|
||||
import { SaveProvisionedDashboardForm, Props } from './SaveProvisionedDashboardForm';
|
||||
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
@@ -31,7 +30,7 @@ jest.mock('@grafana/runtime', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('app/features/dashboard-scene/utils/useProvisionedRequestHandler', () => {
|
||||
jest.mock('../../hooks/useProvisionedRequestHandler', () => {
|
||||
return {
|
||||
useProvisionedRequestHandler: jest.fn(),
|
||||
};
|
||||
@@ -77,8 +76,8 @@ jest.mock('react-router-dom-v5-compat', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../SaveDashboardForm', () => {
|
||||
const actual = jest.requireActual('../SaveDashboardForm');
|
||||
jest.mock('app/features/dashboard-scene/saving/SaveDashboardForm', () => {
|
||||
const actual = jest.requireActual('app/features/dashboard-scene/saving/SaveDashboardForm');
|
||||
return {
|
||||
...actual,
|
||||
SaveDashboardFormCommonOptions: () => <div data-testid="common-options">Common Options</div>,
|
||||
+11
-8
@@ -11,20 +11,23 @@ import { RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import { Resource } from 'app/features/apiserver/types';
|
||||
import { RepoInvalidStateBanner } from 'app/features/browse-dashboards/components/BulkActions/RepoInvalidStateBanner';
|
||||
import { SaveDashboardFormCommonOptions } from 'app/features/dashboard-scene/saving/SaveDashboardForm';
|
||||
import { getDashboardUrl } from 'app/features/dashboard-scene/utils/getDashboardUrl';
|
||||
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
||||
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
||||
import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile';
|
||||
import {
|
||||
ProvisionedOperationInfo,
|
||||
useProvisionedRequestHandler,
|
||||
} from 'app/features/provisioning/hooks/useProvisionedRequestHandler';
|
||||
|
||||
import { ResourceEditFormSharedFields } from '../../components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { buildResourceBranchRedirectUrl } from '../../settings/utils';
|
||||
import { getDashboardUrl } from '../../utils/getDashboardUrl';
|
||||
import { ProvisionedOperationInfo, useProvisionedRequestHandler } from '../../utils/useProvisionedRequestHandler';
|
||||
import { SaveDashboardFormCommonOptions } from '../SaveDashboardForm';
|
||||
import { ProvisionedDashboardFormData } from '../shared';
|
||||
import { ProvisionedDashboardFormData } from '../../types/form';
|
||||
import { buildResourceBranchRedirectUrl } from '../../utils/redirect';
|
||||
import { RepoInvalidStateBanner } from '../Shared/RepoInvalidStateBanner';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
import { getProvisionedMeta } from '../utils/getProvisionedMeta';
|
||||
|
||||
import { SaveProvisionedDashboardProps } from './SaveProvisionedDashboard';
|
||||
import { getProvisionedMeta } from './utils/getProvisionedMeta';
|
||||
|
||||
export interface Props extends SaveProvisionedDashboardProps {
|
||||
isNew: boolean;
|
||||
+7
-4
@@ -4,7 +4,10 @@ import userEvent from '@testing-library/user-event';
|
||||
import { RepositoryView, useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { FolderDTO } from 'app/types/folders';
|
||||
|
||||
import { ProvisionedFolderFormDataResult, useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
|
||||
import {
|
||||
ProvisionedFolderFormDataResult,
|
||||
useProvisionedFolderFormData,
|
||||
} from '../../hooks/useProvisionedFolderFormData';
|
||||
|
||||
import { DeleteProvisionedFolderForm } from './DeleteProvisionedFolderForm';
|
||||
|
||||
@@ -47,13 +50,13 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../hooks/useProvisionedFolderFormData');
|
||||
jest.mock('../../hooks/useProvisionedFolderFormData');
|
||||
|
||||
jest.mock('./BrowseActions/DescendantCount', () => ({
|
||||
jest.mock('app/features/browse-dashboards/components/BrowseActions/DescendantCount', () => ({
|
||||
DescendantCount: () => <div data-testid="descendant-count">2 folders, 5 dashboards</div>,
|
||||
}));
|
||||
|
||||
jest.mock('app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields', () => ({
|
||||
jest.mock('../Shared/ResourceEditFormSharedFields', () => ({
|
||||
ResourceEditFormSharedFields: () => <div data-testid="shared-fields" />,
|
||||
}));
|
||||
|
||||
+8
-12
@@ -8,20 +8,16 @@ import { Box, Button, Stack } from '@grafana/ui';
|
||||
import { Folder } from 'app/api/clients/folder/v1beta1';
|
||||
import { RepositoryView, useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
|
||||
import { buildResourceBranchRedirectUrl } from 'app/features/dashboard-scene/settings/utils';
|
||||
import {
|
||||
useProvisionedRequestHandler,
|
||||
ProvisionedOperationInfo,
|
||||
} from 'app/features/dashboard-scene/utils/useProvisionedRequestHandler';
|
||||
import { DescendantCount } from 'app/features/browse-dashboards/components/BrowseActions/DescendantCount';
|
||||
import { getFolderURL } from 'app/features/browse-dashboards/components/utils';
|
||||
import { FolderDTO } from 'app/types/folders';
|
||||
|
||||
import { useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
|
||||
|
||||
import { DescendantCount } from './BrowseActions/DescendantCount';
|
||||
import { RepoInvalidStateBanner } from './BulkActions/RepoInvalidStateBanner';
|
||||
import { getFolderURL } from './utils';
|
||||
import { useProvisionedFolderFormData } from '../../hooks/useProvisionedFolderFormData';
|
||||
import { ProvisionedOperationInfo, useProvisionedRequestHandler } from '../../hooks/useProvisionedRequestHandler';
|
||||
import { BaseProvisionedFormData } from '../../types/form';
|
||||
import { buildResourceBranchRedirectUrl } from '../../utils/redirect';
|
||||
import { RepoInvalidStateBanner } from '../Shared/RepoInvalidStateBanner';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
|
||||
interface FormProps extends DeleteProvisionedFolderFormProps {
|
||||
initialValues: BaseProvisionedFormData;
|
||||
+5
-13
@@ -8,7 +8,10 @@ import { validationSrv } from 'app/features/manage-dashboards/services/Validatio
|
||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||
import { FolderDTO } from 'app/types/folders';
|
||||
|
||||
import { ProvisionedFolderFormDataResult, useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
|
||||
import {
|
||||
ProvisionedFolderFormDataResult,
|
||||
useProvisionedFolderFormData,
|
||||
} from '../../hooks/useProvisionedFolderFormData';
|
||||
|
||||
import { NewProvisionedFolderForm } from './NewProvisionedFolderForm';
|
||||
|
||||
@@ -47,7 +50,7 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../hooks/useProvisionedFolderFormData', () => {
|
||||
jest.mock('../../hooks/useProvisionedFolderFormData', () => {
|
||||
return {
|
||||
useProvisionedFolderFormData: jest.fn(),
|
||||
};
|
||||
@@ -75,17 +78,6 @@ jest.mock('react-router-dom-v5-compat', () => {
|
||||
};
|
||||
});
|
||||
|
||||
// Mock the defaults
|
||||
jest.mock('../../dashboard-scene/saving/provisioned/defaults', () => {
|
||||
return {
|
||||
getDefaultWorkflow: jest.fn().mockReturnValue('write'),
|
||||
getWorkflowOptions: jest.fn().mockReturnValue([
|
||||
{ label: 'Commit directly', value: 'write' },
|
||||
{ label: 'Create a branch', value: 'branch' },
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
interface Props {
|
||||
onDismiss?: () => void;
|
||||
parentFolder?: FolderDTO;
|
||||
+6
-10
@@ -8,20 +8,16 @@ import { Alert, Button, Field, Input, Stack } from '@grafana/ui';
|
||||
import { Folder } from 'app/api/clients/folder/v1beta1';
|
||||
import { RepositoryView, useCreateRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { AnnoKeySourcePath, Resource } from 'app/features/apiserver/types';
|
||||
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
|
||||
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
|
||||
import { buildResourceBranchRedirectUrl } from 'app/features/dashboard-scene/settings/utils';
|
||||
import {
|
||||
useProvisionedRequestHandler,
|
||||
ProvisionedOperationInfo,
|
||||
} from 'app/features/dashboard-scene/utils/useProvisionedRequestHandler';
|
||||
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||
import { FolderDTO } from 'app/types/folders';
|
||||
|
||||
import { useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
|
||||
|
||||
import { RepoInvalidStateBanner } from './BulkActions/RepoInvalidStateBanner';
|
||||
import { useProvisionedFolderFormData } from '../../hooks/useProvisionedFolderFormData';
|
||||
import { ProvisionedOperationInfo, useProvisionedRequestHandler } from '../../hooks/useProvisionedRequestHandler';
|
||||
import { BaseProvisionedFormData } from '../../types/form';
|
||||
import { buildResourceBranchRedirectUrl } from '../../utils/redirect';
|
||||
import { RepoInvalidStateBanner } from '../Shared/RepoInvalidStateBanner';
|
||||
import { ResourceEditFormSharedFields } from '../Shared/ResourceEditFormSharedFields';
|
||||
|
||||
interface FormProps extends Props {
|
||||
initialValues: BaseProvisionedFormData;
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { CommonBannerProps } from 'app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner';
|
||||
import { PreviewBannerViewPR } from 'app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR';
|
||||
import { CommonBannerProps } from 'app/features/provisioning/components/Dashboards/DashboardPreviewBanner';
|
||||
import { PreviewBannerViewPR } from 'app/features/provisioning/components/Shared/PreviewBannerViewPR';
|
||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||
|
||||
export function ProvisionedFolderPreviewBanner({ queryParams }: CommonBannerProps) {
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { Alert, Icon, Stack } from '@grafana/ui';
|
||||
import { RepoTypeDisplay, RepoType } from 'app/features/provisioning/Wizard/types';
|
||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||
|
||||
import { commonAlertProps } from './DashboardPreviewBanner';
|
||||
import { commonAlertProps } from '../Dashboards/DashboardPreviewBanner';
|
||||
|
||||
// TODO: We have this https://github.com/grafana/git-ui-sync-project/issues/166 to add more details about the PR.
|
||||
|
||||
+3
-2
@@ -3,8 +3,9 @@ import userEvent from '@testing-library/user-event';
|
||||
import { ReactNode } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
import { RepositoryView } from '../../../../api/clients/provisioning/v0alpha1';
|
||||
import { ProvisionedDashboardFormData } from '../../saving/shared';
|
||||
import { RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
import { ProvisionedDashboardFormData } from '../../types/form';
|
||||
|
||||
import { ResourceEditFormSharedFields } from './ResourceEditFormSharedFields';
|
||||
|
||||
+5
-6
@@ -3,16 +3,15 @@ import { useState } from 'react';
|
||||
import { RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { useUrlParams } from 'app/core/navigation/hooks';
|
||||
import { AnnoKeyManagerIdentity, AnnoKeyManagerKind, AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
|
||||
import { getIsReadOnlyRepo } from 'app/features/provisioning/utils/repository';
|
||||
import { DashboardMeta } from 'app/types/dashboard';
|
||||
|
||||
import { DashboardScene } from '../../scene/DashboardScene';
|
||||
import { ProvisionedDashboardFormData } from '../shared';
|
||||
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from './defaults';
|
||||
import { generatePath } from './utils/path';
|
||||
import { generateTimestamp } from './utils/timestamp';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from '../components/defaults';
|
||||
import { generatePath } from '../components/utils/path';
|
||||
import { generateTimestamp } from '../components/utils/timestamp';
|
||||
import { ProvisionedDashboardFormData } from '../types/form';
|
||||
|
||||
interface UseDefaultValuesParams {
|
||||
meta: DashboardMeta;
|
||||
+4
-4
@@ -3,13 +3,13 @@ import { useMemo } from 'react';
|
||||
import { Folder } from 'app/api/clients/folder/v1beta1';
|
||||
import { RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/dashboard-scene/saving/provisioned/defaults';
|
||||
import { generateTimestamp } from 'app/features/dashboard-scene/saving/provisioned/utils/timestamp';
|
||||
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/provisioning/components/defaults';
|
||||
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
|
||||
|
||||
import { BaseProvisionedFormData } from '../../dashboard-scene/saving/shared';
|
||||
import { generateTimestamp } from '../components/utils/timestamp';
|
||||
import { BaseProvisionedFormData } from '../types/form';
|
||||
|
||||
export interface UseProvisionedFolderFormDataProps {
|
||||
interface UseProvisionedFolderFormDataProps {
|
||||
folderUid?: string;
|
||||
action: 'create' | 'delete';
|
||||
title?: string;
|
||||
+2
-2
@@ -9,8 +9,8 @@ import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsP
|
||||
import { useSearchStateManager } from 'app/features/search/state/SearchStateManager';
|
||||
import { useSelector } from 'app/types/store';
|
||||
|
||||
import { findItem } from '../../state/utils';
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
import { findItem } from '../../browse-dashboards/state/utils';
|
||||
import { DashboardTreeSelection } from '../../browse-dashboards/types';
|
||||
|
||||
// TODO: This will soon be remove after bulk action is merged in
|
||||
|
||||
+4
-5
@@ -2,14 +2,13 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { useGetFrontendSettingsQuery } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { findItem } from 'app/features/browse-dashboards/state/utils';
|
||||
import { DashboardTreeSelection } from 'app/features/browse-dashboards/types';
|
||||
import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance';
|
||||
import { getIsReadOnlyRepo } from 'app/features/provisioning/utils/repository';
|
||||
import { getIsReadOnlyRepo, getItemRepositoryUid } from 'app/features/provisioning/utils/repository';
|
||||
import { useSelector } from 'app/types/store';
|
||||
|
||||
import { useChildrenByParentUIDState, rootItemsSelector } from '../../state/hooks';
|
||||
import { findItem } from '../../state/utils';
|
||||
import { DashboardTreeSelection } from '../../types';
|
||||
import { getItemRepositoryUid } from '../utils';
|
||||
import { useChildrenByParentUIDState, rootItemsSelector } from '../../browse-dashboards/state/hooks';
|
||||
|
||||
// This hook is responsible for validating if all selected resources (dashboard folders and dashboards) are in the same repository
|
||||
export function useSelectionRepoValidation(selectedItems: Omit<DashboardTreeSelection, 'panel' | '$all'>) {
|
||||
@@ -0,0 +1,18 @@
|
||||
import { WorkflowOption } from '../types';
|
||||
|
||||
export interface BaseProvisionedFormData {
|
||||
ref?: string;
|
||||
path: string;
|
||||
comment?: string;
|
||||
repo: string;
|
||||
workflow?: WorkflowOption;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface ProvisionedDashboardFormData extends BaseProvisionedFormData {
|
||||
description: string;
|
||||
folder: {
|
||||
uid?: string;
|
||||
title?: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
type ResourceBranchUrlOptions = {
|
||||
baseUrl?: string;
|
||||
paramName?: string;
|
||||
paramValue?: string;
|
||||
repoType?: string;
|
||||
};
|
||||
|
||||
export function buildResourceBranchRedirectUrl({
|
||||
baseUrl = '/dashboards',
|
||||
paramName,
|
||||
paramValue,
|
||||
repoType,
|
||||
}: ResourceBranchUrlOptions): string {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (paramName && paramValue) {
|
||||
params.set(paramName, paramValue);
|
||||
}
|
||||
|
||||
if (repoType) {
|
||||
params.set('repo_type', repoType);
|
||||
}
|
||||
|
||||
const queryString = params.toString();
|
||||
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import { t } from '@grafana/i18n';
|
||||
import { RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
import { findItem } from 'app/features/browse-dashboards/state/utils';
|
||||
import { BrowseDashboardsState } from 'app/features/browse-dashboards/types';
|
||||
import { DashboardViewItem } from 'app/features/search/types';
|
||||
|
||||
import { RepoWorkflows } from '../types';
|
||||
|
||||
@@ -28,3 +32,35 @@ export const getReadOnlyTooltipText = ({ isLocal = false }) => {
|
||||
'This folder is read-only and provisioned through Git. To make any changes in the folder, update the connected repository. To modify the folder settings go to Administration > Provisioning > Repositories.'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the repository name for an item by traversing up the tree to find the root provisioned folder (managed by ManagerKind.Repo)
|
||||
* This should be an edge case where user have multiple provisioned folders and try to managing resources on root folder
|
||||
*/
|
||||
export function getItemRepositoryUid(
|
||||
item: DashboardViewItem,
|
||||
rootItems: DashboardViewItem[],
|
||||
childrenByParentUID: BrowseDashboardsState['childrenByParentUID']
|
||||
): string {
|
||||
// For root provisioned folders, the UID is the repository name
|
||||
if (item.managedBy === ManagerKind.Repo && !item.parentUID && item.kind === 'folder') {
|
||||
return item.uid;
|
||||
}
|
||||
|
||||
// Traverse up the tree to find the root provisioned folder
|
||||
let currentItem = item;
|
||||
while (currentItem.parentUID) {
|
||||
const parent = findItem(rootItems, childrenByParentUID, currentItem.parentUID);
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (parent.managedBy === ManagerKind.Repo && !parent.parentUID) {
|
||||
return currentItem.parentUID;
|
||||
}
|
||||
|
||||
currentItem = parent;
|
||||
}
|
||||
|
||||
return 'non_provisioned';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user