Feat(webui): dashboard and console qol improvements#7215
Feat(webui): dashboard and console qol improvements#7215LIghtJUNction merged 4 commits intoAstrBotDevs:masterfrom
Conversation
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The
checkOnboardingCompletedmethod performs two network requests both on login and on everyLoginPagemount when a token exists; consider caching the onboarding status in the store or reusing existing config state to avoid repeated calls and reduce login/redirect latency.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `checkOnboardingCompleted` method performs two network requests both on login and on every `LoginPage` mount when a token exists; consider caching the onboarding status in the store or reusing existing config state to avoid repeated calls and reduce login/redirect latency.
## Individual Comments
### Comment 1
<location path="dashboard/src/components/shared/ConsoleDisplayer.vue" line_range="267-269" />
<code_context>
this.autoScroll = !this.autoScroll;
},
+ toggleFullscreen() {
+ const container = document.getElementById('console-wrapper');
+ if (!document.fullscreenElement) {
+ container.requestFullscreen().catch(err => {
+ console.error(`Error attempting to enable full-screen mode: ${err.message}`);
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against a missing `console-wrapper` element before calling `requestFullscreen`.
If `document.getElementById('console-wrapper')` returns `null` (e.g., after refactors or conditional rendering), `container.requestFullscreen()` will throw. Add a null check before calling `requestFullscreen`, for example:
```js
const container = document.getElementById('console-wrapper');
if (!container) {
console.warn('Console wrapper element not found for fullscreen');
return;
}
```
</issue_to_address>
### Comment 2
<location path="dashboard/src/stores/auth.ts" line_range="40" />
<code_context>
return Promise.reject(error);
}
},
+ async checkOnboardingCompleted(): Promise<boolean> {
+ try {
+ // 1. 检查平台配置
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the onboarding check logic into a dedicated service that also centralizes provider type resolution to keep the auth store focused and easier to maintain.
You can keep the new behavior but reduce complexity and coupling by:
1. Extracting onboarding checks out of the store into a small service/composable.
2. Simplifying provider detection with a helper that normalizes provider type resolution.
For example, create a dedicated onboarding service:
```ts
// services/onboardingService.ts
import axios from 'axios';
async function fetchPlatformHasConfig(): Promise<boolean> {
const res = await axios.get('/api/config/get');
return (res.data.data.config.platform || []).length > 0;
}
function resolveProviderType(
provider: any,
sourceTypeById: Record<string, string>,
): string | null {
if (provider.provider_type) return provider.provider_type;
if (provider.provider_source_id) {
return sourceTypeById[provider.provider_source_id] || null;
}
const legacyType = String(provider.type || '');
return legacyType || null;
}
async function fetchHasChatCompletionProvider(): Promise<boolean> {
const res = await axios.get('/api/config/provider/template');
const providers = res.data.data?.providers || [];
const sources = res.data.data?.provider_sources || [];
const sourceTypeById: Record<string, string> = {};
sources.forEach((s: any) => {
sourceTypeById[s.id] = s.provider_type;
});
return providers.some((p: any) => {
const type = resolveProviderType(p, sourceTypeById);
return type === 'chat_completion' || String(type).includes('chat_completion');
});
}
export async function isOnboardingCompleted(): Promise<boolean> {
try {
const hasPlatform = await fetchPlatformHasConfig();
if (!hasPlatform) return false;
return await fetchHasChatCompletionProvider();
} catch (e) {
console.error('Failed to check onboarding status:', e);
return false; // preserve existing behavior
}
}
```
Then the store stays focused and orchestration is clearer:
```ts
// in auth store
import { isOnboardingCompleted } from '@/services/onboardingService';
async login(username: string, password: string) {
try {
const res = await axios.post('/api/login', { username, password });
// ... existing login logic ...
const onboardingCompleted = await isOnboardingCompleted();
this.returnUrl = null;
router.push(onboardingCompleted ? '/dashboard/default' : '/welcome');
} catch (error) {
return Promise.reject(error);
}
}
```
This keeps functionality identical while:
- Removing cross-cutting onboarding logic from the auth store.
- Encapsulating network + domain logic into a service.
- Making provider type resolution self-contained and easier to reason about.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| toggleFullscreen() { | ||
| const container = document.getElementById('console-wrapper'); | ||
| if (!document.fullscreenElement) { |
There was a problem hiding this comment.
issue (bug_risk): Guard against a missing console-wrapper element before calling requestFullscreen.
If document.getElementById('console-wrapper') returns null (e.g., after refactors or conditional rendering), container.requestFullscreen() will throw. Add a null check before calling requestFullscreen, for example:
const container = document.getElementById('console-wrapper');
if (!container) {
console.warn('Console wrapper element not found for fullscreen');
return;
}| return Promise.reject(error); | ||
| } | ||
| }, | ||
| async checkOnboardingCompleted(): Promise<boolean> { |
There was a problem hiding this comment.
issue (complexity): Consider extracting the onboarding check logic into a dedicated service that also centralizes provider type resolution to keep the auth store focused and easier to maintain.
You can keep the new behavior but reduce complexity and coupling by:
- Extracting onboarding checks out of the store into a small service/composable.
- Simplifying provider detection with a helper that normalizes provider type resolution.
For example, create a dedicated onboarding service:
// services/onboardingService.ts
import axios from 'axios';
async function fetchPlatformHasConfig(): Promise<boolean> {
const res = await axios.get('/api/config/get');
return (res.data.data.config.platform || []).length > 0;
}
function resolveProviderType(
provider: any,
sourceTypeById: Record<string, string>,
): string | null {
if (provider.provider_type) return provider.provider_type;
if (provider.provider_source_id) {
return sourceTypeById[provider.provider_source_id] || null;
}
const legacyType = String(provider.type || '');
return legacyType || null;
}
async function fetchHasChatCompletionProvider(): Promise<boolean> {
const res = await axios.get('/api/config/provider/template');
const providers = res.data.data?.providers || [];
const sources = res.data.data?.provider_sources || [];
const sourceTypeById: Record<string, string> = {};
sources.forEach((s: any) => {
sourceTypeById[s.id] = s.provider_type;
});
return providers.some((p: any) => {
const type = resolveProviderType(p, sourceTypeById);
return type === 'chat_completion' || String(type).includes('chat_completion');
});
}
export async function isOnboardingCompleted(): Promise<boolean> {
try {
const hasPlatform = await fetchPlatformHasConfig();
if (!hasPlatform) return false;
return await fetchHasChatCompletionProvider();
} catch (e) {
console.error('Failed to check onboarding status:', e);
return false; // preserve existing behavior
}
}Then the store stays focused and orchestration is clearer:
// in auth store
import { isOnboardingCompleted } from '@/services/onboardingService';
async login(username: string, password: string) {
try {
const res = await axios.post('/api/login', { username, password });
// ... existing login logic ...
const onboardingCompleted = await isOnboardingCompleted();
this.returnUrl = null;
router.push(onboardingCompleted ? '/dashboard/default' : '/welcome');
} catch (error) {
return Promise.reject(error);
}
}This keeps functionality identical while:
- Removing cross-cutting onboarding logic from the auth store.
- Encapsulating network + domain logic into a service.
- Making provider type resolution self-contained and easier to reason about.
There was a problem hiding this comment.
Code Review
This pull request introduces several UI and logic enhancements, including displaying plugin names in the pinned items list, adding a fullscreen toggle for the console displayer, and implementing an onboarding check to redirect users after login. Feedback focuses on improving code robustness with optional chaining, adhering to Vue best practices by using refs instead of direct DOM manipulation, addressing accessibility concerns regarding color contrast in the console, and resolving potential layout overflows in the pinned plugin component.
| try { | ||
| // 1. 检查平台配置 | ||
| const platformRes = await axios.get('/api/config/get'); | ||
| const hasPlatform = (platformRes.data.data.config.platform || []).length > 0; |
There was a problem hiding this comment.
|
|
||
| <template> | ||
| <div> | ||
| <div class="console-displayer-wrapper" id="console-wrapper"> |
| }, | ||
|
|
||
| toggleFullscreen() { | ||
| const container = document.getElementById('console-wrapper'); |
Modifications / 改动点
本PR提供了三项提升用户体验的改动:
为日志控制台增加了展开为全屏按钮,方便用户使用副屏进行监控
现在已经在欢迎界面完成两项配置的用户,第二次登录的时候将会直接跳转到数据大屏界面;而不是欢迎界面
为置顶的插件增加下置的插件名,增加可读性
This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Improve web UI dashboard and console usability with fullscreen log viewing, smarter post-login routing, and clearer pinned plugin labels.
New Features: