Skip to content

Commit e07a92e

Browse files
committed
feat!: combine base services with ping
1 parent 3d1e44c commit e07a92e

File tree

10 files changed

+167
-98
lines changed

10 files changed

+167
-98
lines changed

Diff for: components/Item.vue

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { BaseService } from '~/types'
88
99
const props = defineProps<BaseService>()
1010
11-
const type = capitalize(props.type || 'base')
12-
const component = defineAsyncComponent(() => import(`~/components/service/${type}.vue`))
11+
const component = props.type
12+
? defineAsyncComponent(() => import(`~/components/service/${capitalize(props.type!)}.vue`))
13+
: resolveComponent('ServiceBase')
1314
</script>

Diff for: components/service/Base.vue

-42
This file was deleted.

Diff for: components/service/Ping.vue

-23
This file was deleted.

Diff for: components/service/base/Icon.vue

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<template>
2+
<div :class="wrapClasses" :style="wrapStyles">
3+
<Icon v-if="props?.name" :name="props.name" :class="iconClasses" />
4+
<img v-else-if="props?.url" :src="props.url" alt="" :class="iconClasses">
5+
</div>
6+
</template>
7+
8+
<script setup lang="ts">
9+
import type { ServiceIcon } from '~/types'
10+
11+
const props = defineProps<ServiceIcon>()
12+
13+
const iconClasses = 'block h-full w-full'
14+
15+
const wrapClasses = computed(() => ({
16+
'bg-fg/5 dark:bg-fg/10': props?.wrap && !props?.background,
17+
'p-2': props?.wrap,
18+
[iconClasses]: true,
19+
}))
20+
21+
const wrapStyles = computed(() => ({
22+
background: props?.background,
23+
color: props?.color,
24+
}))
25+
</script>

Diff for: components/service/base/Index.vue

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<template>
2+
<div class="p-4 flex gap-4">
3+
<div class="flex-shrink-0 flex">
4+
<a :href="link" class="self-center w-16 h-16 overflow-hidden rounded-2xl border border-fg/10 dark:border-fg/15">
5+
<slot name="icon">
6+
<ServiceBaseIcon v-if="icon" v-bind="icon" />
7+
</slot>
8+
</a>
9+
</div>
10+
<div>
11+
<h3 class="text-lg mt-1 font-semibold line-clamp-1 flex gap-2 items-center">
12+
<slot name="title">
13+
<a :href="link">{{ title }}</a>
14+
</slot>
15+
<slot v-if="props?.status" name="status">
16+
<ServiceBaseStatus :ping="data?.ping" />
17+
</slot>
18+
</h3>
19+
20+
<p class="text-sm text-fg-dimmed line-clamp-1">
21+
<slot name="description">
22+
{{ description }}
23+
</slot>
24+
</p>
25+
</div>
26+
</div>
27+
</template>
28+
29+
<script setup lang="ts">
30+
import type { BaseService } from '~/types'
31+
import { useServiceData } from '~/composables/services'
32+
33+
const props = defineProps<BaseService>()
34+
const { data, pauseUpdate } = useServiceData<BaseService, { ping: { time: number, status: boolean } }>(props)
35+
36+
onBeforeUnmount(pauseUpdate)
37+
</script>

Diff for: components/service/base/Status.vue

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<template>
2+
<span class="relative inline-flex z-1 h-2.5 w-2.5 rounded-full bg-green-400" :class="color">
3+
<span class="absolute -z-1 inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75" :class="color" />
4+
</span>
5+
</template>
6+
7+
<script setup lang="ts">
8+
export interface Props {
9+
ping?: {
10+
status: boolean
11+
time: number
12+
}
13+
}
14+
15+
const props = defineProps<Props>()
16+
const color = computed(() => {
17+
if (!props.ping) {
18+
return 'bg-neutral-400'
19+
}
20+
21+
return props.ping.status ? 'bg-green-400' : 'bg-red-400'
22+
})
23+
</script>

Diff for: composables/services.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { BaseService } from '~/types'
2+
3+
export interface ServiceDataOptions {
4+
immediate?: boolean
5+
updateInterval?: number
6+
}
7+
8+
export function useServiceData<T extends BaseService, R>(service: T, options?: ServiceDataOptions) {
9+
const immediate = options?.immediate || true
10+
const updateInterval = (options?.updateInterval || 60) * 1000
11+
const type = service.type || 'base'
12+
13+
const { data, pending, status, refresh, execute } = useFetch<R>(`/api/services/${type}`, {
14+
immediate,
15+
query: { id: service.id },
16+
timeout: 15000,
17+
})
18+
19+
const { pause, resume } = useIntervalFn(refresh, updateInterval, { immediate })
20+
21+
return {
22+
data,
23+
pending,
24+
status,
25+
execute,
26+
pauseUpdate: pause,
27+
resumeUpdate: resume,
28+
}
29+
}

Diff for: server/api/services/base.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { BaseService } from '~/types'
2+
3+
export interface State {
4+
ping: {
5+
status: boolean
6+
time: number
7+
}
8+
}
9+
10+
export default defineEventHandler(async (event): Promise<State> => {
11+
const service = await getService<BaseService>(event)
12+
const state: State = {
13+
ping: {
14+
status: false,
15+
time: -1,
16+
},
17+
}
18+
19+
if (service?.status?.enabled) {
20+
try {
21+
const startTime = new Date().getTime()
22+
await $fetch(service.link, { timeout: 15000 })
23+
const endTime = new Date().getTime()
24+
25+
state.ping = {
26+
status: true,
27+
time: endTime - startTime,
28+
}
29+
} catch (e) {
30+
logger.error(e)
31+
}
32+
}
33+
34+
return state
35+
})

Diff for: server/api/services/ping.ts

-18
This file was deleted.

Diff for: types/services.d.ts

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1+
export interface ServiceStatus {
2+
enabled?: boolean
3+
interval?: number
4+
}
5+
6+
export interface ServiceIcon {
7+
url?: string
8+
name?: string
9+
wrap?: boolean
10+
background?: string
11+
color?: string
12+
}
13+
114
export interface BaseService {
215
id: string
316
type?: string
417
title: string
518
description?: string
619
link: string
7-
icon?: {
8-
url?: string
9-
name?: string
10-
wrap?: boolean
11-
background?: string
12-
color?: string
13-
}
20+
icon?: ServiceIcon
21+
status?: ServiceStatus
1422
options?: Record<string, string | number | boolean>
1523
secrets?: Record<string, string | number | boolean>
1624
}
17-
18-
export interface PingService extends BaseService {
19-
options?: {
20-
interval?: number
21-
}
22-
}

0 commit comments

Comments
 (0)