diff --git a/src/stores/resources.ts b/src/stores/resources.ts
index 6e648731ee92345303510a247e845a6eae20c9ad..986b90f7f7f0020be830ac6b0de110f1453c9204 100644
--- a/src/stores/resources.ts
+++ b/src/stores/resources.ts
@@ -5,9 +5,12 @@ import type {
   ResourceVersionIn,
   ResourceVersionOut,
 } from "@/client/resource";
-import { ResourceService, ResourceVersionService } from "@/client/resource";
+import {
+  ResourceService,
+  ResourceVersionService,
+  Status,
+} from "@/client/resource";
 import { useAuthStore } from "@/stores/users";
-import { Status } from "@/client/resource";
 import { useNameStore } from "@/stores/names";
 
 export const useResourceStore = defineStore({
@@ -16,9 +19,11 @@ export const useResourceStore = defineStore({
     ({
       resourceMapping: {},
       ownResourceMapping: {},
+      reviewableResourceMapping: {},
     }) as {
       resourceMapping: Record<string, ResourceOut>;
       ownResourceMapping: Record<string, ResourceOut>;
+      reviewableResourceMapping: Record<string, ResourceOut>;
     },
   getters: {
     resources(): ResourceOut[] {
@@ -27,20 +32,45 @@ export const useResourceStore = defineStore({
     ownResources(): ResourceOut[] {
       return Object.values(this.ownResourceMapping);
     },
+    reviewableResources(): ResourceOut[] {
+      return Object.values(this.reviewableResourceMapping);
+    },
   },
   actions: {
-    __addNameToMapping(key: string, value: string) {
-      const nameStore = useNameStore();
-      nameStore.addNameToMapping(key, value);
-    },
     fetchResources(
       maintainerId?: string,
       versionStatus?: Status[],
     ): Promise<ResourceOut[]> {
       return ResourceService.resourceListResources(maintainerId, versionStatus);
     },
+    fetchReviewableResources(onFinally?: () => void): Promise<ResourceOut[]> {
+      if (Object.keys(this.reviewableResourceMapping).length > 0) {
+        onFinally?.();
+      }
+      return this.fetchResources(undefined, [
+        Status.SYNC_REQUESTED,
+        Status.SYNCHRONIZING,
+      ])
+        .then((resources) => {
+          const newMapping: Record<string, ResourceOut> = {};
+          const nameStore = useNameStore();
+          for (const resource of resources) {
+            newMapping[resource.resource_id] = resource;
+            nameStore.addNameToMapping(resource.resource_id, resource.name);
+            for (const version of resource.versions) {
+              nameStore.addNameToMapping(
+                version.resource_version_id,
+                version.release,
+              );
+            }
+          }
+          this.reviewableResourceMapping = newMapping;
+          return resources;
+        })
+        .finally(onFinally);
+    },
     fetchPublicResources(onFinally?: () => void): Promise<ResourceOut[]> {
-      if (Object.keys(this.resourceMapping).length > 0) {
+      if (this.resources.length > 0) {
         onFinally?.();
       }
       return this.fetchResources()
@@ -89,7 +119,7 @@ export const useResourceStore = defineStore({
     },
     fetchOwnResources(onFinally?: () => void): Promise<ResourceOut[]> {
       const authStore = useAuthStore();
-      if (Object.keys(this.ownResourceMapping).length > 0) {
+      if (this.ownResources.length > 0) {
         onFinally?.();
       }
       return this.fetchResources(authStore.currentUID, Object.values(Status))
@@ -182,5 +212,36 @@ export const useResourceStore = defineStore({
         return versionOut;
       });
     },
+    syncResource(
+      resourceVersion: ResourceVersionOut,
+    ): Promise<ResourceVersionOut> {
+      return ResourceVersionService.resourceVersionResourceVersionSync(
+        resourceVersion.resource_id,
+        resourceVersion.resource_version_id,
+      ).then((changedVersion) => {
+        if (
+          this.reviewableResourceMapping[changedVersion.resource_id] ==
+          undefined
+        ) {
+          return changedVersion;
+        }
+        const versionIndex = this.reviewableResourceMapping[
+          changedVersion.resource_id
+        ].versions.findIndex(
+          (version) =>
+            version.resource_version_id == changedVersion.resource_version_id,
+        );
+        if (versionIndex > -1) {
+          this.reviewableResourceMapping[changedVersion.resource_id].versions[
+            versionIndex
+          ] = changedVersion;
+        } else {
+          this.reviewableResourceMapping[
+            changedVersion.resource_id
+          ].versions.push(changedVersion);
+        }
+        return changedVersion;
+      });
+    },
   },
 });
diff --git a/src/views/resources/ReviewResourceView.vue b/src/views/resources/ReviewResourceView.vue
index cb91f85b499515f2557f4d92bda43bce8cb03730..b1477b56a4c2dfdeca38b2ea188089348b0c6206 100644
--- a/src/views/resources/ReviewResourceView.vue
+++ b/src/views/resources/ReviewResourceView.vue
@@ -1,49 +1,88 @@
 <script setup lang="ts">
 import { useResourceStore } from "@/stores/resources";
 import { computed, onMounted, reactive } from "vue";
-import { type ResourceOut, Status } from "@/client/resource";
+import { type ResourceVersionOut, Status } from "@/client/resource";
 import CopyToClipboardIcon from "@/components/CopyToClipboardIcon.vue";
+import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
+import { Tooltip } from "bootstrap";
 
 const resourceRepository = useResourceStore();
+let refreshTimeout: NodeJS.Timeout | undefined = undefined;
 
 const resourceState = reactive<{
-  reviewableResources: ResourceOut[];
+  sendingRequest: boolean;
   loading: boolean;
 }>({
-  reviewableResources: [],
+  sendingRequest: false,
   loading: true,
 });
 
 const countItems = computed<number>(() =>
-  resourceState.reviewableResources.reduce(
+  resourceRepository.reviewableResources.reduce(
     (previousValue, currentValue) =>
       previousValue + currentValue.versions.length,
     0,
   ),
 );
 
+function fetchResources() {
+  resourceRepository.fetchReviewableResources().finally(() => {
+    resourceState.loading = false;
+  });
+}
+
+function clickRefreshResources() {
+  clearTimeout(refreshTimeout);
+  refreshTimeout = setTimeout(() => {
+    fetchResources();
+  }, 500);
+}
+
+function syncResource(resourceVersion: ResourceVersionOut) {
+  resourceState.sendingRequest = true;
+  resourceRepository.syncResource(resourceVersion).finally(() => {
+    resourceState.sendingRequest = false;
+  });
+}
+
 onMounted(() => {
-  resourceRepository
-    .fetchResources(undefined, [Status.SYNC_REQUESTED, Status.SYNCHRONIZING])
-    .then((resources) => {
-      resourceState.reviewableResources = resources;
-    })
-    .finally(() => {
-      resourceState.loading = false;
-    });
+  fetchResources();
+  new Tooltip("#refreshReviewableResourcesButton");
 });
 </script>
 
 <template>
-  <div class="row m-2 border-bottom mb-4">
-    <h2 class="mb-2">Resource Requests</h2>
+  <div
+    class="row m-2 border-bottom mb-4 justify-content-between align-items-center"
+  >
+    <h2 class="w-fit">Resource Requests</h2>
+    <span
+      class="w-fit"
+      tabindex="0"
+      data-bs-title="Refresh Reviewable Resources"
+      data-bs-toggle="tooltip"
+      id="refreshReviewableResourcesButton"
+    >
+      <button
+        type="button"
+        class="btn btn-primary btn-light me-2 shadow-sm border w-fit"
+        :disabled="resourceState.loading"
+        @click="clickRefreshResources"
+      >
+        <font-awesome-icon icon="fa-solid fa-arrow-rotate-right" />
+        <span class="visually-hidden">Refresh Reviewable Resources</span>
+      </button>
+    </span>
   </div>
   <div v-if="resourceState.loading" class="text-center mt-5">
     <div class="spinner-border" style="width: 3rem; height: 3rem" role="status">
       <span class="visually-hidden">Loading...</span>
     </div>
   </div>
-  <table class="table caption-top table-striped table-hover align-middle">
+  <table
+    class="table caption-top table-striped table-hover align-middle"
+    v-else-if="resourceRepository.reviewableResources.length > 0"
+  >
     <caption>
       Display
       {{
@@ -62,7 +101,7 @@ onMounted(() => {
     </thead>
     <tbody>
       <template
-        v-for="resource in resourceState.reviewableResources"
+        v-for="resource in resourceRepository.reviewableResources"
         :key="resource.resource_id"
       >
         <tr
@@ -91,10 +130,17 @@ onMounted(() => {
               v-if="version.status === Status.SYNC_REQUESTED"
               class="btn-group"
             >
-              <button type="button" class="btn btn-success btn-sm">
+              <button
+                type="button"
+                class="btn btn-success btn-sm"
+                :disabled="resourceState.sendingRequest"
+                @click="syncResource(version)"
+              >
                 Synchronize
               </button>
-              <button type="button" class="btn btn-danger btn-sm">Deny</button>
+              <button type="button" class="btn btn-danger btn-sm" disabled>
+                Deny
+              </button>
             </div>
             <div
               v-else-if="version.status === Status.SYNCHRONIZING"
@@ -115,6 +161,9 @@ onMounted(() => {
       </template>
     </tbody>
   </table>
+  <div v-else>
+    <p>Hello</p>
+  </div>
 </template>
 
 <style scoped></style>