diff --git a/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_pods.vue b/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_pods.vue
index 4a75d73823f84beb128975a6e4da8830cd7f0c65..8afac231f11375ce1d68c6ed7a8b35211016f8e4 100644
--- a/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_pods.vue
+++ b/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_pods.vue
@@ -30,15 +30,19 @@ export default {
           namespace: this.namespace,
         };
       },
-
       update(data) {
         return (
           data?.k8sPods?.map((pod) => {
             return {
-              name: pod.metadata?.name,
-              namespace: pod.metadata?.namespace,
+              name: pod.metadata.name,
+              namespace: pod.metadata.namespace,
               status: pod.status.phase,
-              age: getAge(pod.metadata?.creationTimestamp),
+              age: getAge(pod.metadata.creationTimestamp),
+              labels: pod.metadata.labels,
+              annotations: pod.metadata.annotations,
+              kind: s__('KubernetesDashboard|Pod'),
+              spec: pod.spec,
+              fullStatus: pod.status,
             };
           }) || []
         );
@@ -106,6 +110,12 @@ export default {
 
       return filteredPods.length;
     },
+    onItemSelect(item) {
+      this.$emit('show-resource-details', item);
+    },
+    onRemoveSelection() {
+      this.$emit('remove-selection');
+    },
   },
   i18n: {
     podsTitle: s__('Environment|Pods'),
@@ -128,8 +138,9 @@ export default {
         v-if="k8sPods"
         :items="k8sPods"
         :page-size="$options.PAGE_SIZE"
-        :row-clickable="false"
         class="gl-mt-8"
+        @select-item="onItemSelect"
+        @remove-selection="onRemoveSelection"
       />
     </template>
   </gl-tab>
diff --git a/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_services.vue b/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_services.vue
index 7cc14ae50ec024f5992a28debf07c552d5581424..09022b59ce53ae19f78c723f3f0bebac836f5865 100644
--- a/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_services.vue
+++ b/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_services.vue
@@ -50,13 +50,18 @@ export default {
 
       return this.k8sServices.map((service) => {
         return {
-          name: service?.metadata?.name,
-          namespace: service?.metadata?.namespace,
-          type: service?.spec?.type,
-          clusterIP: service?.spec?.clusterIP,
-          externalIP: service?.spec?.externalIP,
-          ports: generateServicePortsString(service?.spec?.ports),
-          age: getAge(service?.metadata?.creationTimestamp),
+          name: service.metadata.name,
+          namespace: service.metadata.namespace,
+          type: service.spec.type,
+          clusterIP: service.spec.clusterIP || '-',
+          externalIP: service.spec.externalIP || '-',
+          ports: generateServicePortsString(service.spec.ports),
+          age: getAge(service.metadata.creationTimestamp),
+          labels: service.metadata.labels,
+          annotations: service.metadata.annotations,
+          kind: s__('KubernetesDashboard|Service'),
+          spec: service.spec,
+          fullStatus: service.status,
         };
       });
     },
@@ -64,6 +69,14 @@ export default {
       return this.$apollo.queries.k8sServices.loading;
     },
   },
+  methods: {
+    onItemSelect(item) {
+      this.$emit('show-resource-details', item);
+    },
+    onRemoveSelection() {
+      this.$emit('remove-selection');
+    },
+  },
   i18n: {
     servicesTitle: s__('Environment|Services'),
   },
@@ -85,8 +98,9 @@ export default {
       :items="servicesItems"
       :fields="$options.SERVICES_TABLE_FIELDS"
       :page-size="$options.SERVICES_LIMIT_PER_PAGE"
-      :row-clickable="false"
       class="gl-mt-5"
+      @select-item="onItemSelect"
+      @remove-selection="onRemoveSelection"
     />
   </gl-tab>
 </template>
diff --git a/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_tabs.vue b/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_tabs.vue
index 45037647eb947fab68d542bd57626fdfdc4df1c5..ae534c6edd3432409d04fe7624938a37470ca5d8 100644
--- a/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_tabs.vue
+++ b/app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_tabs.vue
@@ -1,6 +1,9 @@
 <script>
-import { GlTabs } from '@gitlab/ui';
+import { GlTabs, GlDrawer } from '@gitlab/ui';
+import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
+import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
 import { k8sResourceType } from '~/environments/graphql/resolvers/kubernetes/constants';
+import WorkloadDetails from '~/kubernetes_dashboard/components/workload_details.vue';
 import KubernetesPods from './kubernetes_pods.vue';
 import KubernetesServices from './kubernetes_services.vue';
 
@@ -11,6 +14,8 @@ export default {
     GlTabs,
     KubernetesPods,
     KubernetesServices,
+    GlDrawer,
+    WorkloadDetails,
   },
 
   props: {
@@ -30,29 +35,68 @@ export default {
   data() {
     return {
       activeTabIndex: tabs.indexOf(this.value),
+      selectedItem: {},
+      showDetailsDrawer: false,
     };
   },
+  computed: {
+    drawerHeaderHeight() {
+      return getContentWrapperHeight();
+    },
+  },
   watch: {
     activeTabIndex(newValue) {
       this.$emit('input', tabs[newValue]);
     },
   },
+  methods: {
+    showResourceDetails(item) {
+      this.selectedItem = item;
+      this.showDetailsDrawer = true;
+    },
+    closeDetailsDrawer() {
+      this.showDetailsDrawer = false;
+    },
+  },
+  DRAWER_Z_INDEX,
 };
 </script>
 <template>
-  <gl-tabs v-model="activeTabIndex">
-    <kubernetes-pods
-      :namespace="namespace"
-      :configuration="configuration"
-      @loading="$emit('loading', $event)"
-      @update-failed-state="$emit('update-failed-state', $event)"
-      @cluster-error="$emit('cluster-error', $event)"
-    />
+  <div>
+    <gl-tabs v-model="activeTabIndex">
+      <kubernetes-pods
+        :namespace="namespace"
+        :configuration="configuration"
+        @loading="$emit('loading', $event)"
+        @update-failed-state="$emit('update-failed-state', $event)"
+        @cluster-error="$emit('cluster-error', $event)"
+        @show-resource-details="showResourceDetails"
+        @remove-selection="closeDetailsDrawer"
+      />
+
+      <kubernetes-services
+        :namespace="namespace"
+        :configuration="configuration"
+        @cluster-error="$emit('cluster-error', $event)"
+        @show-resource-details="showResourceDetails"
+        @remove-selection="closeDetailsDrawer"
+      />
+    </gl-tabs>
 
-    <kubernetes-services
-      :namespace="namespace"
-      :configuration="configuration"
-      @cluster-error="$emit('cluster-error', $event)"
-    />
-  </gl-tabs>
+    <gl-drawer
+      :open="showDetailsDrawer"
+      :header-height="drawerHeaderHeight"
+      :z-index="$options.DRAWER_Z_INDEX"
+      @close="closeDetailsDrawer"
+    >
+      <template #title>
+        <h4 class="gl-font-weight-bold gl-font-size-h2 gl-m-0 gl-word-break-word">
+          {{ selectedItem.name }}
+        </h4>
+      </template>
+      <template #default>
+        <workload-details :item="selectedItem" />
+      </template>
+    </gl-drawer>
+  </div>
 </template>
diff --git a/app/assets/javascripts/environments/graphql/client.js b/app/assets/javascripts/environments/graphql/client.js
index d0b2af3229add3a9e795b8cca20492135ba488e8..0f47cbff15988413147123a1c7108250f72b3a02 100644
--- a/app/assets/javascripts/environments/graphql/client.js
+++ b/app/assets/javascripts/environments/graphql/client.js
@@ -21,6 +21,15 @@ export const apolloProvider = (endpoint) => {
   });
   const { cache } = defaultClient;
 
+  const k8sMetadata = {
+    name: null,
+    namespace: null,
+    creationTimestamp: null,
+    labels: null,
+    annotations: null,
+  };
+  const k8sData = { nodes: { metadata: k8sMetadata, status: {}, spec: {} } };
+
   cache.writeQuery({
     query: environmentApp,
     data: {
@@ -91,16 +100,7 @@ export const apolloProvider = (endpoint) => {
   });
   cache.writeQuery({
     query: k8sPodsQuery,
-    data: {
-      metadata: {
-        name: null,
-        namespace: null,
-        creationTimestamp: null,
-      },
-      status: {
-        phase: null,
-      },
-    },
+    data: k8sData,
   });
   cache.writeQuery({
     query: k8sConnectionStatusQuery,
@@ -117,19 +117,7 @@ export const apolloProvider = (endpoint) => {
   });
   cache.writeQuery({
     query: k8sServicesQuery,
-    data: {
-      metadata: {
-        name: null,
-        namespace: null,
-        creationTimestamp: null,
-      },
-      spec: {
-        type: null,
-        clusterIP: null,
-        externalIP: null,
-        ports: [],
-      },
-    },
+    data: k8sData,
   });
   cache.writeQuery({
     query: k8sNamespacesQuery,
diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql
index 1a2a23925b177cfdc6c579f03726f5dc3237d61c..711fa424f52a65ab3bdd7f24e2de555496ca17e8 100644
--- a/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql
@@ -1,12 +1,7 @@
+#import "~/kubernetes_dashboard/graphql/queries/workload_item.fragment.graphql"
+
 query getK8sPods($configuration: LocalConfiguration, $namespace: String) {
   k8sPods(configuration: $configuration, namespace: $namespace) @client {
-    metadata {
-      name
-      namespace
-      creationTimestamp
-    }
-    status {
-      phase
-    }
+    ...WorkloadItem
   }
 }
diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql
index 8fc4a54b08b19d2af11c4e3436f6138d93466143..4c084899028355d14577cf7ee9c7abc521ec7e15 100644
--- a/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql
@@ -1,15 +1,7 @@
+#import "~/kubernetes_dashboard/graphql/queries/workload_item.fragment.graphql"
+
 query getK8sServices($configuration: LocalConfiguration, $namespace: String) {
   k8sServices(configuration: $configuration, namespace: $namespace) @client {
-    metadata {
-      name
-      namespace
-      creationTimestamp
-    }
-    spec {
-      type
-      clusterIP
-      externalIP
-      ports
-    }
+    ...WorkloadItem
   }
 }
diff --git a/app/assets/javascripts/environments/graphql/resolvers/kubernetes/index.js b/app/assets/javascripts/environments/graphql/resolvers/kubernetes/index.js
index 9c8781c921c3160c74411c109b99e1cb3c85c4de..a31ca497d9c41e7c53d66e4aa80722c0e1614a11 100644
--- a/app/assets/javascripts/environments/graphql/resolvers/kubernetes/index.js
+++ b/app/assets/javascripts/environments/graphql/resolvers/kubernetes/index.js
@@ -1,93 +1,21 @@
-import {
-  CoreV1Api,
-  Configuration,
-  WatchApi,
-  EVENT_DATA,
-  EVENT_TIMEOUT,
-  EVENT_ERROR,
-} from '@gitlab/cluster-client';
+import { CoreV1Api, Configuration } from '@gitlab/cluster-client';
 import {
   getK8sPods,
   watchWorkloadItems,
   handleClusterError,
   buildWatchPath,
+  mapWorkloadItem,
 } from '~/kubernetes_dashboard/graphql/helpers/resolver_helpers';
 import { humanizeClusterErrors } from '../../../helpers/k8s_integration_helper';
 import k8sPodsQuery from '../../queries/k8s_pods.query.graphql';
 import k8sServicesQuery from '../../queries/k8s_services.query.graphql';
-import { updateConnectionStatus } from './k8s_connection_status';
-import { connectionStatus, k8sResourceType } from './constants';
-
-const mapServicesItems = (items) => {
-  return items.map((item) => {
-    const { type, clusterIP, externalIP, ports } = item.spec;
-    return {
-      metadata: item.metadata,
-      spec: {
-        type,
-        clusterIP: clusterIP || '-',
-        externalIP: externalIP || '-',
-        ports,
-      },
-    };
-  });
-};
+import { k8sResourceType } from './constants';
 
 const watchServices = ({ configuration, namespace, client }) => {
-  const path = buildWatchPath({ resource: 'services', namespace });
-  const config = new Configuration(configuration);
-  const watcherApi = new WatchApi(config);
-
-  updateConnectionStatus(client, {
-    configuration,
-    namespace,
-    resourceType: k8sResourceType.k8sServices,
-    status: connectionStatus.connecting,
-  });
-
-  watcherApi
-    .subscribeToStream(path, { watch: true })
-    .then((watcher) => {
-      let result = [];
-
-      watcher.on(EVENT_DATA, (data) => {
-        result = mapServicesItems(data);
-
-        client.writeQuery({
-          query: k8sServicesQuery,
-          variables: { configuration, namespace },
-          data: { k8sServices: result },
-        });
-
-        updateConnectionStatus(client, {
-          configuration,
-          namespace,
-          resourceType: k8sResourceType.k8sServices,
-          status: connectionStatus.connected,
-        });
-      });
-
-      watcher.on(EVENT_TIMEOUT, () => {
-        updateConnectionStatus(client, {
-          configuration,
-          namespace,
-          resourceType: k8sResourceType.k8sServices,
-          status: connectionStatus.disconnected,
-        });
-      });
-
-      watcher.on(EVENT_ERROR, () => {
-        updateConnectionStatus(client, {
-          configuration,
-          namespace,
-          resourceType: k8sResourceType.k8sServices,
-          status: connectionStatus.disconnected,
-        });
-      });
-    })
-    .catch((err) => {
-      handleClusterError(err);
-    });
+  const query = k8sServicesQuery;
+  const watchPath = buildWatchPath({ resource: 'services', namespace });
+  const queryField = k8sResourceType.k8sServices;
+  watchWorkloadItems({ client, query, configuration, namespace, watchPath, queryField });
 };
 
 const watchPods = ({ configuration, namespace, client }) => {
@@ -119,9 +47,7 @@ export const kubernetesQueries = {
   k8sPods(_, { configuration, namespace }, { client }) {
     const query = k8sPodsQuery;
     const enableWatch = gon.features?.k8sWatchApi;
-    // TODO: Remove mapping function once the drawer with the pods details is added under the Kubernetes overview section
-    const mapPodItem = (item) => item;
-    return getK8sPods({ client, query, configuration, namespace, enableWatch, mapFn: mapPodItem });
+    return getK8sPods({ client, query, configuration, namespace, enableWatch });
   },
   k8sServices(_, { configuration, namespace }, { client }) {
     const coreV1Api = new CoreV1Api(new Configuration(configuration));
@@ -137,7 +63,7 @@ export const kubernetesQueries = {
           watchServices({ configuration, namespace, client });
         }
 
-        return mapServicesItems(items);
+        return items.map(mapWorkloadItem);
       })
       .catch(async (err) => {
         try {
diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql
index d8b05102b53409674e084f96c1fc4c4e25e90d14..034b269e5cbc5e8919e770bcda8ff9da46b7c5f5 100644
--- a/app/assets/javascripts/environments/graphql/typedefs.graphql
+++ b/app/assets/javascripts/environments/graphql/typedefs.graphql
@@ -1,4 +1,5 @@
 #import "~/graphql_shared/client/page_info.typedefs.graphql"
+#import "~/kubernetes_dashboard/graphql/typedefs.graphql"
 
 type LocalEnvironment {
   id: Int!
@@ -57,43 +58,11 @@ type LocalErrors {
   errors: [String!]!
 }
 
-type k8sPodStatus {
-  phase: String
-}
-
-type k8sPodMetadata {
-  name: String
-  namespace: String
-  creationTimestamp: String
-}
-
-type LocalK8sPods {
-  status: k8sPodStatus
-  metadata: k8sPodMetadata
-}
-
 input LocalConfiguration {
   basePath: String
   baseOptions: JSON
 }
 
-type k8sServiceMetadata {
-  name: String
-  namespace: String
-  creationTimestamp: String
-}
-
-type k8sServiceSpec {
-  type: String
-  clusterIP: String
-  externalIP: String
-  ports: JSON
-}
-
-type LocalK8sServices {
-  metadata: k8sServiceMetadata
-  spec: k8sServiceSpec
-}
 type k8sNamespaceMetadata {
   name: String
 }
@@ -123,8 +92,8 @@ extend type Query {
   environmentToStop: LocalEnvironment
   isEnvironmentStopping(environment: LocalEnvironmentInput): Boolean
   isLastDeployment(environment: LocalEnvironmentInput): Boolean
-  k8sPods(configuration: LocalConfiguration, namespace: String): [LocalK8sPods]
-  k8sServices(configuration: LocalConfiguration): [LocalK8sServices]
+  k8sPods(configuration: LocalConfiguration, namespace: String): [LocalWorkloadItem]
+  k8sServices(configuration: LocalConfiguration, namespace: String): [LocalWorkloadItem]
   k8sConnection(configuration: LocalConfiguration): K8sResources
   fluxKustomizationStatus(
     configuration: LocalConfiguration
diff --git a/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue b/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue
index bd081f32a01546d050be39e540babdc307c6da30..99ba982b2a5eeee0e884fb3ff60bae38f182a7d6 100644
--- a/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue
+++ b/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue
@@ -70,7 +70,13 @@ export default {
   </gl-alert>
   <div v-else>
     <workload-stats :stats="stats" />
-    <workload-table :items="items" :fields="fields" class="gl-mt-8" @select-item="onItemSelect" />
+    <workload-table
+      :items="items"
+      :fields="fields"
+      class="gl-mt-8"
+      @select-item="onItemSelect"
+      @remove-selection="closeDetailsDrawer"
+    />
 
     <gl-drawer
       :open="showDetailsDrawer"
diff --git a/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue b/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue
index 297ceff31d1d65d8d1aa37a58f9771230ab7061f..6533feafa53a8544544260af21e4f9e34bf8b24d 100644
--- a/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue
+++ b/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue
@@ -28,11 +28,6 @@ export default {
       default: PAGE_SIZE,
       required: false,
     },
-    rowClickable: {
-      type: Boolean,
-      default: true,
-      required: false,
-    },
   },
   data() {
     return {
@@ -48,9 +43,6 @@ export default {
         };
       });
     },
-    tableRowClass() {
-      return this.rowClickable ? 'gl-hover-cursor-pointer' : '';
-    },
   },
   methods: {
     selectItem(item) {
@@ -58,6 +50,8 @@ export default {
 
       if (selectedItem) {
         this.$emit('select-item', selectedItem);
+      } else {
+        this.$emit('remove-selection');
       }
     },
   },
@@ -76,10 +70,8 @@ export default {
       :per-page="pageSize"
       :current-page="currentPage"
       :empty-text="$options.i18n.emptyText"
-      :tbody-tr-class="tableRowClass"
-      :hover="rowClickable"
-      :selectable="rowClickable"
-      :no-select-on-click="!rowClickable"
+      hover
+      selectable
       select-mode="single"
       selected-variant="primary"
       show-empty
diff --git a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_pods_spec.js b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_pods_spec.js
index dbbf8e7f5d4c98fc4e9100a02c163409b0924baa..b7a77701d10d71fce13d7283b354a53ad070a4e9 100644
--- a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_pods_spec.js
+++ b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_pods_spec.js
@@ -8,8 +8,12 @@ import KubernetesPods from '~/environments/environment_details/components/kubern
 import WorkloadStats from '~/kubernetes_dashboard/components/workload_stats.vue';
 import WorkloadTable from '~/kubernetes_dashboard/components/workload_table.vue';
 import { useFakeDate } from 'helpers/fake_date';
-import { mockKasTunnelUrl } from '../../../mock_data';
-import { k8sPodsMock, k8sPodsStatsData, k8sPodsTableData } from '../../../graphql/mock_data';
+import { mockKasTunnelUrl } from 'jest/environments/mock_data';
+import {
+  k8sPodsMock,
+  mockPodStats,
+  mockPodsTableItems,
+} from 'jest/kubernetes_dashboard/graphql/mock_data';
 
 Vue.use(VueApollo);
 
@@ -85,14 +89,14 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_po
       createWrapper();
       await waitForPromises();
 
-      expect(findWorkloadStats().props('stats')).toEqual(k8sPodsStatsData);
+      expect(findWorkloadStats().props('stats')).toEqual(mockPodStats);
     });
 
     it('renders workload table with the correct data', async () => {
       createWrapper();
       await waitForPromises();
 
-      expect(findWorkloadTable().props('items')).toMatchObject(k8sPodsTableData);
+      expect(findWorkloadTable().props('items')).toMatchObject(mockPodsTableItems);
     });
 
     it('emits a update-failed-state event for each pod', async () => {
@@ -107,6 +111,26 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_po
         [{ pods: true }],
       ]);
     });
+
+    it('emits show-resource-details event on item select', async () => {
+      createWrapper();
+      await waitForPromises();
+
+      expect(wrapper.emitted('show-resource-details')).toBeUndefined();
+
+      findWorkloadTable().vm.$emit('select-item', mockPodsTableItems[0]);
+      expect(wrapper.emitted('show-resource-details')).toEqual([[mockPodsTableItems[0]]]);
+    });
+
+    it('emits remove-selection event when receives it from the WorkloadTable component', async () => {
+      createWrapper();
+      await waitForPromises();
+
+      expect(wrapper.emitted('remove-selection')).toBeUndefined();
+
+      findWorkloadTable().vm.$emit('remove-selection');
+      expect(wrapper.emitted('remove-selection')).toHaveLength(1);
+    });
   });
 
   describe('when gets an error from the cluster_client API', () => {
diff --git a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_services_spec.js b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_services_spec.js
index 9ab97dc4bbec39cf7051c00e4d5318f1a3381357..29eefd92cd8ad068236df770c128353d4a3a089e 100644
--- a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_services_spec.js
+++ b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_services_spec.js
@@ -9,8 +9,11 @@ import KubernetesServices from '~/environments/environment_details/components/ku
 import WorkloadTable from '~/kubernetes_dashboard/components/workload_table.vue';
 import { SERVICES_LIMIT_PER_PAGE } from '~/environments/constants';
 import { SERVICES_TABLE_FIELDS } from '~/kubernetes_dashboard/constants';
-import { mockKasTunnelUrl } from '../../../mock_data';
-import { k8sServicesMock } from '../../../graphql/mock_data';
+import { mockKasTunnelUrl } from 'jest/environments/mock_data';
+import {
+  k8sServicesMock,
+  mockServicesTableItems,
+} from 'jest/kubernetes_dashboard/graphql/mock_data';
 
 Vue.use(VueApollo);
 
@@ -64,7 +67,7 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_se
   });
 
   describe('when gets services data', () => {
-    useFakeDate(2020, 6, 6);
+    useFakeDate(2023, 10, 23, 10, 10);
 
     it('hides the loading icon when the list of services loaded', async () => {
       createWrapper();
@@ -79,26 +82,27 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_se
 
       expect(findWorkloadTable().props('pageSize')).toBe(SERVICES_LIMIT_PER_PAGE);
       expect(findWorkloadTable().props('fields')).toBe(SERVICES_TABLE_FIELDS);
-      expect(findWorkloadTable().props('items')).toMatchObject([
-        {
-          name: 'my-first-service',
-          namespace: 'default',
-          type: 'ClusterIP',
-          clusterIP: '10.96.0.1',
-          externalIP: '-',
-          ports: '443/TCP',
-          age: '0s',
-        },
-        {
-          name: 'my-second-service',
-          namespace: 'default',
-          type: 'NodePort',
-          clusterIP: '10.105.219.238',
-          externalIP: '-',
-          ports: '80:31989/TCP, 443:32679/TCP',
-          age: '2d',
-        },
-      ]);
+      expect(findWorkloadTable().props('items')).toMatchObject(mockServicesTableItems);
+    });
+
+    it('emits show-resource-details event on item select', async () => {
+      createWrapper();
+      await waitForPromises();
+
+      expect(wrapper.emitted('show-resource-details')).toBeUndefined();
+
+      findWorkloadTable().vm.$emit('select-item', mockServicesTableItems[0]);
+      expect(wrapper.emitted('show-resource-details')).toEqual([[mockServicesTableItems[0]]]);
+    });
+
+    it('emits remove-selection event when receives it from the WorkloadTable component', async () => {
+      createWrapper();
+      await waitForPromises();
+
+      expect(wrapper.emitted('remove-selection')).toBeUndefined();
+
+      findWorkloadTable().vm.$emit('remove-selection');
+      expect(wrapper.emitted('remove-selection')).toHaveLength(1);
     });
 
     it('emits an error message when gets an error from the cluster_client API', async () => {
diff --git a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_tabs_spec.js b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_tabs_spec.js
index 9ff6e66200b4ee492ea8664fbc0d708f2dc746f0..db74e48321f1868dd36ebcea80ede83cb4dea3d8 100644
--- a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_tabs_spec.js
+++ b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_tabs_spec.js
@@ -1,11 +1,13 @@
 import { nextTick } from 'vue';
 import { shallowMount } from '@vue/test-utils';
-import { GlTabs } from '@gitlab/ui';
+import { GlTabs, GlDrawer } from '@gitlab/ui';
 import KubernetesTabs from '~/environments/environment_details/components/kubernetes/kubernetes_tabs.vue';
 import KubernetesPods from '~/environments/environment_details/components/kubernetes/kubernetes_pods.vue';
 import KubernetesServices from '~/environments/environment_details/components/kubernetes/kubernetes_services.vue';
+import WorkloadDetails from '~/kubernetes_dashboard/components/workload_details.vue';
 import { k8sResourceType } from '~/environments/graphql/resolvers/kubernetes/constants';
-import { mockKasTunnelUrl } from '../../../mock_data';
+import { mockKasTunnelUrl } from 'jest/environments/mock_data';
+import { mockPodsTableItems } from 'jest/kubernetes_dashboard/graphql/mock_data';
 
 describe('~/environments/environment_details/components/kubernetes/kubernetes_tabs.vue', () => {
   let wrapper;
@@ -20,10 +22,13 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_ta
   const findTabs = () => wrapper.findComponent(GlTabs);
   const findKubernetesPods = () => wrapper.findComponent(KubernetesPods);
   const findKubernetesServices = () => wrapper.findComponent(KubernetesServices);
+  const findDrawer = () => wrapper.findComponent(GlDrawer);
+  const findWorkloadDetails = () => wrapper.findComponent(WorkloadDetails);
 
   const createWrapper = (activeTab = k8sResourceType.k8sPods) => {
     wrapper = shallowMount(KubernetesTabs, {
       propsData: { configuration, namespace, value: activeTab },
+      stubs: { GlDrawer },
     });
   };
 
@@ -100,4 +105,46 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_ta
       expect(wrapper.emitted('cluster-error')).toEqual([[errorMessage]]);
     });
   });
+
+  describe('resource details drawer', () => {
+    beforeEach(() => {
+      createWrapper();
+    });
+
+    it('is closed by default', () => {
+      expect(findDrawer().props('open')).toBe(false);
+    });
+
+    describe('when receives show-resource-details event', () => {
+      beforeEach(() => {
+        findKubernetesPods().vm.$emit('show-resource-details', mockPodsTableItems[0]);
+      });
+
+      it('opens the drawer', () => {
+        expect(findDrawer().props('open')).toBe(true);
+      });
+
+      it('provides the resource details to the drawer', () => {
+        expect(findWorkloadDetails().props('item')).toEqual(mockPodsTableItems[0]);
+      });
+
+      it('renders a title with the selected item name', () => {
+        expect(findDrawer().text()).toContain(mockPodsTableItems[0].name);
+      });
+
+      it('is closed when clicked on a cross button', async () => {
+        expect(findDrawer().props('open')).toBe(true);
+
+        await findDrawer().vm.$emit('close');
+        expect(findDrawer().props('open')).toBe(false);
+      });
+
+      it('is closed on remove-selection event', async () => {
+        expect(findDrawer().props('open')).toBe(true);
+
+        await findKubernetesPods().vm.$emit('remove-selection');
+        expect(findDrawer().props('open')).toBe(false);
+      });
+    });
+  });
 });
diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js
index a6aaea5899f6c2fb91e20738148743ba98af2bcf..4754d1c15a82e9f03a8ed99c8d5b188fcb108beb 100644
--- a/spec/frontend/environments/graphql/mock_data.js
+++ b/spec/frontend/environments/graphql/mock_data.js
@@ -810,140 +810,6 @@ export const agent = {
 
 export const kubernetesNamespace = 'agent-namespace';
 
-const runningPod = {
-  metadata: { name: 'pod-1', namespace: 'default', creationTimestamp: '2023-07-31T11:50:17Z' },
-  status: { phase: 'Running' },
-};
-const pendingPod = {
-  metadata: {
-    name: 'pod-2',
-    namespace: 'new-namespace',
-    creationTimestamp: '2023-11-21T11:50:59Z',
-  },
-  status: { phase: 'Pending' },
-};
-const succeededPod = {
-  metadata: { name: 'pod-3', namespace: 'default', creationTimestamp: '2023-07-31T11:50:17Z' },
-  status: { phase: 'Succeeded' },
-};
-const failedPod = {
-  metadata: { name: 'pod-4', namespace: 'default', creationTimestamp: '2023-11-21T11:50:59Z' },
-  status: { phase: 'Failed' },
-};
-
-export const k8sPodsMock = [runningPod, runningPod, pendingPod, succeededPod, failedPod, failedPod];
-
-export const k8sPodsStatsData = [
-  {
-    value: 2,
-    title: 'Running',
-  },
-  {
-    value: 1,
-    title: 'Pending',
-  },
-  {
-    value: 1,
-    title: 'Succeeded',
-  },
-  {
-    value: 2,
-    title: 'Failed',
-  },
-];
-
-export const k8sPodsTableData = [
-  {
-    name: 'pod-1',
-    namespace: 'default',
-    status: 'Running',
-    age: '114d',
-  },
-  {
-    name: 'pod-1',
-    namespace: 'default',
-    status: 'Running',
-    age: '114d',
-  },
-  {
-    name: 'pod-2',
-    namespace: 'new-namespace',
-    status: 'Pending',
-    age: '1d',
-  },
-  {
-    name: 'pod-3',
-    namespace: 'default',
-    status: 'Succeeded',
-    age: '114d',
-  },
-  {
-    name: 'pod-4',
-    namespace: 'default',
-    status: 'Failed',
-    age: '1d',
-  },
-  {
-    name: 'pod-4',
-    namespace: 'default',
-    status: 'Failed',
-    age: '1d',
-  },
-];
-
-export const k8sServicesMock = [
-  {
-    metadata: {
-      name: 'my-first-service',
-      namespace: 'default',
-      creationTimestamp: new Date(),
-    },
-    spec: {
-      ports: [
-        {
-          name: 'https',
-          protocol: 'TCP',
-          port: 443,
-          targetPort: 8443,
-        },
-      ],
-      clusterIP: '10.96.0.1',
-      externalIP: '-',
-      type: 'ClusterIP',
-    },
-  },
-  {
-    metadata: {
-      name: 'my-second-service',
-      namespace: 'default',
-      creationTimestamp: '2020-07-03T14:06:04Z',
-    },
-    spec: {
-      ports: [
-        {
-          name: 'http',
-          protocol: 'TCP',
-          appProtocol: 'http',
-          port: 80,
-          targetPort: 'http',
-          nodePort: 31989,
-        },
-        {
-          name: 'https',
-          protocol: 'TCP',
-          appProtocol: 'https',
-          port: 443,
-          targetPort: 'https',
-          nodePort: 32679,
-        },
-      ],
-      clusterIP: '10.105.219.238',
-      externalIP: '-',
-      type: 'NodePort',
-    },
-  },
-];
-
 export const k8sNamespacesMock = [
   { metadata: { name: 'default' } },
   { metadata: { name: 'agent' } },
diff --git a/spec/frontend/environments/graphql/resolvers/kubernetes_spec.js b/spec/frontend/environments/graphql/resolvers/kubernetes_spec.js
index 933825255d284a81ba8fb0e60a7cd1290edda1a3..18dcc0a1e66808a64a0219a44478c9860f24a72b 100644
--- a/spec/frontend/environments/graphql/resolvers/kubernetes_spec.js
+++ b/spec/frontend/environments/graphql/resolvers/kubernetes_spec.js
@@ -16,7 +16,8 @@ import {
   connectionStatus,
   k8sResourceType,
 } from '~/environments/graphql/resolvers/kubernetes/constants';
-import { k8sPodsMock, k8sServicesMock, k8sNamespacesMock } from '../mock_data';
+import { k8sPodsMock, k8sServicesMock } from 'jest/kubernetes_dashboard/graphql/mock_data';
+import { k8sNamespacesMock } from '../mock_data';
 
 jest.mock('~/environments/graphql/resolvers/kubernetes/k8s_connection_status');
 
@@ -342,7 +343,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
         });
       });
 
-      it('should not watch pods from the cluster_client library when the services data is not present', async () => {
+      it('should not watch services from the cluster_client library when the services data is not present', async () => {
         jest.spyOn(CoreV1Api.prototype, 'listCoreV1NamespacedService').mockImplementation(
           jest.fn().mockImplementation(() => {
             return Promise.resolve({
diff --git a/spec/frontend/kubernetes_dashboard/components/workload_layout_spec.js b/spec/frontend/kubernetes_dashboard/components/workload_layout_spec.js
index 1dc5bd4f1650191e4ef33764101f78e0728a0fb4..0f32bc3a2914931ea5174c7cac0fde9ad0f4c791 100644
--- a/spec/frontend/kubernetes_dashboard/components/workload_layout_spec.js
+++ b/spec/frontend/kubernetes_dashboard/components/workload_layout_spec.js
@@ -127,6 +127,14 @@ describe('Workload layout component', () => {
         expect(findDrawer().props('open')).toBe(false);
       });
 
+      it('is closed on remove-selection event', async () => {
+        await findWorkloadTable().vm.$emit('select-item', mockPodsTableItems[0]);
+        expect(findDrawer().props('open')).toBe(true);
+
+        await findWorkloadTable().vm.$emit('remove-selection');
+        expect(findDrawer().props('open')).toBe(false);
+      });
+
       it('renders a title with the selected item name', async () => {
         await findWorkloadTable().vm.$emit('select-item', mockPodsTableItems[0]);
         expect(findDrawer().text()).toContain(mockPodsTableItems[0].name);
diff --git a/spec/frontend/kubernetes_dashboard/components/workload_table_spec.js b/spec/frontend/kubernetes_dashboard/components/workload_table_spec.js
index 1ddafeb0525de89231f2189dbfb2a54f373cf6e7..79fdfe666baa2144b4828807c76ad9c8027d68d6 100644
--- a/spec/frontend/kubernetes_dashboard/components/workload_table_spec.js
+++ b/spec/frontend/kubernetes_dashboard/components/workload_table_spec.js
@@ -159,10 +159,12 @@ describe('Workload table component', () => {
     });
   });
 
-  describe('on row click', () => {
-    it('emits an event on row click', () => {
+  describe('row selection', () => {
+    beforeEach(() => {
       createWrapper({ items: mockPodsTableItems });
+    });
 
+    it('emits row-selected event on row click', () => {
       mockPodsTableItems.forEach((data, index) => {
         findTable().vm.$emit('row-selected', [data]);
 
@@ -170,68 +172,12 @@ describe('Workload table component', () => {
       });
     });
 
-    describe('be default', () => {
-      it('row has hover styles by default', () => {
-        createWrapper({ items: mockPodsTableItems });
-
-        expect(findRow(0).attributes('class')).toContain('gl-hover-cursor-pointer');
-      });
-
-      it('table has hover state enabled by default', () => {
-        createWrapper({ items: mockPodsTableItems }, true);
-
-        expect(findTable().props('hover')).toBe(true);
-      });
-
-      it('table is selectable by default', () => {
-        createWrapper({ items: mockPodsTableItems }, true);
-
-        expect(findTable().props('selectable')).toBe(true);
-      });
-
-      it('table row is selectable on click', () => {
-        createWrapper({ items: mockPodsTableItems }, true);
-
-        expect(findTable().props('noSelectOnClick')).toBe(false);
-      });
-    });
-
-    describe('when rowClickable is false', () => {
-      it('row has no hover styles', () => {
-        createWrapper({ items: mockPodsTableItems, rowClickable: false });
-
-        expect(findRow(0).attributes('class')).not.toContain('gl-hover-cursor-pointer');
-      });
-
-      it('table has no hover state enabled', () => {
-        createWrapper({ items: mockPodsTableItems, rowClickable: false }, true);
-
-        expect(findTable().props('hover')).toBe(false);
-      });
-
-      it('table is not selectable', () => {
-        createWrapper({ items: mockPodsTableItems, rowClickable: false }, true);
-
-        expect(findTable().props('selectable')).toBe(false);
-      });
-
-      it('table row is not selectable on click', () => {
-        createWrapper({ items: mockPodsTableItems, rowClickable: false }, true);
-
-        expect(findTable().props('noSelectOnClick')).toBe(true);
-      });
-    });
-
-    it('row has hover styles by default', () => {
-      createWrapper({ items: mockPodsTableItems });
-
-      expect(findRow(0).attributes('class')).toContain('gl-hover-cursor-pointer');
-    });
-
-    it('row has no hover styles if rowClickable is false', () => {
-      createWrapper({ items: mockPodsTableItems, rowClickable: false });
+    it('emits remove-selection event on the second click on the same item', () => {
+      findTable().vm.$emit('row-selected', [mockPodsTableItems[0]]);
+      expect(wrapper.emitted('select-item')).toEqual([[mockPodsTableItems[0]]]);
 
-      expect(findRow(0).attributes('class')).not.toContain('gl-hover-cursor-pointer');
+      findTable().vm.$emit('row-selected', mockPodsTableItems[0]);
+      expect(wrapper.emitted('remove-selection')).toHaveLength(1);
     });
   });
 });