Skip to content

Commit 871b1c1

Browse files
committed
feat: update grant-app page
1 parent fa9c695 commit 871b1c1

File tree

7 files changed

+176
-156
lines changed

7 files changed

+176
-156
lines changed

service/server/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func handleAppRegister(c *gin.Context) {
101101
"appName": {req.Name},
102102
"appDescription": {req.Description},
103103
}
104-
uiActive, cleanup, err := logic.OpenAction("register", params)
104+
uiActive, cleanup, err := logic.OpenAction("grant-app", params)
105105
if cleanup != nil {
106106
defer cleanup()
107107
}

ui/src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ onUIOpened()
8080

8181
<LoginForm v-else-if="!authStore.isLoggedIn" :register="authState?.status === 'not_registered'" />
8282

83+
<RouterView v-else-if="currentRoute.meta.fullPage" />
84+
8385
<SidebarProvider v-else>
8486
<AppSidebar />
8587
<SidebarInset>

ui/src/lib/providers/openrouter/Login.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const provider = useOpenRouterProvider()
1111
const keysStore = useKeysStore()
1212
1313
function handleLogin() {
14-
const callbackUrl = `${window.location.protocol}//${window.location.host}/action/openrouter-auth`
14+
const callbackUrl = `${window.location.protocol}//${window.location.host}/action/oauth-callback`
1515
const authUrl = `https://openrouter.ai/auth?callback_url=${encodeURIComponent(callbackUrl)}`
1616
window.open(authUrl, '_blank', 'width=600,height=600,noopener=yes,noreferrer=yes')
1717

ui/src/lib/router.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
import type { RouteRecordRaw } from 'vue-router'
12
import { createRouter, createWebHistory } from 'vue-router'
23
import About from '@/views/About.vue'
3-
import ActionHandler from '@/views/ActionHandler.vue'
4+
import GrantApp from '@/views/action/GrantApp.vue'
5+
import OAuthCallback from '@/views/action/OAuthCallback.vue'
46
import AppManagement from '@/views/AppManagement.vue'
57
import Models from '@/views/Models.vue'
68
import NotFound from '@/views/NotFound.vue'
79
import Settings from '@/views/Settings.vue'
810
import Usage from '@/views/Usage.vue'
911

10-
const routes = [
12+
const routes: RouteRecordRaw[] = [
1113
{
1214
path: '/',
1315
redirect: '/apps',
@@ -38,9 +40,15 @@ const routes = [
3840
component: About,
3941
},
4042
{
41-
path: '/action/:actionType',
42-
name: 'ActionHandler',
43-
component: ActionHandler,
43+
path: '/action/grant-app',
44+
name: 'GrantApp',
45+
component: GrantApp,
46+
meta: { fullPage: true },
47+
},
48+
{
49+
path: '/action/oauth-callback',
50+
name: 'OAuthCallback',
51+
component: OAuthCallback,
4452
},
4553
{
4654
path: '/:pathMatch(.*)*',

ui/src/views/ActionHandler.vue

Lines changed: 0 additions & 149 deletions
This file was deleted.

ui/src/views/action/GrantApp.vue

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import { useI18n } from 'vue-i18n'
4+
import { useRouter } from 'vue-router'
5+
import { toast } from 'vue-sonner'
6+
import KeySelector from '@/components/KeySelector.vue'
7+
import { Button } from '@/components/ui/button'
8+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
9+
import { useKeysStore } from '@/stores'
10+
import { useAppStore } from '@/stores/app'
11+
import LogoSvg from '/logo.svg?raw'
12+
13+
const { t } = useI18n()
14+
const router = useRouter()
15+
16+
const query = new URLSearchParams(window.location.search)
17+
18+
const selectedKey = ref<string>('')
19+
const appStore = useAppStore()
20+
const keysStore = useKeysStore()
21+
22+
async function registerAction(granted: boolean) {
23+
const appId = query.get('appId')
24+
25+
if (!appId) {
26+
toast.error(t('missingAppId'))
27+
return
28+
}
29+
30+
await appStore.toggleAppAuthorization(appId, granted, selectedKey.value)
31+
router.replace('/')
32+
}
33+
</script>
34+
35+
<template>
36+
<div class="min-h-screen flex items-center justify-center p-6 bg-gradient-to-br from-background to-muted/20">
37+
<Card class="w-full max-w-2xl shadow-lg">
38+
<CardHeader class="text-center space-y-4 pb-8">
39+
<div class="flex justify-center">
40+
<div class="rounded-2xl bg-primary p-3 text-primary-foreground shadow-md">
41+
<div class="h-10 w-10" v-html="LogoSvg" />
42+
</div>
43+
</div>
44+
<div>
45+
<CardTitle class="text-3xl font-bold">
46+
{{ t('appPermissionRequest') }}
47+
</CardTitle>
48+
<CardDescription class="text-base mt-2">
49+
{{ t('appPermissionDescription') }}
50+
</CardDescription>
51+
</div>
52+
</CardHeader>
53+
54+
<CardContent class="space-y-6">
55+
<div class="space-y-4 bg-muted/30 rounded-lg p-6">
56+
<div class="flex items-baseline gap-3">
57+
<span class="text-sm font-medium text-muted-foreground min-w-20">{{ t('appName') }}</span>
58+
<span class="text-lg font-semibold">{{ query.get('appName') || '-' }}</span>
59+
</div>
60+
<div class="flex items-baseline gap-3">
61+
<span class="text-sm font-medium text-muted-foreground min-w-20">{{ t('appDescription') }}</span>
62+
<span class="text-base">{{ query.get('appDescription') || '-' }}</span>
63+
</div>
64+
</div>
65+
66+
<KeySelector v-model="selectedKey" compact />
67+
68+
<div class="flex gap-3 pt-4">
69+
<Button
70+
variant="outline"
71+
size="lg"
72+
class="flex-1"
73+
@click="registerAction(false)"
74+
>
75+
{{ t('deny') }}
76+
</Button>
77+
<Button
78+
variant="default"
79+
size="lg"
80+
class="flex-1"
81+
:disabled="!selectedKey || keysStore.keys.length === 0"
82+
@click="registerAction(true)"
83+
>
84+
{{ t('approve') }}
85+
</Button>
86+
</div>
87+
</CardContent>
88+
</Card>
89+
</div>
90+
</template>
91+
92+
<i18n lang="yaml">
93+
en-US:
94+
missingAppId: Missing application ID
95+
appPermissionRequest: Application Authorization
96+
appPermissionDescription: This application is requesting access to use your AI provider keys
97+
appName: App Name
98+
appDescription: Description
99+
deny: Deny
100+
approve: Approve
101+
102+
zh-CN:
103+
missingAppId: 缺少应用ID
104+
appPermissionRequest: 应用授权请求
105+
appPermissionDescription: 该应用请求使用您的 AI 提供商密钥
106+
appName: 应用名称
107+
appDescription: 应用描述
108+
deny: 拒绝
109+
approve: 同意
110+
</i18n>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<script setup lang="ts">
2+
import { onMounted, ref } from 'vue'
3+
import { useI18n } from 'vue-i18n'
4+
import { Button } from '@/components/ui/button'
5+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
6+
7+
const { t } = useI18n()
8+
9+
const query = new URLSearchParams(window.location.search)
10+
const open = ref(true)
11+
12+
onMounted(() => {
13+
const bc = new BroadcastChannel('openrouter-auth')
14+
bc.postMessage({ code: query.get('code') })
15+
setTimeout(() => {
16+
window.close()
17+
}, 100)
18+
})
19+
</script>
20+
21+
<template>
22+
<Dialog v-model:open="open">
23+
<DialogContent>
24+
<DialogHeader>
25+
<DialogTitle>{{ t('authorizationSuccessful') }}</DialogTitle>
26+
<DialogDescription>
27+
{{ t('authorizationSuccessfulDescription') }}
28+
</DialogDescription>
29+
</DialogHeader>
30+
<div class="flex justify-center mt-6">
31+
<Button @click="open = false">
32+
{{ t('close') }}
33+
</Button>
34+
</div>
35+
</DialogContent>
36+
</Dialog>
37+
</template>
38+
39+
<i18n lang="yaml">
40+
en-US:
41+
authorizationSuccessful: Authorization Successful
42+
authorizationSuccessfulDescription: Authorization completed successfully. Please close this page.
43+
close: Close
44+
45+
zh-CN:
46+
authorizationSuccessful: 授权成功
47+
authorizationSuccessfulDescription: 授权成功。请关闭该页面。
48+
close: 关闭
49+
</i18n>

0 commit comments

Comments
 (0)