From 21cfe68a2ac2304d9c034b9d247a61e9861af666 Mon Sep 17 00:00:00 2001
From: alex <alex@alexloehr.net>
Date: Fri, 28 Nov 2025 15:23:17 +0000
Subject: [PATCH] GS-2333

---
 lib/db.js                      |    4 
 vue/src/components/Header.vue  |    1 
 package-lock.json              |  240 ++++------------------------------
 vue/src/router.js              |    6 
 package.json                   |    2 
 vue/src/pages/CourseAdmins.vue |  119 +++++++++++++++++
 vue/src/lib/api.js             |   12 +
 vue/src/assets/styles.styl     |    3 
 8 files changed, 175 insertions(+), 212 deletions(-)

diff --git a/lib/db.js b/lib/db.js
index dd4dc76..6d95cc1 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -691,6 +691,7 @@
                 INNER JOIN ${database}.object_data od2 ON od2.obj_id = rf.rol_id
        WHERE od.\`type\` = "crs"
          AND od2.title LIKE "%admin%"
+         AND t.deleted is NULL
    `
    const [results] = await pool.query(q)
    return results
@@ -706,7 +707,8 @@
                       INNER JOIN ${database}.rbac_fa rf ON rf.parent = t.ref_id
                       INNER JOIN ${database}.object_data od2 ON od2.obj_id = rf.rol_id
              WHERE od.\`type\` = "crs"
-               AND od2.title LIKE "%admin%") adminRoles
+               AND od2.title LIKE "%admin%"
+               AND t.deleted is NULL) adminRoles
        WHERE adminRoles.rol_id NOT IN (SELECT ru2.rol_id
                                        FROM ${database}.rbac_ua ru2)
    `
diff --git a/package-lock.json b/package-lock.json
index bd99ae7..62cbdf3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,7 +28,7 @@
             "stylus": "^0.64.0",
             "vue": "^3.5.13",
             "vue-router": "^4.5.1",
-            "yargs": "^15.4.1"
+            "yargs": "^17.7.2"
          },
          "devDependencies": {
             "@vitejs/plugin-vue": "^5.2.3",
@@ -2281,15 +2281,6 @@
             "url": "https://github.com/sponsors/sindresorhus"
          }
       },
-      "node_modules/camelcase": {
-         "version": "5.3.1",
-         "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-         "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-         "license": "MIT",
-         "engines": {
-            "node": ">=6"
-         }
-      },
       "node_modules/caniuse-lite": {
          "version": "1.0.30001720",
          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
@@ -2361,14 +2352,17 @@
          }
       },
       "node_modules/cliui": {
-         "version": "6.0.0",
-         "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-         "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+         "version": "8.0.1",
+         "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+         "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
          "license": "ISC",
          "dependencies": {
             "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^6.2.0"
+            "strip-ansi": "^6.0.1",
+            "wrap-ansi": "^7.0.0"
+         },
+         "engines": {
+            "node": ">=12"
          }
       },
       "node_modules/color-convert": {
@@ -2495,15 +2489,6 @@
             "supports-color": {
                "optional": true
             }
-         }
-      },
-      "node_modules/decamelize": {
-         "version": "1.2.0",
-         "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-         "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
-         "license": "MIT",
-         "engines": {
-            "node": ">=0.10.0"
          }
       },
       "node_modules/deeks": {
@@ -3006,19 +2991,6 @@
          },
          "engines": {
             "node": ">=20"
-         }
-      },
-      "node_modules/find-up": {
-         "version": "4.1.0",
-         "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-         "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-         "license": "MIT",
-         "dependencies": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-         },
-         "engines": {
-            "node": ">=8"
          }
       },
       "node_modules/flat": {
@@ -3659,18 +3631,6 @@
          ],
          "license": "MIT"
       },
-      "node_modules/locate-path": {
-         "version": "5.0.0",
-         "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-         "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-         "license": "MIT",
-         "dependencies": {
-            "p-locate": "^4.1.0"
-         },
-         "engines": {
-            "node": ">=8"
-         }
-      },
       "node_modules/lodash": {
          "version": "4.17.21",
          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -3895,20 +3855,6 @@
             "url": "https://paulmillr.com/funding/"
          }
       },
