mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
💄 style(desktop): improve WelcomeStep layout centering in onboarding (#13125)
* 💄 style(desktop): improve WelcomeStep layout centering in onboarding Made-with: Cursor * 🐛 fix(desktop): validate remote server URL in isRemoteServerConfigured Made-with: Cursor
This commit is contained in:
@@ -93,10 +93,26 @@ export default class RemoteServerConfigCtr extends ControllerModule {
|
|||||||
*/
|
*/
|
||||||
async isRemoteServerConfigured(config?: DataSyncConfig): Promise<boolean> {
|
async isRemoteServerConfigured(config?: DataSyncConfig): Promise<boolean> {
|
||||||
const effectiveConfig = config ?? (await this.getRemoteServerConfig());
|
const effectiveConfig = config ?? (await this.getRemoteServerConfig());
|
||||||
return (
|
const isActive = Boolean(effectiveConfig.active);
|
||||||
effectiveConfig.active &&
|
const isSelfHostConfigured =
|
||||||
(effectiveConfig.storageMode !== 'selfHost' || !!effectiveConfig.remoteServerUrl)
|
effectiveConfig.storageMode !== 'selfHost' ||
|
||||||
);
|
this.isValidSelfHostRemoteUrl(effectiveConfig.remoteServerUrl);
|
||||||
|
|
||||||
|
return isActive && isSelfHostConfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isValidSelfHostRemoteUrl(remoteServerUrl?: string): boolean {
|
||||||
|
if (!remoteServerUrl) return false;
|
||||||
|
const normalizedUrl = remoteServerUrl.trim();
|
||||||
|
|
||||||
|
if (!normalizedUrl) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsedUrl = new URL(normalizedUrl);
|
||||||
|
return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -537,7 +553,7 @@ export default class RemoteServerConfigCtr extends ControllerModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getRemoteServerUrl(config?: DataSyncConfig) {
|
async getRemoteServerUrl(config?: DataSyncConfig) {
|
||||||
const dataConfig = this.normalizeConfig(config ? config : await this.getRemoteServerConfig());
|
const dataConfig = this.normalizeConfig(config ?? (await this.getRemoteServerConfig()));
|
||||||
|
|
||||||
return dataConfig.storageMode === 'cloud' ? OFFICIAL_CLOUD_SERVER : dataConfig.remoteServerUrl;
|
return dataConfig.storageMode === 'cloud' ? OFFICIAL_CLOUD_SERVER : dataConfig.remoteServerUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -747,6 +747,16 @@ describe('RemoteServerConfigCtr', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('isRemoteServerConfigured', () => {
|
describe('isRemoteServerConfigured', () => {
|
||||||
|
it('should return false when active is undefined', async () => {
|
||||||
|
mockStoreManager.get.mockReturnValue({
|
||||||
|
storageMode: 'cloud',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await controller.isRemoteServerConfigured();
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('should return true for active cloud mode (no remoteServerUrl needed)', async () => {
|
it('should return true for active cloud mode (no remoteServerUrl needed)', async () => {
|
||||||
mockStoreManager.get.mockReturnValue({
|
mockStoreManager.get.mockReturnValue({
|
||||||
active: true,
|
active: true,
|
||||||
@@ -794,6 +804,30 @@ describe('RemoteServerConfigCtr', () => {
|
|||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return false for selfHost mode with blank remoteServerUrl', async () => {
|
||||||
|
mockStoreManager.get.mockReturnValue({
|
||||||
|
active: true,
|
||||||
|
remoteServerUrl: ' ',
|
||||||
|
storageMode: 'selfHost',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await controller.isRemoteServerConfigured();
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false for selfHost mode with invalid remoteServerUrl', async () => {
|
||||||
|
mockStoreManager.get.mockReturnValue({
|
||||||
|
active: true,
|
||||||
|
remoteServerUrl: 'foo',
|
||||||
|
storageMode: 'selfHost',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await controller.isRemoteServerConfigured();
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('should use provided config instead of fetching', async () => {
|
it('should use provided config instead of fetching', async () => {
|
||||||
// Store has inactive config
|
// Store has inactive config
|
||||||
mockStoreManager.get.mockReturnValue({
|
mockStoreManager.get.mockReturnValue({
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ const WelcomeStep = memo<WelcomeStepProps>(({ onNext }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={16}>
|
<Flexbox align="center" gap={16} justify="center">
|
||||||
<ProductLogo size={64} />
|
<ProductLogo size={64} />
|
||||||
<Flexbox style={{ marginBottom: 16 }}>
|
<Flexbox align="center" gap={16} justify="center" style={{ marginBottom: 16 }}>
|
||||||
<Text as={'h1'} fontSize={28} weight={'bold'}>
|
<Text as={'h1'} fontSize={28} weight={'bold'}>
|
||||||
<TypewriterEffect
|
<TypewriterEffect
|
||||||
cursorCharacter={<LoadingDots size={28} variant={'pulse'} />}
|
cursorCharacter={<LoadingDots size={28} variant={'pulse'} />}
|
||||||
|
|||||||
Reference in New Issue
Block a user