diff --git a/ee/query-service/app/api/dashboard.go b/ee/query-service/app/api/dashboard.go
index 0628ae18f6..51fe6c2ded 100644
--- a/ee/query-service/app/api/dashboard.go
+++ b/ee/query-service/app/api/dashboard.go
@@ -1,7 +1,9 @@
package api
import (
+ "errors"
"net/http"
+ "strings"
"github.com/gorilla/mux"
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
@@ -29,6 +31,10 @@ func (ah *APIHandler) lockUnlockDashboard(w http.ResponseWriter, r *http.Request
// Get the dashboard UUID from the request
uuid := mux.Vars(r)["uuid"]
+ if strings.HasPrefix(uuid,"integration") {
+ RespondError(w, &model.ApiError{Typ: model.ErrorForbidden, Err: errors.New("dashboards created by integrations cannot be unlocked")}, "You are not authorized to lock/unlock this dashboard")
+ return
+ }
dashboard, err := dashboards.GetDashboard(r.Context(), uuid)
if err != nil {
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, err.Error())
diff --git a/frontend/src/container/NewDashboard/DashboardDescription/__tests__/DashboardDescription.test.tsx b/frontend/src/container/NewDashboard/DashboardDescription/__tests__/DashboardDescription.test.tsx
new file mode 100644
index 0000000000..8e302042a3
--- /dev/null
+++ b/frontend/src/container/NewDashboard/DashboardDescription/__tests__/DashboardDescription.test.tsx
@@ -0,0 +1,100 @@
+import { getNonIntegrationDashboardById } from 'mocks-server/__mockdata__/dashboards';
+import { server } from 'mocks-server/server';
+import { rest } from 'msw';
+import { DashboardProvider } from 'providers/Dashboard/Dashboard';
+import { MemoryRouter, useLocation } from 'react-router-dom';
+import { fireEvent, render, screen, waitFor } from 'tests/test-utils';
+
+import DashboardDescription from '..';
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useLocation: jest.fn(),
+ useRouteMatch: jest.fn().mockReturnValue({
+ params: {
+ dashboardId: 4,
+ },
+ }),
+}));
+
+jest.mock(
+ 'container/TopNav/DateTimeSelectionV2/index.tsx',
+ () =>
+ function MockDateTimeSelection(): JSX.Element {
+ return
@@ -334,13 +345,22 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
{(isAuthor || role === USER_ROLES.ADMIN) && (
- }
- onClick={handleLockDashboardToggle}
+
- {isDashboardLocked ? 'Unlock Dashboard' : 'Lock Dashboard'}
-
+ }
+ disabled={selectedDashboard?.created_by === 'integration'}
+ onClick={handleLockDashboardToggle}
+ data-testid="lock-unlock-dashboard"
+ >
+ {isDashboardLocked ? 'Unlock Dashboard' : 'Lock Dashboard'}
+
+
)}
{!isDashboardLocked && editDashboard && (
diff --git a/frontend/src/mocks-server/__mockdata__/dashboards.ts b/frontend/src/mocks-server/__mockdata__/dashboards.ts
index 4f1a6b78e7..40d9cb48d9 100644
--- a/frontend/src/mocks-server/__mockdata__/dashboards.ts
+++ b/frontend/src/mocks-server/__mockdata__/dashboards.ts
@@ -1,3 +1,4 @@
+/* eslint-disable sonarjs/no-duplicate-string */
export const dashboardSuccessResponse = {
status: 'success',
data: [
@@ -48,3 +49,53 @@ export const dashboardEmptyState = {
status: 'sucsess',
data: [],
};
+
+export const getDashboardById = {
+ status: 'success',
+ data: {
+ id: 1,
+ uuid: '1',
+ created_at: '2022-11-16T13:29:47.064874419Z',
+ created_by: 'integration',
+ updated_at: '2024-05-21T06:41:30.546630961Z',
+ updated_by: 'thor@avengers.io',
+ isLocked: true,
+ data: {
+ collapsableRowsMigrated: true,
+ description: '',
+ name: '',
+ panelMap: {},
+ tags: ['linux'],
+ title: 'thor',
+ uploadedGrafana: false,
+ uuid: '',
+ version: '',
+ variables: {},
+ },
+ },
+};
+
+export const getNonIntegrationDashboardById = {
+ status: 'success',
+ data: {
+ id: 1,
+ uuid: '1',
+ created_at: '2022-11-16T13:29:47.064874419Z',
+ created_by: 'thor',
+ updated_at: '2024-05-21T06:41:30.546630961Z',
+ updated_by: 'thor@avengers.io',
+ isLocked: true,
+ data: {
+ collapsableRowsMigrated: true,
+ description: '',
+ name: '',
+ panelMap: {},
+ tags: ['linux'],
+ title: 'thor',
+ uploadedGrafana: false,
+ uuid: '',
+ version: '',
+ variables: {},
+ },
+ },
+};
diff --git a/frontend/src/mocks-server/handlers.ts b/frontend/src/mocks-server/handlers.ts
index f96309380a..d46aa52420 100644
--- a/frontend/src/mocks-server/handlers.ts
+++ b/frontend/src/mocks-server/handlers.ts
@@ -1,7 +1,10 @@
import { rest } from 'msw';
import { billingSuccessResponse } from './__mockdata__/billing';
-import { dashboardSuccessResponse } from './__mockdata__/dashboards';
+import {
+ dashboardSuccessResponse,
+ getDashboardById,
+} from './__mockdata__/dashboards';
import { explorerView } from './__mockdata__/explorer_views';
import { inviteUser } from './__mockdata__/invite_user';
import { licensesSuccessResponse } from './__mockdata__/licenses';
@@ -141,6 +144,10 @@ export const handlers = [
res(ctx.status(200), ctx.json(dashboardSuccessResponse)),
),
+ rest.get('http://localhost/api/v1/dashboards/4', (_, res, ctx) =>
+ res(ctx.status(200), ctx.json(getDashboardById)),
+ ),
+
rest.get('http://localhost/api/v1/invite', (_, res, ctx) =>
res(ctx.status(200), ctx.json(inviteUser)),
),
diff --git a/frontend/src/tests/test-utils.tsx b/frontend/src/tests/test-utils.tsx
index ff2d3c7e51..4eced41eff 100644
--- a/frontend/src/tests/test-utils.tsx
+++ b/frontend/src/tests/test-utils.tsx
@@ -42,6 +42,7 @@ const mockStored = (role?: string): any =>
accessJwt: '',
refreshJwt: '',
},
+ isLoggedIn: true,
org: [
{
createdAt: 0,