Skip to content

Commit 4dd8a1b

Browse files
committed
Update Admin UIs with placeholders on how to install different features when missing
1 parent 57d0d57 commit 4dd8a1b

34 files changed

+1958
-1334
lines changed

ServiceStack/src/ServiceStack.AI.Chat/modules/admin-ui/components/AdminChat.mjs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,26 @@ export const AdminChat = {
431431
LogDetailDialog,
432432
},
433433
template: `
434-
<div class="flex flex-col h-full w-full bg-gray-50 dark:bg-gray-900">
434+
<section v-if="!plugin">
435+
<div class="p-4 max-w-3xl">
436+
<Alert type="info">Admin Chat UI is not enabled</Alert>
437+
<div class="my-4">
438+
<div>
439+
<p>
440+
The <b>ChatFeature</b> plugin needs to be configured with your App
441+
<a href="https://docs.servicestack.net/ai-chat-api" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
442+
Learn more <span aria-hidden="true">&rarr;</span>
443+
</a>
444+
</p>
445+
</div>
446+
</div>
447+
<div>
448+
<p class="text-sm text-gray-700 my-2">Quick start:</p>
449+
<CopyLine text="x mix chat" />
450+
</div>
451+
</div>
452+
</section>
453+
<div v-else class="flex flex-col h-full w-full bg-gray-50 dark:bg-gray-900">
435454
<!-- Header with Title and Month Selector -->
436455
<div class="border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-2 sm:px-4 py-3">
437456
<div class="max-w-6xl mx-auto flex items-center justify-between">
@@ -780,6 +799,7 @@ export const AdminChat = {
780799
setup() {
781800
const routes = inject('routes')
782801
const server = inject('server')
802+
const plugin = server.plugins.loaded.includes('aichat')
783803
const client = useClient()
784804
const selectedLog = ref(null)
785805
const preview = ref(false)
@@ -1639,6 +1659,7 @@ export const AdminChat = {
16391659
})
16401660

16411661
return {
1662+
plugin,
16421663
routes,
16431664
selectedLog,
16441665
logs,

ServiceStack/src/ServiceStack/modules/admin-ui/components/Analytics.mjs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,7 +1719,28 @@ export const Analytics = {
17191719
IpAnalytics,
17201720
},
17211721
template: `
1722-
<div class="container mx-auto">
1722+
<section v-if="!plugin">
1723+
<div class="p-4 max-w-3xl">
1724+
<Alert type="info">Admin Analytics UI is not enabled</Alert>
1725+
<div class="my-4">
1726+
<div>
1727+
<p>
1728+
The <b>RequestLogsFeature</b> plugin needs to be configured with your App's RDBMS
1729+
<a href="https://docs.servicestack.net/admin-ui-rdbms-analytics" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
1730+
Learn more <span aria-hidden="true">&rarr;</span>
1731+
</a>
1732+
</p>
1733+
</div>
1734+
</div>
1735+
<div>
1736+
<p class="text-sm text-gray-700 my-2">For ASP.NET Identity Auth Projects:</p>
1737+
<CopyLine text="x mix db-identity" />
1738+
<p class="text-sm text-gray-700 my-2">For other ASP.NET Core Projects:</p>
1739+
<CopyLine text="x mix db-requestlogs" />
1740+
</div>
1741+
</div>
1742+
</section>
1743+
<div v-else class="container mx-auto">
17231744
<ErrorSummary v-if="api.error" :status="api.error" />
17241745
<div>
17251746
<div class="relative">
@@ -1764,13 +1785,14 @@ export const Analytics = {
17641785
setup(props) {
17651786
const routes = inject('routes')
17661787
const server = inject('server')
1788+
const plugin = server.plugins.requestLogs
17671789
const client = useClient()
17681790
const analytics = ref(null)
17691791
const loading = ref(false)
17701792
const error = ref(null)
17711793
const api = ref(new ApiResult())
1772-
const tabs = ref(server.plugins.requestLogs?.analytics?.tabs ?? {APIs: ''})
1773-
const months = ref(server.plugins.requestLogs?.analytics?.months ?? [])
1794+
const tabs = ref(plugin?.analytics?.tabs ?? {APIs: ''})
1795+
const months = ref(plugin?.analytics?.months ?? [])
17741796
const years = computed(() =>
17751797
Array.from(new Set(months.value.map(x => leftPart(x, '-')))).toReversed())
17761798
async function update() {
@@ -1807,6 +1829,7 @@ export const Analytics = {
18071829
nextTick(update)
18081830
})
18091831
return {
1832+
plugin,
18101833
routes,
18111834
api,
18121835
analytics,

ServiceStack/src/ServiceStack/modules/admin-ui/components/ApiKeys.mjs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,26 @@ import { ApiResult, apiValueFmt, humanify, mapGet } from "@servicestack/client"
44
import { AdminQueryApiKeys } from "dtos"
55
export const ApiKeys = {
66
template:`
7-
<section id="apikeys">
7+
<section v-if="!plugin">
8+
<div class="p-4 max-w-3xl">
9+
<Alert type="info">API Keys Admin UI is not enabled</Alert>
10+
<div class="my-4">
11+
<div>
12+
<p>
13+
The <b>ApiKeysFeature</b> plugin needs to be configured with your App
14+
<a href="https://docs.servicestack.net/auth/apikeys" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
15+
Learn more <span aria-hidden="true">&rarr;</span>
16+
</a>
17+
</p>
18+
</div>
19+
</div>
20+
<div>
21+
<p class="text-sm text-gray-700 mb-2">Quick start:</p>
22+
<CopyLine text="x mix apikeys" />
23+
</div>
24+
</div>
25+
</section>
26+
<section v-else id="apikeys">
827
<form @submit.prevent="formSearch" class="mb-3">
928
<div class="flex items-center">
1029
<TextInput id="query" type="search" v-model="request.search" label="" placeholder="Search API Keys" @search="formSearch" class="-mt-1" />
@@ -91,17 +110,18 @@ export const ApiKeys = {
91110
const routes = inject('routes')
92111
const store = inject('store')
93112
const server = inject('server')
113+
const plugin = server.plugins.apiKey
94114
const client = useClient()
95115
const { formatDate, relativeTime } = useFormatters()
96116
const renderKey = ref(1)
97117
const request = ref(new AdminQueryApiKeys())
98118
const api = ref(new ApiResult())
99119
const results = computed(() => api.value?.response?.results || [])
100120
const columns = 'id,userName,name,visibleKey,createdDate,expiryDate'.split(',')
101-
if (server.plugins.apiKey.scopes.length) {
121+
if (plugin.scopes.length) {
102122
columns.push('scopes')
103123
}
104-
if (server.plugins.apiKey.features.length) {
124+
if (plugin.features.length) {
105125
columns.push('features')
106126
}
107127
columns.push('lastUsedDate')
@@ -172,6 +192,7 @@ export const ApiKeys = {
172192
client,
173193
store,
174194
server,
195+
plugin,
175196
routes,
176197
renderKey,
177198
link,

ServiceStack/src/ServiceStack/modules/admin-ui/components/BackgroundJobs.mjs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,10 +997,31 @@ export const BackgroundJobs = {
997997
ScheduledTasks,
998998
},
999999
template: `
1000-
<Tabs :tabs="tabs" :label="tabLabel" :clearQuery="true" />
1000+
<section v-if="!plugin">
1001+
<div class="p-4 max-w-3xl">
1002+
<Alert type="info">Background Jobs Admin UI is not enabled</Alert>
1003+
<div class="my-4">
1004+
<div>
1005+
<p>
1006+
The <b>DatabaseJobFeature</b> plugin needs to be configured with your App
1007+
<a href="https://docs.servicestack.net/rdbms-background-jobs" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
1008+
Learn more <span aria-hidden="true">&rarr;</span>
1009+
</a>
1010+
</p>
1011+
</div>
1012+
</div>
1013+
<div>
1014+
<p class="text-sm text-gray-700 mb-2">Quick start:</p>
1015+
<CopyLine text="x mix db-jobs" />
1016+
</div>
1017+
</div>
1018+
</section>
1019+
<Tabs v-else :tabs="tabs" :label="tabLabel" :clearQuery="true" />
10011020
`,
10021021
setup() {
10031022
const client = useClient()
1023+
const server = inject('server')
1024+
const plugin = server.plugins.loaded.includes('backgroundjobs')
10041025

10051026
const tabs = {
10061027
Dashboard,
@@ -1044,6 +1065,7 @@ export const BackgroundJobs = {
10441065
clearTimeout(updateStatsTimeout)
10451066
})
10461067
return {
1068+
plugin,
10471069
info,
10481070
tabs,
10491071
tabLabel,

ServiceStack/src/ServiceStack/modules/admin-ui/components/Commands.mjs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,23 @@ import { ViewCommands, ExecuteCommand } from "dtos"
66
import { Chart, registerables } from 'chart.js'
77
Chart.register(...registerables)
88
export const Commands = {
9-
template:/*html*/`
10-
<section class="">
9+
template:`
10+
<section v-if="!plugin">
11+
<div class="p-4 max-w-3xl">
12+
<Alert type="info">Admin Commands UI is not enabled</Alert>
13+
<div class="my-4">
14+
<div>
15+
<p>
16+
The <b>CommandsFeature</b> plugin needs to be configured with your App
17+
<a href="https://docs.servicestack.net/commands#command-admin-ui" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
18+
Learn more <span aria-hidden="true">&rarr;</span>
19+
</a>
20+
</p>
21+
</div>
22+
</div>
23+
</div>
24+
</section>
25+
<section v-else>
1126
<div>
1227
<div class="sm:hidden">
1328
<label for="redis-tabs" class="sr-only">Select a tab</label>
@@ -238,6 +253,7 @@ export const Commands = {
238253
const routes = inject('routes')
239254
const server = inject('server')
240255
const client = inject('client')
256+
const plugin = server.plugins.commands
241257
const {
242258
time,
243259
relativeTime,
@@ -272,7 +288,7 @@ export const Commands = {
272288
: {}
273289
}
274290
const model = ref({})
275-
const commandInfos = server.plugins.commands.commands
291+
const commandInfos = plugin.commands
276292
const navs = ref(Array.from(new Set(commandInfos.map(x => x.tag ?? 'other')))
277293
.map(x => ({
278294
tag: x,
@@ -520,8 +536,8 @@ export const Commands = {
520536
error.errors?.length > 0 ? '\n' + error.errors?.map(x => ` - ${x.errorCode}: ${x.message}`).join('\n') : null,
521537
].filter(x => !!x).join('\n')
522538
}
523-
return {
524-
routes, api, commandTotals, tabs, elChart, bottom, loadingMore, q, type,
539+
return {
540+
plugin, routes, api, commandTotals, tabs, elChart, bottom, loadingMore, q, type,
525541
refresh, headerSelected, rowSelected,
526542
selectedError, selectedClean, prettyJson, toggleError, rowSelectedError,
527543
toDate, time, altError,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ref } from "vue"
2+
import { useUtils } from "@servicestack/vue"
3+
const CopyLine = {
4+
template:`<div class="flex cursor-pointer" @click="copy(text)">
5+
<div class="flex-grow bg-gray-700">
6+
<div class="pl-4 py-1 text-lg align-middle text-white select-none">{{prefix||''}}{{text}}</div>
7+
</div>
8+
<div class="flex">
9+
<div class="bg-sky-500 text-white p-1 py-1.5">
10+
<svg v-if="copied" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
11+
<svg v-else class="w-6 h-6" title="copy" fill='none' stroke='white' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'>
12+
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='1' d='M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2'></path>
13+
</svg>
14+
</div>
15+
</div>
16+
</div>`,
17+
props:['text','prefix'],
18+
setup(props) {
19+
const { copyText } = useUtils()
20+
const copied = ref(false)
21+
function copy(text) {
22+
copied.value = true
23+
copyText(text)
24+
setTimeout(() => copied.value = false, 3000)
25+
}
26+
return { copied, copy, }
27+
}
28+
}
29+
export default CopyLine

ServiceStack/src/ServiceStack/modules/admin-ui/components/Dashboard.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ export const Dashboard = {
189189
validation:'Validation',
190190
database:'Database',
191191
redis:'Redis',
192+
aichat:'AI Chat',
192193
}))
193194

194195
function isRegistered(id) {

ServiceStack/src/ServiceStack/modules/admin-ui/components/Database.mjs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,23 @@ import { keydown } from "app"
55
import { AdminDatabase } from "dtos"
66
import { prettyJson } from "core"
77
export const Database = {
8-
template:/*html*/`
9-
<section class="">
8+
template:`
9+
<section v-if="!plugin">
10+
<div class="p-4 max-w-3xl">
11+
<Alert type="info">Database Admin UI is not enabled</Alert>
12+
<div class="my-4">
13+
<div>
14+
<p>
15+
The <b>AdminDatabaseFeature</b> plugin needs to be configured with your App
16+
<a href="https://docs.servicestack.net/admin-ui-database" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
17+
Learn more <span aria-hidden="true">&rarr;</span>
18+
</a>
19+
</p>
20+
</div>
21+
</div>
22+
</div>
23+
</section>
24+
<section v-else>
1025
<div v-if="!routes.table" class="flex flex-wrap">
1126
<nav v-for="db in databases" class="flex-1 space-y-1 bg-white pb-4 md:pb-scroll" aria-label="Tables">
1227
<div class="">

ServiceStack/src/ServiceStack/modules/admin-ui/components/IdentityRoles.mjs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,22 @@ export const EditRole = {
240240
export const IdentityRoles = {
241241
components: { NewRole, EditRole },
242242
template:/*html*/`
243-
<section id="admin-users">
243+
<section v-if="!plugin">
244+
<div class="p-4 max-w-3xl">
245+
<Alert type="info">AdminUsersFeature is not enabled</Alert>
246+
<div class="my-4">
247+
<div>
248+
<p>
249+
The <b>AdminUsersFeature</b> plugin needs to be configured with your App
250+
<a href="https://docs.servicestack.net/admin-ui-identity-roles" class="ml-2 whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" target="_blank">
251+
Learn more <span aria-hidden="true">&rarr;</span>
252+
</a>
253+
</p>
254+
</div>
255+
</div>
256+
</div>
257+
</section>
258+
<section v-else id="admin-users">
244259
<a v-href="{ new:1,edit:null }" class="inline-flex items-center px-3 py-2.5 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
245260
New
246261
<span class="hidden md:ml-1 md:inline">Role</span>
@@ -287,8 +302,10 @@ export const IdentityRoles = {
287302
setup() {
288303
const routes = inject('routes')
289304
const store = inject('store')
305+
const server = inject('server')
290306
const client = useClient()
291307
const refreshKey = ref(1)
308+
const plugin = server.plugins.adminIdentityUsers
292309
const request = ref(new AdminGetRoles())
293310
/** @type {Ref<ApiResult<AdminGetRolesResponse>>} */
294311
const api = ref(new ApiResult())
@@ -348,6 +365,7 @@ export const IdentityRoles = {
348365
return {
349366
client,
350367
store,
368+
plugin,
351369
routes,
352370
refreshKey,
353371
link,

0 commit comments

Comments
 (0)