-      "node_modules/mocha/node_modules/cliui": {
-         "version": "8.0.1",
-         "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
-         "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
-         "license": "ISC",
-         "dependencies": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.1",
-            "wrap-ansi": "^7.0.0"
-         },
-         "engines": {
-            "node": ">=12"
-         }
-      },
       "node_modules/mocha/node_modules/find-up": {
          "version": "5.0.0",
          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -4079,50 +4025,6 @@
             "url": "https://github.com/chalk/supports-color?sponsor=1"
          }
       },
-      "node_modules/mocha/node_modules/wrap-ansi": {
-         "version": "7.0.0",
-         "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-         "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-         "license": "MIT",
-         "dependencies": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-         },
-         "engines": {
-            "node": ">=10"
-         },
-         "funding": {
-            "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-         }
-      },
-      "node_modules/mocha/node_modules/yargs": {
-         "version": "17.7.2",
-         "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
-         "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
-         "license": "MIT",
-         "dependencies": {
-            "cliui": "^8.0.1",
-            "escalade": "^3.1.1",
-            "get-caller-file": "^2.0.5",
-            "require-directory": "^2.1.1",
-            "string-width": "^4.2.3",
-            "y18n": "^5.0.5",
-            "yargs-parser": "^21.1.1"
-         },
-         "engines": {
-            "node": ">=12"
-         }
-      },
-      "node_modules/mocha/node_modules/yargs-parser": {
-         "version": "21.1.1",
-         "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-         "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-         "license": "ISC",
-         "engines": {
-            "node": ">=12"
-         }
-      },
       "node_modules/mrmime": {
          "version": "2.0.1",
          "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
@@ -4213,23 +4115,6 @@
             "string-width": "^4.2.0",
             "strip-ansi": "^6.0.0",
             "wrap-ansi": "^7.0.0"
-         }
-      },
-      "node_modules/nconf/node_modules/wrap-ansi": {
-         "version": "7.0.0",
-         "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-         "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-         "license": "MIT",
-         "dependencies": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-         },
-         "engines": {
-            "node": ">=10"
-         },
-         "funding": {
-            "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
          }
       },
       "node_modules/nconf/node_modules/yargs": {
@@ -4368,42 +4253,6 @@
          },
          "funding": {
             "url": "https://github.com/sponsors/sindresorhus"
-         }
-      },
-      "node_modules/p-limit": {
-         "version": "2.3.0",
-         "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-         "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-         "license": "MIT",
-         "dependencies": {
-            "p-try": "^2.0.0"
-         },
-         "engines": {
-            "node": ">=6"
-         },
-         "funding": {
-            "url": "https://github.com/sponsors/sindresorhus"
-         }
-      },
-      "node_modules/p-locate": {
-         "version": "4.1.0",
-         "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-         "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-         "license": "MIT",
-         "dependencies": {
-            "p-limit": "^2.2.0"
-         },
-         "engines": {
-            "node": ">=8"
-         }
-      },
-      "node_modules/p-try": {
-         "version": "2.2.0",
-         "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-         "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-         "license": "MIT",
-         "engines": {
-            "node": ">=6"
          }
       },
       "node_modules/package-json-from-dist": {
@@ -4771,12 +4620,6 @@
             "node": ">=0.10.0"
          }
       },
-      "node_modules/require-main-filename": {
-         "version": "2.0.0",
-         "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-         "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-         "license": "ISC"
-      },
       "node_modules/ret": {
          "version": "0.5.0",
          "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz",
@@ -4962,12 +4805,6 @@
          "dependencies": {
             "randombytes": "^2.1.0"
          }
-      },
-      "node_modules/set-blocking": {
-         "version": "2.0.0",
-         "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-         "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
-         "license": "ISC"
       },
       "node_modules/set-cookie-parser": {
          "version": "2.7.1",
@@ -5778,12 +5615,6 @@
             "node": ">= 8"
          }
       },
