Skip to content

Commit 7801f28

Browse files
authored
feat: add theme swtich support (#715)
* feat: add the frontend theme support * add theme backend extension * feat: complete the basic feature to switch theme * add a help link of the theme * improve the setting --------- Co-authored-by: rick <[email protected]>
1 parent f3b09b4 commit 7801f28

File tree

23 files changed

+988
-250
lines changed

23 files changed

+988
-250
lines changed

cmd/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
292292
server.RegisterRunnerServer(s, remoteServer)
293293
server.RegisterMockServer(s, mockServerController)
294294
server.RegisterDataServerServer(s, remoteServer.(server.DataServerServer))
295+
server.RegisterThemeExtensionServer(s, remoteServer.(server.ThemeExtensionServer))
295296
serverLogger.Info("gRPC server listening at", "addr", lis.Addr())
296297
s.Serve(lis)
297298
}()
@@ -336,13 +337,15 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
336337
err = errors.Join(
337338
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}),
338339
server.RegisterMockHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}),
340+
server.RegisterThemeExtensionHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}),
339341
server.RegisterDataServerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}))
340342
} else {
341343
dialOption := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials()),
342344
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt))}
343345
err = errors.Join(
344346
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, dialOption),
345347
server.RegisterMockHandlerFromEndpoint(ctx, mux, gRPCServerAddr, dialOption),
348+
server.RegisterThemeExtensionHandlerFromEndpoint(ctx, mux, gRPCServerAddr, dialOption),
346349
server.RegisterDataServerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, dialOption))
347350
}
348351

console/atest-ui/src/App.vue

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<script setup lang="ts">
22
import {
3-
Document,
4-
Menu as IconMenu,
5-
Histogram,
6-
Location,
7-
Share,
8-
ArrowDown,
9-
Guide,
10-
DataAnalysis
3+
Document,
4+
Menu as IconMenu,
5+
Histogram,
6+
Location,
7+
Share,
8+
ArrowDown,
9+
Guide,
10+
DataAnalysis, Help, Setting
1111
} from '@element-plus/icons-vue'
1212
import { ref, watch } from 'vue'
1313
import { API } from './views/net'
@@ -23,8 +23,9 @@ import { useI18n } from 'vue-i18n'
2323
2424
const { t, locale: i18nLocale } = useI18n()
2525
26-
import setAsDarkTheme from './theme'
26+
import { setAsDarkTheme, getThemes, setTheme, getTheme } from './theme'
2727
28+
const allThemes = ref(getThemes())
2829
const asDarkMode = ref(Cache.GetPreference().darkTheme)
2930
setAsDarkTheme(asDarkMode.value)
3031
watch(asDarkMode, Cache.WithDarkTheme)
@@ -87,6 +88,16 @@ const toHistoryPanel = ({ ID: selectID, panelName: historyPanelName }) => {
8788
panelName.value = historyPanelName;
8889
}
8990
91+
const settingDialogVisible = ref(false)
92+
watch(settingDialogVisible, (v: boolean) => {
93+
if (v) {
94+
allThemes.value = getThemes()
95+
}
96+
})
97+
const theme = ref(getTheme())
98+
watch(theme, (e) => {
99+
setTheme(e)
100+
})
90101
</script>
91102

