mirror of https://github.com/grafana/grafana.git
Git sync create folder flow refactor to use new hook (#107422)
Actionlint / Lint GitHub Actions files (push) Waiting to run
Details
Backend Code Checks / Validate Backend Configs (push) Waiting to run
Details
Backend Unit Tests / Detect whether code changed (push) Waiting to run
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (1/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (2/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (3/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (4/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (5/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (6/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (7/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (8/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (1/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (2/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (3/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (4/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (5/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (6/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (7/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (8/8) (push) Blocked by required conditions
Details
Backend Unit Tests / All backend unit tests complete (push) Blocked by required conditions
Details
CodeQL checks / Analyze (actions) (push) Waiting to run
Details
CodeQL checks / Analyze (go) (push) Waiting to run
Details
CodeQL checks / Analyze (javascript) (push) Waiting to run
Details
Lint Frontend / Detect whether code changed (push) Waiting to run
Details
Lint Frontend / Lint (push) Blocked by required conditions
Details
Lint Frontend / Typecheck (push) Blocked by required conditions
Details
Lint Frontend / Betterer (push) Blocked by required conditions
Details
golangci-lint / lint-go (push) Waiting to run
Details
Verify i18n / verify-i18n (push) Waiting to run
Details
Documentation / Build & Verify Docs (push) Waiting to run
Details
End-to-end tests / Detect whether code changed (push) Waiting to run
Details
End-to-end tests / Build & Package Grafana (push) Blocked by required conditions
Details
End-to-end tests / Build E2E test runner (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/dashboards-suite, dashboards-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/panels-suite, panels-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/smoke-tests-suite, smoke-tests-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/various-suite, various-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/dashboards-suite, dashboards-suite) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/panels-suite, panels-suite) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/smoke-tests-suite, smoke-tests-suite) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/various-suite, various-suite) (push) Blocked by required conditions
Details
End-to-end tests / A11y test (push) Blocked by required conditions
Details
End-to-end tests / All E2E tests complete (push) Blocked by required conditions
Details
Frontend tests / Detect whether code changed (push) Waiting to run
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (1) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (2) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (3) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (4) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (5) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (6) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (7) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (8) (push) Blocked by required conditions
Details
Frontend tests / All frontend unit tests complete (push) Blocked by required conditions
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (1/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (2/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (3/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (4/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (5/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (6/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (7/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (8/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (1/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (2/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (3/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (4/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (5/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (6/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (7/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (8/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (1/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (2/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (3/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (4/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (5/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (6/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (7/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (8/8) (push) Waiting to run
Details
Integration Tests / All backend integration tests complete (push) Blocked by required conditions
Details
publish-technical-documentation-next / sync (push) Waiting to run
Details
Reject GitHub secrets / reject-gh-secrets (push) Waiting to run
Details
Build Release Packages / setup (push) Waiting to run
Details
Build Release Packages / Dispatch grafana-enterprise build (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:darwin/amd64, darwin-amd64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:darwin/arm64, darwin-arm64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/amd64,deb:grafana:linux/amd64,rpm:grafana:linux/amd64,docker:grafana:linux/amd64,docker:grafana:linux/amd64:ubuntu,npm:grafana,storybook, linux-amd64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6, linux-armv6) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm/v7,deb:grafana:linux/arm/v7,docker:grafana:linux/arm/v7,docker:grafana:linux/arm/v7:ubuntu, linux-armv7) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm64,deb:grafana:linux/arm64,rpm:grafana:linux/arm64,docker:grafana:linux/arm64,docker:grafana:linux/arm64:ubuntu, linux-arm64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/s390x,deb:grafana:linux/s390x,rpm:grafana:linux/s390x,docker:grafana:linux/s390x,docker:grafana:linux/s390x:ubuntu, linux-s390x) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:windows/amd64,zip:grafana:windows/amd64,msi:grafana:windows/amd64, windows-amd64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:windows/arm64,zip:grafana:windows/arm64, windows-arm64) (push) Blocked by required conditions
Details
Build Release Packages / Upload artifacts (push) Blocked by required conditions
Details
Run dashboard schema v2 e2e / dashboard-schema-v2-e2e (push) Waiting to run
Details
Shellcheck / Shellcheck scripts (push) Waiting to run
Details
Verify Storybook / Verify Storybook (push) Waiting to run
Details
Swagger generated code / Verify committed API specs match (push) Waiting to run
Details
Dispatch sync to mirror / dispatch-job (push) Waiting to run
Details
trigger-dashboard-search-e2e / trigger-search-e2e (push) Waiting to run
Details
Crowdin Upload Action / upload-sources-to-crowdin (push) Has been cancelled
Details
Actionlint / Lint GitHub Actions files (push) Waiting to run
Details
Backend Code Checks / Validate Backend Configs (push) Waiting to run
Details
Backend Unit Tests / Detect whether code changed (push) Waiting to run
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (1/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (2/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (3/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (4/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (5/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (6/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (7/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana (${{ matrix.shard }}) (8/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (1/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (2/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (3/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (4/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (5/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (6/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (7/8) (push) Blocked by required conditions
Details
Backend Unit Tests / Grafana Enterprise (${{ matrix.shard }}) (8/8) (push) Blocked by required conditions
Details
Backend Unit Tests / All backend unit tests complete (push) Blocked by required conditions
Details
CodeQL checks / Analyze (actions) (push) Waiting to run
Details
CodeQL checks / Analyze (go) (push) Waiting to run
Details
CodeQL checks / Analyze (javascript) (push) Waiting to run
Details
Lint Frontend / Detect whether code changed (push) Waiting to run
Details
Lint Frontend / Lint (push) Blocked by required conditions
Details
Lint Frontend / Typecheck (push) Blocked by required conditions
Details
Lint Frontend / Betterer (push) Blocked by required conditions
Details
golangci-lint / lint-go (push) Waiting to run
Details
Verify i18n / verify-i18n (push) Waiting to run
Details
Documentation / Build & Verify Docs (push) Waiting to run
Details
End-to-end tests / Detect whether code changed (push) Waiting to run
Details
End-to-end tests / Build & Package Grafana (push) Blocked by required conditions
Details
End-to-end tests / Build E2E test runner (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/dashboards-suite, dashboards-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/panels-suite, panels-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/smoke-tests-suite, smoke-tests-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (--flags="--env dashboardScene=false", e2e/old-arch/various-suite, various-suite (old arch)) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/dashboards-suite, dashboards-suite) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/panels-suite, panels-suite) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/smoke-tests-suite, smoke-tests-suite) (push) Blocked by required conditions
Details
End-to-end tests / ${{ matrix.suite }} (e2e/various-suite, various-suite) (push) Blocked by required conditions
Details
End-to-end tests / A11y test (push) Blocked by required conditions
Details
End-to-end tests / All E2E tests complete (push) Blocked by required conditions
Details
Frontend tests / Detect whether code changed (push) Waiting to run
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (1) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (2) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (3) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (4) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (5) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (6) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (7) (push) Blocked by required conditions
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (8) (push) Blocked by required conditions
Details
Frontend tests / All frontend unit tests complete (push) Blocked by required conditions
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (1/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (2/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (3/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (4/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (5/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (6/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (7/8) (push) Waiting to run
Details
Integration Tests / Sqlite (${{ matrix.shard }}) (8/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (1/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (2/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (3/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (4/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (5/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (6/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (7/8) (push) Waiting to run
Details
Integration Tests / MySQL (${{ matrix.shard }}) (8/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (1/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (2/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (3/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (4/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (5/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (6/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (7/8) (push) Waiting to run
Details
Integration Tests / Postgres (${{ matrix.shard }}) (8/8) (push) Waiting to run
Details
Integration Tests / All backend integration tests complete (push) Blocked by required conditions
Details
publish-technical-documentation-next / sync (push) Waiting to run
Details
Reject GitHub secrets / reject-gh-secrets (push) Waiting to run
Details
Build Release Packages / setup (push) Waiting to run
Details
Build Release Packages / Dispatch grafana-enterprise build (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:darwin/amd64, darwin-amd64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:darwin/arm64, darwin-arm64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/amd64,deb:grafana:linux/amd64,rpm:grafana:linux/amd64,docker:grafana:linux/amd64,docker:grafana:linux/amd64:ubuntu,npm:grafana,storybook, linux-amd64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6, linux-armv6) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm/v7,deb:grafana:linux/arm/v7,docker:grafana:linux/arm/v7,docker:grafana:linux/arm/v7:ubuntu, linux-armv7) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/arm64,deb:grafana:linux/arm64,rpm:grafana:linux/arm64,docker:grafana:linux/arm64,docker:grafana:linux/arm64:ubuntu, linux-arm64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:linux/s390x,deb:grafana:linux/s390x,rpm:grafana:linux/s390x,docker:grafana:linux/s390x,docker:grafana:linux/s390x:ubuntu, linux-s390x) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:windows/amd64,zip:grafana:windows/amd64,msi:grafana:windows/amd64, windows-amd64) (push) Blocked by required conditions
Details
Build Release Packages / ${{ needs.setup.outputs.version }} / ${{ matrix.name }} (targz:grafana:windows/arm64,zip:grafana:windows/arm64, windows-arm64) (push) Blocked by required conditions
Details
Build Release Packages / Upload artifacts (push) Blocked by required conditions
Details
Run dashboard schema v2 e2e / dashboard-schema-v2-e2e (push) Waiting to run
Details
Shellcheck / Shellcheck scripts (push) Waiting to run
Details
Verify Storybook / Verify Storybook (push) Waiting to run
Details
Swagger generated code / Verify committed API specs match (push) Waiting to run
Details
Dispatch sync to mirror / dispatch-job (push) Waiting to run
Details
trigger-dashboard-search-e2e / trigger-search-e2e (push) Waiting to run
Details
Crowdin Upload Action / upload-sources-to-crowdin (push) Has been cancelled
Details
* Git sync create folder flow refactor to use new hook --------- Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
parent
8b9e57f2f6
commit
fdf4935e42
|
@ -1493,12 +1493,6 @@ exports[`better eslint`] = {
|
||||||
"public/app/features/browse-dashboards/components/NewFolderForm.tsx:5381": [
|
"public/app/features/browse-dashboards/components/NewFolderForm.tsx:5381": [
|
||||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"]
|
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"]
|
||||||
],
|
],
|
||||||
"public/app/features/browse-dashboards/components/NewProvisionedFolderForm.tsx:5381": [
|
|
||||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
|
|
||||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"],
|
|
||||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "2"],
|
|
||||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "3"]
|
|
||||||
],
|
|
||||||
"public/app/features/browse-dashboards/state/index.ts:5381": [
|
"public/app/features/browse-dashboards/state/index.ts:5381": [
|
||||||
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"],
|
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"],
|
||||||
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"],
|
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"],
|
||||||
|
|
|
@ -107,11 +107,7 @@ export default function CreateNewButton({ parentFolder, canCreateDashboard, canC
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
{parentFolder?.managedBy === ManagerKind.Repo || isProvisionedInstance ? (
|
{parentFolder?.managedBy === ManagerKind.Repo || isProvisionedInstance ? (
|
||||||
<NewProvisionedFolderForm
|
<NewProvisionedFolderForm onDismiss={() => setShowNewFolderDrawer(false)} parentFolder={parentFolder} />
|
||||||
onSubmit={() => setShowNewFolderDrawer(false)}
|
|
||||||
onCancel={() => setShowNewFolderDrawer(false)}
|
|
||||||
parentFolder={parentFolder}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<NewFolderForm onConfirm={onCreateFolder} onCancel={() => setShowNewFolderDrawer(false)} />
|
<NewFolderForm onConfirm={onCreateFolder} onCancel={() => setShowNewFolderDrawer(false)} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -33,8 +33,8 @@ jest.mock('./BrowseActions/DescendantCount', () => ({
|
||||||
DescendantCount: () => <div data-testid="descendant-count">2 folders, 5 dashboards</div>,
|
DescendantCount: () => <div data-testid="descendant-count">2 folders, 5 dashboards</div>,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('app/features/dashboard-scene/components/Provisioned/DashboardEditFormSharedFields', () => ({
|
jest.mock('app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields', () => ({
|
||||||
DashboardEditFormSharedFields: () => <div data-testid="shared-fields" />,
|
ResourceEditFormSharedFields: () => <div data-testid="shared-fields" />,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const mockUseDeleteRepositoryFilesMutation = useDeleteRepositoryFilesWithPathMutation as jest.MockedFunction<
|
const mockUseDeleteRepositoryFilesMutation = useDeleteRepositoryFilesWithPathMutation as jest.MockedFunction<
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { Box, Button, Stack } from '@grafana/ui';
|
||||||
import { Folder } from 'app/api/clients/folder/v1beta1';
|
import { Folder } from 'app/api/clients/folder/v1beta1';
|
||||||
import { RepositoryView, useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
import { RepositoryView, useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||||
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
|
||||||
import { DashboardEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/DashboardEditFormSharedFields';
|
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
|
||||||
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
|
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
|
||||||
import { FolderDTO } from 'app/types';
|
import { FolderDTO } from 'app/types';
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ function FormContent({
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<DashboardEditFormSharedFields
|
<ResourceEditFormSharedFields
|
||||||
resourceType="folder"
|
resourceType="folder"
|
||||||
isNew={false}
|
isNew={false}
|
||||||
workflow={workflow}
|
workflow={workflow}
|
||||||
|
|
|
@ -3,13 +3,12 @@ import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
import { AppEvents } from '@grafana/data';
|
import { AppEvents } from '@grafana/data';
|
||||||
import { getAppEvents } from '@grafana/runtime';
|
import { getAppEvents } from '@grafana/runtime';
|
||||||
import { useGetFolderQuery } from 'app/api/clients/folder/v1beta1';
|
|
||||||
import { useCreateRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
import { useCreateRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||||
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
||||||
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
|
|
||||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||||
|
|
||||||
import { FolderDTO } from '../../../types';
|
import { FolderDTO } from '../../../types';
|
||||||
|
import { ProvisionedFolderFormDataResult, useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
|
||||||
|
|
||||||
import { NewProvisionedFolderForm } from './NewProvisionedFolderForm';
|
import { NewProvisionedFolderForm } from './NewProvisionedFolderForm';
|
||||||
|
|
||||||
|
@ -41,9 +40,9 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.mock('app/api/clients/folder/v1beta1', () => {
|
jest.mock('../hooks/useProvisionedFolderFormData', () => {
|
||||||
return {
|
return {
|
||||||
useGetFolderQuery: jest.fn(),
|
useProvisionedFolderFormData: jest.fn(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -53,12 +52,6 @@ jest.mock('app/features/provisioning/hooks/usePullRequestParam', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.mock('app/features/provisioning/hooks/useGetResourceRepositoryView', () => {
|
|
||||||
return {
|
|
||||||
useGetResourceRepositoryView: jest.fn(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.mock('react-router-dom-v5-compat', () => {
|
jest.mock('react-router-dom-v5-compat', () => {
|
||||||
const actual = jest.requireActual('react-router-dom-v5-compat');
|
const actual = jest.requireActual('react-router-dom-v5-compat');
|
||||||
return {
|
return {
|
||||||
|
@ -79,17 +72,15 @@ jest.mock('../../dashboard-scene/saving/provisioned/defaults', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onSubmit: () => void;
|
onDismiss?: () => void;
|
||||||
onCancel: () => void;
|
parentFolder?: FolderDTO;
|
||||||
parentFolder: FolderDTO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(props: Partial<Props> = {}) {
|
function setup(props: Partial<Props> = {}, hookData = mockHookData) {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
|
|
||||||
const defaultProps: Props = {
|
const defaultProps: Props = {
|
||||||
onSubmit: jest.fn(),
|
onDismiss: jest.fn(),
|
||||||
onCancel: jest.fn(),
|
|
||||||
parentFolder: {
|
parentFolder: {
|
||||||
id: 1,
|
id: 1,
|
||||||
uid: 'folder-uid',
|
uid: 'folder-uid',
|
||||||
|
@ -108,6 +99,8 @@ function setup(props: Partial<Props> = {}) {
|
||||||
...props,
|
...props,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(useProvisionedFolderFormData as jest.Mock).mockReturnValue(hookData);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
...render(<NewProvisionedFolderForm {...defaultProps} />),
|
...render(<NewProvisionedFolderForm {...defaultProps} />),
|
||||||
|
@ -123,6 +116,40 @@ const mockRequest = {
|
||||||
data: { resource: { upsert: { metadata: { name: 'new-folder' } } } },
|
data: { resource: { upsert: { metadata: { name: 'new-folder' } } } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockHookData: ProvisionedFolderFormDataResult = {
|
||||||
|
repository: {
|
||||||
|
name: 'test-repo',
|
||||||
|
title: 'Test Repository',
|
||||||
|
type: 'github',
|
||||||
|
workflows: ['write', 'branch'],
|
||||||
|
target: 'folder',
|
||||||
|
},
|
||||||
|
folder: {
|
||||||
|
metadata: {
|
||||||
|
annotations: {
|
||||||
|
'grafana.app/sourcePath': '/dashboards',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
title: '',
|
||||||
|
},
|
||||||
|
status: {},
|
||||||
|
},
|
||||||
|
workflowOptions: [
|
||||||
|
{ label: 'Commit directly', value: 'write' },
|
||||||
|
{ label: 'Create a branch', value: 'branch' },
|
||||||
|
],
|
||||||
|
isGitHub: true,
|
||||||
|
initialValues: {
|
||||||
|
title: '',
|
||||||
|
comment: '',
|
||||||
|
ref: 'folder/test-timestamp',
|
||||||
|
repo: 'test-repo',
|
||||||
|
path: '/dashboards',
|
||||||
|
workflow: 'write',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
describe('NewProvisionedFolderForm', () => {
|
describe('NewProvisionedFolderForm', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
@ -133,39 +160,11 @@ describe('NewProvisionedFolderForm', () => {
|
||||||
};
|
};
|
||||||
(getAppEvents as jest.Mock).mockReturnValue(mockAppEvents);
|
(getAppEvents as jest.Mock).mockReturnValue(mockAppEvents);
|
||||||
|
|
||||||
(useGetResourceRepositoryView as jest.Mock).mockReturnValue({
|
|
||||||
isLoading: false,
|
|
||||||
repository: {
|
|
||||||
name: 'test-repo',
|
|
||||||
title: 'Test Repository',
|
|
||||||
type: 'github',
|
|
||||||
github: {
|
|
||||||
url: 'https://github.com/grafana/grafana',
|
|
||||||
branch: 'main',
|
|
||||||
},
|
|
||||||
workflows: [{ name: 'default', path: 'workflows/default.json' }],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock useGetFolderQuery
|
|
||||||
(useGetFolderQuery as jest.Mock).mockReturnValue({
|
|
||||||
data: {
|
|
||||||
metadata: {
|
|
||||||
annotations: {
|
|
||||||
'source.path': '/dashboards',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
isLoading: false,
|
|
||||||
isError: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock usePullRequestParam
|
// Mock usePullRequestParam
|
||||||
(usePullRequestParam as jest.Mock).mockReturnValue(null);
|
(usePullRequestParam as jest.Mock).mockReturnValue(null);
|
||||||
|
|
||||||
// Mock useCreateRepositoryFilesWithPathMutation
|
// Mock useCreateRepositoryFilesWithPathMutation
|
||||||
const mockCreate = jest.fn();
|
const mockCreate = jest.fn();
|
||||||
|
|
||||||
(useCreateRepositoryFilesWithPathMutation as jest.Mock).mockReturnValue([mockCreate, mockRequest]);
|
(useCreateRepositoryFilesWithPathMutation as jest.Mock).mockReturnValue([mockCreate, mockRequest]);
|
||||||
|
|
||||||
(validationSrv.validateNewFolderName as jest.Mock).mockResolvedValue(true);
|
(validationSrv.validateNewFolderName as jest.Mock).mockResolvedValue(true);
|
||||||
|
@ -182,25 +181,27 @@ describe('NewProvisionedFolderForm', () => {
|
||||||
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show loading state when repository data is loading', () => {
|
it('should return null when initialValues is not available', () => {
|
||||||
(useGetResourceRepositoryView as jest.Mock).mockReturnValue({
|
const { container } = setup(
|
||||||
isLoading: true,
|
{},
|
||||||
});
|
{
|
||||||
|
...mockHookData,
|
||||||
setup();
|
initialValues: undefined,
|
||||||
|
}
|
||||||
expect(screen.getByTestId('Spinner')).toBeInTheDocument();
|
);
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show error when repository is not found', () => {
|
it('should show error when repository is not found', () => {
|
||||||
(useGetResourceRepositoryView as jest.Mock).mockReturnValue({
|
const { container } = setup(
|
||||||
isLoading: false,
|
{},
|
||||||
repository: undefined,
|
{
|
||||||
});
|
...mockHookData,
|
||||||
|
repository: undefined,
|
||||||
setup();
|
initialValues: undefined,
|
||||||
|
}
|
||||||
expect(screen.getByText('Repository not found')).toBeInTheDocument();
|
);
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show branch field when branch workflow is selected', async () => {
|
it('should show branch field when branch workflow is selected', async () => {
|
||||||
|
@ -289,6 +290,7 @@ describe('NewProvisionedFolderForm', () => {
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
ref: undefined, // write workflow uses undefined ref
|
ref: undefined, // write workflow uses undefined ref
|
||||||
name: 'test-repo',
|
name: 'test-repo',
|
||||||
|
path: '/dashboards/new-test-folder/',
|
||||||
message: 'Creating a new test folder',
|
message: 'Creating a new test folder',
|
||||||
body: {
|
body: {
|
||||||
title: 'New Test Folder',
|
title: 'New Test Folder',
|
||||||
|
@ -298,8 +300,8 @@ describe('NewProvisionedFolderForm', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if onSubmit was called
|
// Check if onDismiss was called
|
||||||
expect(props.onSubmit).toHaveBeenCalled();
|
expect(props.onDismiss).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create folder with branch workflow', async () => {
|
it('should create folder with branch workflow', async () => {
|
||||||
|
@ -341,6 +343,7 @@ describe('NewProvisionedFolderForm', () => {
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
ref: 'feature/new-folder',
|
ref: 'feature/new-folder',
|
||||||
name: 'test-repo',
|
name: 'test-repo',
|
||||||
|
path: '/dashboards/branch-folder/',
|
||||||
message: 'Create folder: Branch Folder',
|
message: 'Create folder: Branch Folder',
|
||||||
body: {
|
body: {
|
||||||
title: 'Branch Folder',
|
title: 'Branch Folder',
|
||||||
|
@ -415,33 +418,31 @@ describe('NewProvisionedFolderForm', () => {
|
||||||
expect(screen.getByRole('link')).toHaveTextContent('https://github.com/grafana/grafana/pull/1234');
|
expect(screen.getByRole('link')).toHaveTextContent('https://github.com/grafana/grafana/pull/1234');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call onCancel when cancel button is clicked', async () => {
|
it('should call onDismiss when cancel button is clicked', async () => {
|
||||||
const { user, props } = setup();
|
const { user, props } = setup();
|
||||||
|
|
||||||
// Click cancel button
|
// Click cancel button
|
||||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||||
await user.click(cancelButton);
|
await user.click(cancelButton);
|
||||||
|
|
||||||
// Check if onCancel was called
|
expect(props.onDismiss).toHaveBeenCalled();
|
||||||
expect(props.onCancel).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show read-only alert when repository has no workflows', () => {
|
it('should show read-only alert when repository has no workflows', () => {
|
||||||
// Mock repository with empty workflows array
|
// Mock repository with empty workflows array
|
||||||
(useGetResourceRepositoryView as jest.Mock).mockReturnValue({
|
setup(
|
||||||
repository: {
|
{},
|
||||||
name: 'test-repo',
|
{
|
||||||
title: 'Test Repository',
|
...mockHookData,
|
||||||
type: 'github',
|
repository: {
|
||||||
github: {
|
name: 'test-repo',
|
||||||
url: 'https://github.com/grafana/grafana',
|
title: 'Test Repository',
|
||||||
branch: 'main',
|
type: 'github',
|
||||||
|
workflows: [],
|
||||||
|
target: 'folder',
|
||||||
},
|
},
|
||||||
workflows: [],
|
}
|
||||||
},
|
);
|
||||||
});
|
|
||||||
|
|
||||||
setup();
|
|
||||||
|
|
||||||
// Read-only alert should be visible
|
// Read-only alert should be visible
|
||||||
expect(screen.getByText('This repository is read only')).toBeInTheDocument();
|
expect(screen.getByText('This repository is read only')).toBeInTheDocument();
|
||||||
|
|
|
@ -1,73 +1,52 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { Controller, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||||
|
|
||||||
import { AppEvents } from '@grafana/data';
|
import { AppEvents } from '@grafana/data';
|
||||||
import { Trans, t } from '@grafana/i18n';
|
import { Trans, t } from '@grafana/i18n';
|
||||||
import { getAppEvents } from '@grafana/runtime';
|
import { getAppEvents } from '@grafana/runtime';
|
||||||
import { Alert, Button, Field, Input, RadioButtonGroup, Spinner, Stack, TextArea } from '@grafana/ui';
|
import { Alert, Button, Field, Input, Stack } from '@grafana/ui';
|
||||||
import { useCreateRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
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 { AnnoKeySourcePath, Resource } from 'app/features/apiserver/types';
|
||||||
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/dashboard-scene/saving/provisioned/defaults';
|
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
|
||||||
|
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
|
||||||
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
|
||||||
import { BranchValidationError } from 'app/features/provisioning/Shared/BranchValidationError';
|
|
||||||
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
||||||
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
|
|
||||||
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
|
||||||
import { WorkflowOption } from 'app/features/provisioning/types';
|
|
||||||
import { validateBranchName } from 'app/features/provisioning/utils/git';
|
|
||||||
import { FolderDTO } from 'app/types';
|
import { FolderDTO } from 'app/types';
|
||||||
|
|
||||||
type FormData = {
|
import { useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
|
||||||
ref?: string;
|
interface FormProps extends Props {
|
||||||
path: string;
|
initialValues: BaseProvisionedFormData;
|
||||||
comment?: string;
|
repository?: RepositoryView;
|
||||||
repo: string;
|
workflowOptions: Array<{ label: string; value: string }>;
|
||||||
workflow?: WorkflowOption;
|
folder?: Folder;
|
||||||
title: string;
|
isGitHub: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onSubmit: () => void;
|
|
||||||
onCancel: () => void;
|
|
||||||
parentFolder?: FolderDTO;
|
parentFolder?: FolderDTO;
|
||||||
|
onDismiss?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialFormValues: Partial<FormData> = {
|
function FormContent({ initialValues, repository, workflowOptions, folder, isGitHub, onDismiss }: FormProps) {
|
||||||
title: '',
|
|
||||||
comment: '',
|
|
||||||
ref: `folder/${Date.now()}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: use useProvisionedFolderFormData hook to manage form data and repository state
|
|
||||||
export function NewProvisionedFolderForm({ onSubmit, onCancel, parentFolder }: Props) {
|
|
||||||
const { repository, folder, isLoading } = useGetResourceRepositoryView({ folderName: parentFolder?.uid });
|
|
||||||
const prURL = usePullRequestParam();
|
const prURL = usePullRequestParam();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [create, request] = useCreateRepositoryFilesWithPathMutation();
|
const [create, request] = useCreateRepositoryFilesWithPathMutation();
|
||||||
|
|
||||||
const isGitHub = Boolean(repository?.type === 'github');
|
const methods = useForm<BaseProvisionedFormData>({
|
||||||
|
defaultValues: initialValues,
|
||||||
const {
|
mode: 'onBlur', // Validates when user leaves the field
|
||||||
register,
|
});
|
||||||
handleSubmit,
|
const { handleSubmit, watch, register, formState } = methods;
|
||||||
watch,
|
|
||||||
formState: { errors },
|
|
||||||
control,
|
|
||||||
setValue,
|
|
||||||
} = useForm<FormData>({ defaultValues: { ...initialFormValues, workflow: getDefaultWorkflow(repository) } });
|
|
||||||
|
|
||||||
const [workflow, ref] = watch(['workflow', 'ref']);
|
const [workflow, ref] = watch(['workflow', 'ref']);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setValue('workflow', getDefaultWorkflow(repository));
|
|
||||||
}, [repository, setValue]);
|
|
||||||
|
|
||||||
// TODO: replace with useProvisionedRequestHandler hook
|
// TODO: replace with useProvisionedRequestHandler hook
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const appEvents = getAppEvents();
|
const appEvents = getAppEvents();
|
||||||
if (request.isSuccess && repository) {
|
if (request.isSuccess && repository) {
|
||||||
onSubmit();
|
onDismiss?.();
|
||||||
|
|
||||||
appEvents.publish({
|
appEvents.publish({
|
||||||
type: AppEvents.alertSuccess.name,
|
type: AppEvents.alertSuccess.name,
|
||||||
|
@ -101,20 +80,7 @@ export function NewProvisionedFolderForm({ onSubmit, onCancel, parentFolder }: P
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [request.isSuccess, request.isError, request.error, onSubmit, ref, request.data, workflow, navigate, repository]);
|
}, [request.isSuccess, request.isError, request.error, ref, request.data, workflow, navigate, repository, onDismiss]);
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return <Spinner />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!repository) {
|
|
||||||
return (
|
|
||||||
<Alert
|
|
||||||
title={t('browse-dashboards.new-provisioned-folder-form.title-repository-not-found', 'Repository not found')}
|
|
||||||
severity="error"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const validateFolderName = async (folderName: string) => {
|
const validateFolderName = async (folderName: string) => {
|
||||||
try {
|
try {
|
||||||
|
@ -128,7 +94,7 @@ export function NewProvisionedFolderForm({ onSubmit, onCancel, parentFolder }: P
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const doSave = async ({ ref, title, workflow, comment }: FormData) => {
|
const doSave = async ({ ref, title, workflow, comment }: BaseProvisionedFormData) => {
|
||||||
const repoName = repository?.name;
|
const repoName = repository?.name;
|
||||||
if (!title || !repoName) {
|
if (!title || !repoName) {
|
||||||
return;
|
return;
|
||||||
|
@ -163,107 +129,103 @@ export function NewProvisionedFolderForm({ onSubmit, onCancel, parentFolder }: P
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(doSave)}>
|
<FormProvider {...methods}>
|
||||||
<Stack direction="column" gap={2}>
|
<form onSubmit={handleSubmit(doSave)}>
|
||||||
{!repository?.workflows?.length && (
|
<Stack direction="column" gap={2}>
|
||||||
<Alert
|
{!repository?.workflows?.length && (
|
||||||
title={t(
|
<Alert
|
||||||
'browse-dashboards.new-provisioned-folder-form.title-this-repository-is-read-only',
|
title={t(
|
||||||
'This repository is read only'
|
'browse-dashboards.new-provisioned-folder-form.title-this-repository-is-read-only',
|
||||||
)}
|
'This repository is read only'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Trans i18nKey="browse-dashboards.text-this-repository-is-read-only">
|
||||||
|
If you have direct access to the target, copy the JSON and paste it there.
|
||||||
|
</Trans>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Field
|
||||||
|
noMargin
|
||||||
|
label={t('browse-dashboards.new-provisioned-folder-form.label-folder-name', 'Folder name')}
|
||||||
|
invalid={!!formState.errors.title}
|
||||||
|
error={formState.errors.title?.message}
|
||||||
>
|
>
|
||||||
<Trans i18nKey="browse-dashboards.text-this-repository-is-read-only">
|
<Input
|
||||||
If you have direct access to the target, copy the JSON and paste it there.
|
{...register('title', {
|
||||||
</Trans>
|
required: t('browse-dashboards.new-provisioned-folder-form.error-required', 'Folder name is required'),
|
||||||
</Alert>
|
validate: validateFolderName,
|
||||||
)}
|
})}
|
||||||
|
placeholder={t(
|
||||||
|
'browse-dashboards.new-provisioned-folder-form.folder-name-input-placeholder-enter-folder-name',
|
||||||
|
'Enter folder name'
|
||||||
|
)}
|
||||||
|
id="folder-name-input"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
|
||||||
<Field
|
<ResourceEditFormSharedFields
|
||||||
label={t('browse-dashboards.new-provisioned-folder-form.label-folder-name', 'Folder name')}
|
resourceType="folder"
|
||||||
invalid={!!errors.title}
|
isNew={false}
|
||||||
error={errors.title?.message}
|
workflow={workflow}
|
||||||
>
|
workflowOptions={workflowOptions}
|
||||||
<Input
|
isGitHub={isGitHub}
|
||||||
{...register('title', {
|
hidePath
|
||||||
required: t('browse-dashboards.new-provisioned-folder-form.error-required', 'Folder name is required'),
|
|
||||||
validate: validateFolderName,
|
|
||||||
})}
|
|
||||||
placeholder={t(
|
|
||||||
'browse-dashboards.new-provisioned-folder-form.folder-name-input-placeholder-enter-folder-name',
|
|
||||||
'Enter folder name'
|
|
||||||
)}
|
|
||||||
id="folder-name-input"
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
|
||||||
|
|
||||||
{/* TODO: use DashboardEditFormSharedFields to replace comment and workflow input*/}
|
{prURL && (
|
||||||
<Field label={t('browse-dashboards.new-provisioned-folder-form.label-comment', 'Comment')}>
|
<Alert
|
||||||
<TextArea
|
severity="info"
|
||||||
{...register('comment')}
|
title={t(
|
||||||
placeholder={t(
|
'browse-dashboards.new-provisioned-folder-form.title-pull-request-created',
|
||||||
'browse-dashboards.new-provisioned-folder-form.folder-comment-input-placeholder-describe-changes-optional',
|
'Pull request created'
|
||||||
'Add a note to describe your changes (optional)'
|
)}
|
||||||
)}
|
>
|
||||||
id="folder-comment-input"
|
<Trans i18nKey="browse-dashboards.new-provisioned-folder-form.text-pull-request-created">
|
||||||
rows={5}
|
A pull request has been created with changes to this folder:
|
||||||
/>
|
</Trans>{' '}
|
||||||
</Field>
|
<a href={prURL} target="_blank" rel="noopener noreferrer">
|
||||||
|
{prURL}
|
||||||
|
</a>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
{isGitHub && (
|
<Stack gap={2}>
|
||||||
<>
|
<Button variant="secondary" fill="outline" onClick={onDismiss}>
|
||||||
<Field label={t('browse-dashboards.new-provisioned-folder-form.label-workflow', 'Workflow')}>
|
<Trans i18nKey="browse-dashboards.new-provisioned-folder-form.cancel">Cancel</Trans>
|
||||||
<Controller
|
</Button>
|
||||||
control={control}
|
<Button type="submit" disabled={request.isLoading}>
|
||||||
name="workflow"
|
{request.isLoading
|
||||||
render={({ field: { ref, ...field } }) => (
|
? t('browse-dashboards.new-provisioned-folder-form.button-creating', 'Creating...')
|
||||||
<RadioButtonGroup {...field} options={getWorkflowOptions(repository)} id={'folder-workflow'} />
|
: t('browse-dashboards.new-provisioned-folder-form.button-create', 'Create')}
|
||||||
)}
|
</Button>
|
||||||
/>
|
</Stack>
|
||||||
</Field>
|
|
||||||
{workflow === 'branch' && (
|
|
||||||
<Field
|
|
||||||
label={t('browse-dashboards.new-provisioned-folder-form.label-branch', 'Branch')}
|
|
||||||
description={t(
|
|
||||||
'browse-dashboards.new-provisioned-folder-form.description-branch-name-in-git-hub',
|
|
||||||
'Branch name in GitHub'
|
|
||||||
)}
|
|
||||||
invalid={!!errors?.ref}
|
|
||||||
error={errors.ref ? <BranchValidationError /> : ''}
|
|
||||||
>
|
|
||||||
<Input {...register('ref', { validate: validateBranchName })} id="branch-name-input" />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{prURL && (
|
|
||||||
<Alert
|
|
||||||
severity="info"
|
|
||||||
title={t(
|
|
||||||
'browse-dashboards.new-provisioned-folder-form.title-pull-request-created',
|
|
||||||
'Pull request created'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Trans i18nKey="browse-dashboards.new-provisioned-folder-form.text-pull-request-created">
|
|
||||||
A pull request has been created with changes to this folder:
|
|
||||||
</Trans>{' '}
|
|
||||||
<a href={prURL} target="_blank" rel="noopener noreferrer">
|
|
||||||
{prURL}
|
|
||||||
</a>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Stack gap={2}>
|
|
||||||
<Button variant="secondary" fill="outline" onClick={onCancel}>
|
|
||||||
<Trans i18nKey="browse-dashboards.new-provisioned-folder-form.cancel">Cancel</Trans>
|
|
||||||
</Button>
|
|
||||||
<Button type="submit" disabled={request.isLoading}>
|
|
||||||
{request.isLoading
|
|
||||||
? t('browse-dashboards.new-provisioned-folder-form.button-creating', 'Creating...')
|
|
||||||
: t('browse-dashboards.new-provisioned-folder-form.button-create', 'Create')}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</form>
|
||||||
</form>
|
</FormProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NewProvisionedFolderForm({ parentFolder, onDismiss }: Props) {
|
||||||
|
const { workflowOptions, isGitHub, repository, folder, initialValues } = useProvisionedFolderFormData({
|
||||||
|
folderUid: parentFolder?.uid,
|
||||||
|
action: 'create',
|
||||||
|
title: parentFolder?.title,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!initialValues) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormContent
|
||||||
|
parentFolder={parentFolder}
|
||||||
|
onDismiss={onDismiss}
|
||||||
|
initialValues={initialValues}
|
||||||
|
repository={repository}
|
||||||
|
workflowOptions={workflowOptions}
|
||||||
|
folder={folder}
|
||||||
|
isGitHub={isGitHub}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { FormProvider, useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { ProvisionedDashboardFormData } from '../../saving/shared';
|
import { ProvisionedDashboardFormData } from '../../saving/shared';
|
||||||
|
|
||||||
import { DashboardEditFormSharedFields } from './DashboardEditFormSharedFields';
|
import { ResourceEditFormSharedFields } from './ResourceEditFormSharedFields';
|
||||||
|
|
||||||
// Mock the i18n hook since it's used in the component
|
// Mock the i18n hook since it's used in the component
|
||||||
jest.mock('@grafana/i18n', () => ({
|
jest.mock('@grafana/i18n', () => ({
|
||||||
|
@ -65,13 +65,13 @@ function setup(options: SetupOptions = {}) {
|
||||||
user,
|
user,
|
||||||
...render(
|
...render(
|
||||||
<FormWrapper>
|
<FormWrapper>
|
||||||
<DashboardEditFormSharedFields {...componentProps} resourceType="dashboard" />
|
<ResourceEditFormSharedFields {...componentProps} resourceType="dashboard" />
|
||||||
</FormWrapper>
|
</FormWrapper>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('DashboardEditFormSharedFields', () => {
|
describe('ResourceEditFormSharedFields', () => {
|
||||||
describe('Basic Rendering', () => {
|
describe('Basic Rendering', () => {
|
||||||
it('should render path and comment fields by default', () => {
|
it('should render path and comment fields by default', () => {
|
||||||
setup();
|
setup();
|
||||||
|
@ -186,7 +186,7 @@ describe('DashboardEditFormSharedFields', () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<DashboardEditFormSharedFields
|
<ResourceEditFormSharedFields
|
||||||
workflowOptions={[
|
workflowOptions={[
|
||||||
{ label: 'Write directly', value: 'write' },
|
{ label: 'Write directly', value: 'write' },
|
||||||
{ label: 'Create branch', value: 'branch' },
|
{ label: 'Create branch', value: 'branch' },
|
|
@ -14,10 +14,11 @@ interface DashboardEditFormSharedFieldsProps {
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
workflow?: WorkflowOption;
|
workflow?: WorkflowOption;
|
||||||
isGitHub?: boolean;
|
isGitHub?: boolean;
|
||||||
|
hidePath?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DashboardEditFormSharedFields = memo<DashboardEditFormSharedFieldsProps>(
|
export const ResourceEditFormSharedFields = memo<DashboardEditFormSharedFieldsProps>(
|
||||||
({ readOnly = false, workflow, workflowOptions, isGitHub, isNew, resourceType }) => {
|
({ readOnly = false, workflow, workflowOptions, isGitHub, isNew, resourceType, hidePath = false }) => {
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
register,
|
register,
|
||||||
|
@ -32,16 +33,18 @@ export const DashboardEditFormSharedFields = memo<DashboardEditFormSharedFieldsP
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Path */}
|
{/* Path */}
|
||||||
<Field
|
{!hidePath && (
|
||||||
noMargin
|
<Field
|
||||||
label={t('provisioned-resource-form.save-or-delete-resource-shared-fields.label-path', 'Path')}
|
noMargin
|
||||||
description={t(
|
label={t('provisioned-resource-form.save-or-delete-resource-shared-fields.label-path', 'Path')}
|
||||||
'provisioned-resource-form.save-or-delete-resource-shared-fields.description-inside-repository',
|
description={t(
|
||||||
pathText
|
'provisioned-resource-form.save-or-delete-resource-shared-fields.description-inside-repository',
|
||||||
)}
|
pathText
|
||||||
>
|
)}
|
||||||
<Input id="dashboard-path" type="text" {...register('path')} readOnly={!isNew} />
|
>
|
||||||
</Field>
|
<Input id="dashboard-path" type="text" {...register('path')} readOnly={!isNew} />
|
||||||
|
</Field>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Comment */}
|
{/* Comment */}
|
||||||
<Field
|
<Field
|
|
@ -14,7 +14,7 @@ import { validationSrv } from 'app/features/manage-dashboards/services/Validatio
|
||||||
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
||||||
import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile';
|
import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile';
|
||||||
|
|
||||||
import { DashboardEditFormSharedFields } from '../../components/Provisioned/DashboardEditFormSharedFields';
|
import { ResourceEditFormSharedFields } from '../../components/Provisioned/ResourceEditFormSharedFields';
|
||||||
import { getDashboardUrl } from '../../utils/getDashboardUrl';
|
import { getDashboardUrl } from '../../utils/getDashboardUrl';
|
||||||
import { useProvisionedRequestHandler } from '../../utils/useProvisionedRequestHandler';
|
import { useProvisionedRequestHandler } from '../../utils/useProvisionedRequestHandler';
|
||||||
import { SaveDashboardFormCommonOptions } from '../SaveDashboardForm';
|
import { SaveDashboardFormCommonOptions } from '../SaveDashboardForm';
|
||||||
|
@ -214,7 +214,7 @@ export function SaveProvisionedDashboardForm({
|
||||||
|
|
||||||
{!isNew && !readOnly && <SaveDashboardFormCommonOptions drawer={drawer} changeInfo={changeInfo} />}
|
{!isNew && !readOnly && <SaveDashboardFormCommonOptions drawer={drawer} changeInfo={changeInfo} />}
|
||||||
|
|
||||||
<DashboardEditFormSharedFields
|
<ResourceEditFormSharedFields
|
||||||
resourceType="dashboard"
|
resourceType="dashboard"
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
workflow={workflow}
|
workflow={workflow}
|
||||||
|
|
|
@ -34,8 +34,8 @@ jest.mock('react-router-dom-v5-compat', () => ({
|
||||||
const mockNavigate = jest.fn();
|
const mockNavigate = jest.fn();
|
||||||
|
|
||||||
// Mock shared form components
|
// Mock shared form components
|
||||||
jest.mock('../components/Provisioned/DashboardEditFormSharedFields', () => ({
|
jest.mock('../components/Provisioned/ResourceEditFormSharedFields', () => ({
|
||||||
DashboardEditFormSharedFields: ({ disabled }: { disabled: boolean }) => (
|
ResourceEditFormSharedFields: ({ disabled }: { disabled: boolean }) => (
|
||||||
<textarea data-testid="shared-fields" disabled={disabled} />
|
<textarea data-testid="shared-fields" disabled={disabled} />
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { Alert, Button, Drawer, Stack } from '@grafana/ui';
|
||||||
import { useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
import { useDeleteRepositoryFilesWithPathMutation } from 'app/api/clients/provisioning/v0alpha1';
|
||||||
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
|
||||||
|
|
||||||
import { DashboardEditFormSharedFields } from '../components/Provisioned/DashboardEditFormSharedFields';
|
import { ResourceEditFormSharedFields } from '../components/Provisioned/ResourceEditFormSharedFields';
|
||||||
import { ProvisionedDashboardFormData } from '../saving/shared';
|
import { ProvisionedDashboardFormData } from '../saving/shared';
|
||||||
import { DashboardScene } from '../scene/DashboardScene';
|
import { DashboardScene } from '../scene/DashboardScene';
|
||||||
import { useProvisionedRequestHandler } from '../utils/useProvisionedRequestHandler';
|
import { useProvisionedRequestHandler } from '../utils/useProvisionedRequestHandler';
|
||||||
|
@ -121,7 +121,7 @@ export function DeleteProvisionedDashboardForm({
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<DashboardEditFormSharedFields
|
<ResourceEditFormSharedFields
|
||||||
resourceType="dashboard"
|
resourceType="dashboard"
|
||||||
isNew={isNew}
|
isNew={isNew}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
|
|
|
@ -3473,18 +3473,12 @@
|
||||||
"button-create": "Create",
|
"button-create": "Create",
|
||||||
"button-creating": "Creating...",
|
"button-creating": "Creating...",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"description-branch-name-in-git-hub": "Branch name in GitHub",
|
|
||||||
"error-invalid-folder-name": "Invalid folder name",
|
"error-invalid-folder-name": "Invalid folder name",
|
||||||
"error-required": "Folder name is required",
|
"error-required": "Folder name is required",
|
||||||
"folder-comment-input-placeholder-describe-changes-optional": "Add a note to describe your changes (optional)",
|
|
||||||
"folder-name-input-placeholder-enter-folder-name": "Enter folder name",
|
"folder-name-input-placeholder-enter-folder-name": "Enter folder name",
|
||||||
"label-branch": "Branch",
|
|
||||||
"label-comment": "Comment",
|
|
||||||
"label-folder-name": "Folder name",
|
"label-folder-name": "Folder name",
|
||||||
"label-workflow": "Workflow",
|
|
||||||
"text-pull-request-created": "A pull request has been created with changes to this folder:",
|
"text-pull-request-created": "A pull request has been created with changes to this folder:",
|
||||||
"title-pull-request-created": "Pull request created",
|
"title-pull-request-created": "Pull request created",
|
||||||
"title-repository-not-found": "Repository not found",
|
|
||||||
"title-this-repository-is-read-only": "This repository is read only"
|
"title-this-repository-is-read-only": "This repository is read only"
|
||||||
},
|
},
|
||||||
"no-results": {
|
"no-results": {
|
||||||
|
|
Loading…
Reference in New Issue