-      "node_modules/which-module": {
-         "version": "2.0.1",
-         "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
-         "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
-         "license": "ISC"
-      },
       "node_modules/workerpool": {
          "version": "9.3.2",
          "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz",
@@ -5791,9 +5622,9 @@
          "license": "Apache-2.0"
       },
       "node_modules/wrap-ansi": {
-         "version": "6.2.0",
-         "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-         "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+         "version": "7.0.0",
+         "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+         "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
          "license": "MIT",
          "dependencies": {
             "ansi-styles": "^4.0.0",
@@ -5801,7 +5632,10 @@
             "strip-ansi": "^6.0.0"
          },
          "engines": {
-            "node": ">=8"
+            "node": ">=10"
+         },
+         "funding": {
+            "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
          }
       },
       "node_modules/wrap-ansi-cjs": {
@@ -5854,38 +5688,30 @@
          "license": "ISC"
       },
       "node_modules/yargs": {
-         "version": "15.4.1",
-         "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
-         "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+         "version": "17.7.2",
+         "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+         "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
          "license": "MIT",
          "dependencies": {
-            "cliui": "^6.0.0",
-            "decamelize": "^1.2.0",
-            "find-up": "^4.1.0",
-            "get-caller-file": "^2.0.1",
+            "cliui": "^8.0.1",
+            "escalade": "^3.1.1",
+            "get-caller-file": "^2.0.5",
             "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^4.2.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^18.1.2"
+            "string-width": "^4.2.3",
+            "y18n": "^5.0.5",
+            "yargs-parser": "^21.1.1"
          },
          "engines": {
-            "node": ">=8"
+            "node": ">=12"
          }
       },
       "node_modules/yargs-parser": {
-         "version": "18.1.3",
-         "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-         "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+         "version": "21.1.1",
+         "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+         "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
          "license": "ISC",
-         "dependencies": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-         },
          "engines": {
-            "node": ">=6"
+            "node": ">=12"
          }
       },
       "node_modules/yargs-unparser": {
@@ -5935,12 +5761,6 @@
          "engines": {
             "node": ">=8"
          }
-      },
-      "node_modules/yargs/node_modules/y18n": {
-         "version": "4.0.3",
-         "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
-         "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
-         "license": "ISC"
       },
       "node_modules/yocto-queue": {
          "version": "0.1.0",
diff --git a/package.json b/package.json
index fd219b5..075cbc3 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
       "stylus": "^0.64.0",
       "vue": "^3.5.13",
       "vue-router": "^4.5.1",
-      "yargs": "^15.4.1"
+      "yargs": "^17.7.2"
    },
    "devDependencies": {
       "@vitejs/plugin-vue": "^5.2.3",
diff --git a/vue/src/assets/styles.styl b/vue/src/assets/styles.styl
index a6e3ca0..98ebcb3 100644
--- a/vue/src/assets/styles.styl
+++ b/vue/src/assets/styles.styl
@@ -34,6 +34,9 @@
 .nowrap
    white-space nowrap
 
+.muted
+  color #666
+
 
 input[type=text], input[type=password]
    padding .11em .22em
diff --git a/vue/src/components/Header.vue b/vue/src/components/Header.vue
index 455fe20..e61e178 100644
--- a/vue/src/components/Header.vue
+++ b/vue/src/components/Header.vue
@@ -16,6 +16,7 @@
       <div>|</div>
       <RouterLink :to="`${routerBase}/ui/user`">Users</RouterLink>
       <RouterLink :to="`${routerBase}/ui/kurs`">Courses</RouterLink>
+      <RouterLink :to="`${routerBase}/ui/kurs/rolle/admin`">Course-Admins</RouterLink>
       <div style="flex-grow: 1" />
       <div>
          <button type="button" title="reindex search index" @click="doReindex">♻</button>
diff --git a/vue/src/lib/api.js b/vue/src/lib/api.js
index adffe89..4d6f7bd 100644
--- a/vue/src/lib/api.js
+++ b/vue/src/lib/api.js
@@ -91,3 +91,15 @@
    console.log(data)
    return data
 }