92103
<template>
@@ -137,18 +148,7 @@ const toHistoryPanel = ({ ID: selectID, panelName: historyPanelName }) => {
137148
<el-main style="padding-top: 0px;">
138149
<div class="top-menu">
139150
<el-col style="display: flex; align-items: center;">
140-
<el-tag style="font-size: 18px;">{{ t('language') }}</el-tag>
141-
<el-dropdown trigger="click" @command="(command: string) => handleChangeLan(command)">
142-
<el-icon><arrow-down /></el-icon>
143-
<template #dropdown>
144-
<el-dropdown-menu>
145-
<el-dropdown-item command="chinese">中文</el-dropdown-item>
146-
<el-dropdown-item command="english">English</el-dropdown-item>
147-
</el-dropdown-menu>
148-
</template>
149-
</el-dropdown>
150-
151-
<el-switch type="primary" data-intro="Switch light and dark modes" v-model="asDarkMode"/>
151+
<el-icon @click="settingDialogVisible=true" size="20"><Setting /></el-icon>
152152
</el-col>
153153
</div>
154154
<TestingPanel v-if="panelName === 'testing'" @toHistoryPanel="toHistoryPanel"/>
@@ -164,6 +164,55 @@ const toHistoryPanel = ({ ID: selectID, panelName: historyPanelName }) => {
164164
<a :href=appVersionLink target="_blank" rel="noopener">{{appVersion}}</a>
165165
</div>
166166
</el-container>
167+
168+
<el-dialog v-model="settingDialogVisible" :title="t('title.setting' )" width="50%" draggable destroy-on-close>
169+
<el-row>
170+
<el-col :span="4">
171+
Theme:
172+
</el-col>
173+
<el-col :span="18">
174+
<el-select v-model="theme" placeholder="Select a theme">
175+
<el-option
176+
v-for="item in allThemes"
177+
:key="item"
178+
:label="item"
179+
:value="item"
180+
/>
181+
</el-select>
182+
<el-icon>
183+
<el-link href="https://github.com/LinuxSuRen/atest-ext-data-swagger/tree/master/data/theme" target="_blank">
184+
<Help />
185+
</el-link>
186+
</el-icon>
187+
</el-col>
188+
</el-row>
189+
190+
<el-row>
191+
<el-col :span="4">
192+
Language:
193+
</el-col>
194+
<el-col :span="18">
195+
<el-tag style="font-size: 18px;">{{ t('language') }}</el-tag>
196+
<el-dropdown trigger="click" @command="(command: string) => handleChangeLan(command)">
197+
<el-icon><arrow-down /></el-icon>
198+
<template #dropdown>
199+
<el-dropdown-menu>
200+
<el-dropdown-item command="chinese">中文</el-dropdown-item>
201+
<el-dropdown-item command="english">English</el-dropdown-item>
202+
</el-dropdown-menu>
203+
</template>
204+
</el-dropdown>
205+
</el-col>
206+
</el-row>
207+
<el-row>
208+
<el-col :span="4">
209+
Dark Mode:
210+
</el-col>
211+
<el-col :span="18">
212+
<el-switch type="primary" data-intro="Switch light and dark modes" v-model="asDarkMode"/>
213+
</el-col>
214+
</el-row>
215+
</el-dialog>
167216
</template>
168217

169218
<style>

console/atest-ui/src/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@
5252
"output": "Output",
5353
"proxy": "Proxy",
5454
"secure": "Secure",
55-
"data": "Data"
55+
"data": "Data",
56+
"setting": "Setting"
5657
},
5758
"tip": {
5859
"filter": "Filter Keyword",

console/atest-ui/src/locales/zh.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
"output": "输出",
4848
"proxy": "代理",
4949
"secure": "安全",
50-
"data": "数据"
50+
"data": "数据",
51+
"setting": "设置"
5152
},
5253
"tip": {
5354
"filter": "过滤",

console/atest-ui/src/theme.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,57 @@
1-
export default function setAsDarkTheme(darkMode: boolean) {
1+
import { API } from './views/net'
2+
3+
const themes: { [k: string]: any } = {}
4+
5+
export function getThemes() {
6+
return Object.keys(themes)
7+
}
8+
9+
interface Theme {
10+
key: string
11+
}
12+
13+
API.GetThemes(data => {
14+
data.data.forEach((theme: Theme) => {
15+
const key = theme.key
16+
API.GetTheme(key, (data: any) => {
17+
themes[key] = JSON.parse(data.message)
18+
19+
const theme = getTheme()
20+
if (theme) {
21+
setTheme(theme)
22+
}
23+
})
24+
})
25+
})
26+
27+
export function setTheme(theme: string | null) {
28+
if (!theme) {
29+
return
30+
}
31+
32+
const themeObj = themes[theme]
33+
if (themeObj) {
34+
applyTheme(themeObj)
35+
window.localStorage.setItem('theme', theme)
36+
}
37+
}
38+
39+
export function getTheme() {
40+
return window.localStorage.getItem('theme')
41+
}
42+
43+
const applyTheme = function (data: any) {
44+
if (data instanceof Object) {
45+
Object.keys(data).forEach((key) => {
46+
if (data[key] instanceof Object) {
47+
applyTheme(data[key])
48+
} else {
49+
document.documentElement.style.setProperty(key, data[key])
50+
}
51+
})
52+
}
53+
}
54+
55+
export function setAsDarkTheme(darkMode: boolean) {
256
document.documentElement.className = darkMode ? 'dark' : 'light'
357
}

console/atest-ui/src/views/TestCase.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ const renameTestCase = (name: string) => {
975975
</el-option>
976976
</el-select>
977977
</el-col>
978-
<el-col :span="19">
978+
<el-col :span="18">
979979
<el-autocomplete
980980
v-model="testCaseWithSuite.data.request.api"
981981
style="width: 100%"
@@ -990,7 +990,7 @@ const renameTestCase = (name: string) => {
990990
</template>
991991
</el-autocomplete>
992992
</el-col>
993-
<el-col :span="2" style="text-align-last: right;">
993+
<el-col :span="3" style="text-align-last: right;">
994994
<el-dropdown split-button type="primary"
995995
@click="sendRequest"
996996
v-loading="requestLoading"

console/atest-ui/src/views/net.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,16 @@ var DataQuery = (store: string, kind: string, currentDatabase: string, query: st
898898
.catch(errHandler)
899899
}
900900

901+
const GetThemes = (callback: (d: any) => void | null) => {
902+
return fetch(`/api/v1/themes`, {})
903+
.then(DefaultResponseProcess).then(callback)
904+
}
905+
906+
const GetTheme = (name: string, callback: (d: any) => void | null) => {
907+
return fetch(`/api/v1/themes/${name}`, {})
908+
.then(DefaultResponseProcess).then(callback)
909+
}
910+
901911
export const API = {
902912
DefaultResponseProcess,
903913
GetVersion,
@@ -911,5 +921,6 @@ export const API = {
911921
GetSecrets, DeleteSecret, CreateOrUpdateSecret,
912922
GetSuggestedAPIs, GetSwaggers,
913923
ReloadMockServer, GetMockConfig, SBOM, DataQuery, DataQueryAsync,
924+
GetThemes, GetTheme,
914925
getToken
915926
}

pkg/apispec/remote_swagger.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ func decompressData(dataFile string) (err error) {
9999
tarReader := tar.NewReader(gzipReader)
100100

101101
for {
102-
header, err := tarReader.Next()
102+
var header *tar.Header
103+
header, err = tarReader.Next()
103104
if err == io.EOF {
104105
break // 退出循环
105106
}
@@ -113,7 +114,10 @@ func decompressData(dataFile string) (err error) {
113114
continue
114115
}
115116

116-
destPath := filepath.Join(filepath.Dir(dataFile), filepath.Base(header.Name))
117+
destPath := filepath.Join(filepath.Dir(dataFile), strings.TrimPrefix(header.Name, filepath.Base(filepath.Dir(dataFile))))
118+
if err = os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil {
119+
return
120+
}
117121

118122
switch header.Typeflag {
119123
case tar.TypeReg:

pkg/server/remote_server.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ var (
6666
type server struct {
6767
UnimplementedRunnerServer
6868
UnimplementedDataServerServer
69+
UnimplementedThemeExtensionServer
70+
6971
loader testing.Writer
7072
storeWriterFactory testing.StoreWriterFactory
7173
configDir string
@@ -1284,6 +1286,35 @@ func (s *server) Query(ctx context.Context, query *DataQuery) (result *DataQuery
12841286
return
12851287
}
12861288

1289+
func (s *server) GetThemes(ctx context.Context, _ *Empty) (result *SimpleList, err error) {
1290+
loader := s.getLoader(ctx)
1291+
defer loader.Close()
1292+
1293+
result = &SimpleList{}
1294+
var themes []string
1295+
if themes, err = loader.GetThemes(); err == nil {
1296+
for _, theme := range themes {
1297+
result.Data = append(result.Data, &Pair{
1298+
Key: theme,
1299+
Value: "",
1300+
})
1301+
}
1302+
}
1303+
return
1304+
}
1305+
1306+
func (s *server) GetTheme(ctx context.Context, in *SimpleName) (result *CommonResult, err error) {
1307+
loader := s.getLoader(ctx)
1308+
defer loader.Close()
1309+
1310+
result = &CommonResult{}
1311+
result.Message, err = loader.GetTheme(in.Name)
1312+
if err != nil {
1313+
result.Message = fmt.Sprintf("failed to get theme: %v", err)
1314+
}
1315+
return
1316+
}
1317+
12871318
// implement the mock server
12881319

12891320
// Start starts the mock server

0 commit comments

Comments
 (0)