+
+/////// Course Admin ////////////////////////////////////////////////////////////////
+
+export async function getCourseAdmins () {
+   const res = await fetch(`${apiBase}/kurs/rolle/admin?token=${apiToken.value}`)
+   return res.json()
+}
+
+export async function getCourseNoAdmins () {
+   const res = await fetch(`${apiBase}/kurs/rolle/noadmin?token=${apiToken.value}`)
+   return res.json()
+}
diff --git a/vue/src/pages/CourseAdmins.vue b/vue/src/pages/CourseAdmins.vue
new file mode 100644
index 0000000..b769df1
--- /dev/null
+++ b/vue/src/pages/CourseAdmins.vue
@@ -0,0 +1,119 @@
+<script setup>
+
+import {onMounted, reactive, ref} from "vue"
+import {useRoute} from "vue-router"
+import Pagination from "../components/Pagination.vue"
+import {getCourseAdmins, getCourseNoAdmins, getUsers, iliasBase, routerBase, searchUsers} from "@/lib/api"
+import {useRouteQuery} from '@vueuse/router'
+import {onKeyStroke, useDebounceFn} from "@vueuse/core"
+import LinkExtern from "@/components/LinkExtern.vue";
+
+document.title = `Course-Admins | globus-ilias-rest`
+
+const route = useRoute()
+const adminRoles = ref([])
+const adminRoles2 = ref([])
+const error = ref(null)
+
+onMounted(init)
+
+/////////////////////////////////////////////////////////////////////////
+
+async function init() {
+   console.log(">>> INIT")
+   const data1 = await getCourseAdmins()
+   console.log({adminRoles:data1})
+   adminRoles.value = data1
+   const data2 = await getCourseNoAdmins()
+   console.log({noAdminRoles:data2})
+   adminRoles2.value = data2
+}
+
+
+</script>
+
+<template>
+
+   <div>
+
+      <div>
+
+         <h1>
+            Admin-Rollen
+            <small>{{ adminRoles.length }}</small>
+         </h1>
+         <p v-if="error">{{ error }}</p>
+
+         <table class="w100p">
+            <thead>
+            <tr>
+               <th>crs_obj_id</th>
+               <th>crs_ref_id</th>
+               <th>crs_title</th>
+               <th>rol_id</th>
+               <th>role</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr v-if="adminRoles" v-for="item in adminRoles">
+               <td>{{ item.crs_obj_id }}</td>
+               <td>
+                  <a :href="`${iliasBase}/goto.php?target=crs_${item.crs_ref_id}`" target="_blank">
+                     {{ item.crs_ref_id }}
+                     <LinkExtern/>
+                  </a>
+               </td>
+               <td>{{ item.crs_title }}</td>
+               <td>{{ item.rol_id }}</td>
+               <td>{{ item.role }}</td>
+            </tr>
+            </tbody>
+         </table>
+
+      </div>
+
+      <br>
+      <br>
+
+      <div>
+         <h1>Admin-Rollen ohne Benutzer
+            <small>{{ adminRoles2.length }}</small>
+         </h1>
+         <p class="muted">Wenn ein Kurs <strong>keinen</strong> Benutzer mit einer Admin-Rolle zugewiesen hat, so kann
+         von diesem Kurs kein TN gelöscht werden.</p>
+         <table class="w100p">
+            <thead>
+            <tr>
+               <th>crs_obj_id</th>
+               <th>crs_ref_id</th>
+               <th>crs_title</th>
+               <th>rol_id</th>
+               <th>role</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr v-if="adminRoles2" v-for="item in adminRoles2">
+               <td>{{ item.crs_obj_id }}</td>
+               <td>
+                  <a :href="`${iliasBase}/goto.php?target=crs_${item.crs_ref_id}`" target="_blank">
+                     {{ item.crs_ref_id }}
+                     <LinkExtern/>
+                  </a>
+               </td>
+               <td>{{ item.crs_title }}</td>
+               <td>{{ item.rol_id }}</td>
+               <td>{{ item.role }}</td>
+            </tr>
+            </tbody>
+         </table>
+      </div>
+
+
+   </div>
+
+</template>
+
+<style scoped lang="stylus">
+
+
+</style>
diff --git a/vue/src/router.js b/vue/src/router.js
index c19a76d..3d83672 100644
--- a/vue/src/router.js
+++ b/vue/src/router.js
@@ -9,6 +9,7 @@
 import KursDetail from './pages/KursDetail.vue'
 import KursDetailLp from "@/pages/KursDetailLp.vue";
 import {routerBase} from "@/lib/api"
+import CourseAdmins from "@/pages/CourseAdmins.vue";
 
 
 const routes = [
@@ -43,6 +44,11 @@
       component: KursDetailLp,
       meta: { title: 'KursDetail LP | globus-ilias-rest' }
    },
+   {
+      path: `${routerBase}/ui/kurs/rolle/admin`,
+      component: CourseAdmins,
+      meta: { title: 'Course-Admins | globus-ilias-rest' }
+   },
 ]
 // console.log(routes)
 

--
Gitblit v1.8.0