mirror of
https://github.com/directus/directus.git
synced 2026-02-10 10:55:17 -05:00
Add latency store / indicator (#392)
* Add latency store and track latency based on user tracking * Add latency store to dehydration logic * Add signal icons * Add latency-indicator component * Set correct size of latency spinner
This commit is contained in:
23
src/components/v-icon/custom-icons/signal_wifi_1_bar.vue
Normal file
23
src/components/v-icon/custom-icons/signal_wifi_1_bar.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template functional>
|
||||
<svg
|
||||
viewBox="0 0 48 48"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="2"
|
||||
>
|
||||
<path
|
||||
fill-opacity=".3"
|
||||
d="M24.02 42.98L47.28 14c-.9-.68-9.85-8-23.28-8S1.62 13.32.72 14l23.26 28.98.02.02.02-.02z"
|
||||
/>
|
||||
<path d="M0 0h48v48H0z" fill="none" />
|
||||
<path
|
||||
d="M13.34 29.72l10.65 13.27.01.01.01-.01 10.65-13.27C34.13 29.31 30.06 26 24 26s-10.13 3.31-10.66 3.72z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {};
|
||||
</script>
|
||||
23
src/components/v-icon/custom-icons/signal_wifi_2_bar.vue
Normal file
23
src/components/v-icon/custom-icons/signal_wifi_2_bar.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template functional>
|
||||
<svg
|
||||
viewBox="0 0 48 48"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="2"
|
||||
>
|
||||
<path
|
||||
fill-opacity=".3"
|
||||
d="M24.02 42.98L47.28 14c-.9-.68-9.85-8-23.28-8S1.62 13.32.72 14l23.26 28.98.02.02.02-.02z"
|
||||
/>
|
||||
<path d="M0 0h48v48H0z" fill="none" />
|
||||
<path
|
||||
d="M7.07 21.91l16.92 21.07.01.02.02-.02 16.92-21.07C40.08 21.25 33.62 16 24 16c-9.63 0-16.08 5.25-16.93 5.91z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {};
|
||||
</script>
|
||||
23
src/components/v-icon/custom-icons/signal_wifi_3_bar.vue
Normal file
23
src/components/v-icon/custom-icons/signal_wifi_3_bar.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template functional>
|
||||
<svg
|
||||
viewBox="0 0 48 48"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="2"
|
||||
>
|
||||
<path
|
||||
fill-opacity=".3"
|
||||
d="M24.02 42.98L47.28 14c-.9-.68-9.85-8-23.28-8S1.62 13.32.72 14l23.26 28.98.02.02.02-.02z"
|
||||
/>
|
||||
<path d="M0 0h48v48H0z" fill="none" />
|
||||
<path
|
||||
d="M9.58 25.03l14.41 17.95.01.02.01-.02 14.41-17.95C37.7 24.47 32.2 20 24 20s-13.7 4.47-14.42 5.03z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {};
|
||||
</script>
|
||||
@@ -12,13 +12,27 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
import CustomIconBox from './custom-icons/box.vue';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
const customIcons: string[] = ['box'];
|
||||
import CustomIconBox from './custom-icons/box.vue';
|
||||
import CustomIconSignalWifi1Bar from './custom-icons/signal_wifi_1_bar.vue';
|
||||
import CustomIconSignalWifi2Bar from './custom-icons/signal_wifi_2_bar.vue';
|
||||
import CustomIconSignalWifi3Bar from './custom-icons/signal_wifi_3_bar.vue';
|
||||
|
||||
const customIcons: string[] = [
|
||||
'box',
|
||||
'signal_wifi_1_bar',
|
||||
'signal_wifi_2_bar',
|
||||
'signal_wifi_3_bar',
|
||||
];
|
||||
|
||||
export default defineComponent({
|
||||
components: { CustomIconBox },
|
||||
components: {
|
||||
CustomIconBox,
|
||||
CustomIconSignalWifi1Bar,
|
||||
CustomIconSignalWifi2Bar,
|
||||
CustomIconSignalWifi3Bar,
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
@@ -50,7 +64,8 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const customIconName = computed<string | null>(() => {
|
||||
if (customIcons.includes(props.name)) return `custom-icon-${props.name}`;
|
||||
if (customIcons.includes(props.name))
|
||||
return `custom-icon-${props.name}`.replace(/_/g, '-');
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useRequestsStore } from '@/stores/requests/';
|
||||
import { useCollectionPresetsStore } from '@/stores/collection-presets/';
|
||||
import { useSettingsStore } from '@/stores/settings/';
|
||||
import { useProjectsStore } from '@/stores/projects/';
|
||||
import { useLatencyStore } from '@/stores/latency';
|
||||
|
||||
type GenericStore = {
|
||||
id: string;
|
||||
@@ -24,6 +25,7 @@ export function useStores(
|
||||
useCollectionPresetsStore,
|
||||
useSettingsStore,
|
||||
useProjectsStore,
|
||||
useLatencyStore,
|
||||
]
|
||||
) {
|
||||
return stores.map((useStore) => useStore()) as GenericStore[];
|
||||
|
||||
4
src/stores/latency/index.ts
Normal file
4
src/stores/latency/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { useLatencyStore } from './latency';
|
||||
|
||||
export { useLatencyStore };
|
||||
export default useLatencyStore;
|
||||
18
src/stores/latency/latency.ts
Normal file
18
src/stores/latency/latency.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createStore } from 'pinia';
|
||||
|
||||
type Latency = {
|
||||
latency: number;
|
||||
timestamp: Date;
|
||||
};
|
||||
|
||||
export const useLatencyStore = createStore({
|
||||
id: 'latencyStore',
|
||||
state: () => ({
|
||||
latency: [] as Latency[],
|
||||
}),
|
||||
actions: {
|
||||
async dehydrate() {
|
||||
this.reset();
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createStore } from 'pinia';
|
||||
import { useProjectsStore } from '@/stores/projects';
|
||||
import api from '@/api';
|
||||
import { useLatencyStore } from '@/stores/latency';
|
||||
|
||||
import { User } from './types';
|
||||
|
||||
@@ -43,12 +44,22 @@ export const useUserStore = createStore({
|
||||
},
|
||||
async trackPage(page: string) {
|
||||
const projectsStore = useProjectsStore();
|
||||
const latencyStore = useLatencyStore();
|
||||
const currentProjectKey = projectsStore.state.currentProjectKey;
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
await api.patch(`/${currentProjectKey}/users/me/tracking/page`, {
|
||||
last_page: page,
|
||||
});
|
||||
|
||||
const end = Date.now();
|
||||
|
||||
latencyStore.state.latency.push({
|
||||
timestamp: new Date(),
|
||||
latency: end - start,
|
||||
});
|
||||
|
||||
if (this.state.currentUser) {
|
||||
this.state.currentUser.last_page = page;
|
||||
}
|
||||
|
||||
4
src/views/private/components/latency-indicator/index.ts
Normal file
4
src/views/private/components/latency-indicator/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import LatencyIndicator from './latency-indicator.vue';
|
||||
|
||||
export { LatencyIndicator };
|
||||
export default LatencyIndicator;
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="latency-indicator">
|
||||
<v-progress-circular indeterminate v-if="!lastLatency" />
|
||||
<v-icon v-else :name="icon" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
import useLatencyStore from '@/stores/latency';
|
||||
import { sortBy } from 'lodash';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const latencyStore = useLatencyStore();
|
||||
|
||||
const lastLatency = computed(() => {
|
||||
const sorted = sortBy(latencyStore.state.latency, ['timestamp']);
|
||||
return sorted[sorted.length - 1];
|
||||
});
|
||||
|
||||
const icon = computed<string>(() => {
|
||||
const { latency } = lastLatency.value;
|
||||
if (latency <= 750) return 'signal_wifi_4_bar';
|
||||
else if (latency > 750 && latency <= 1250) return 'signal_wifi_3_bar';
|
||||
else if (latency > 1250 && latency <= 2000) return 'signal_wifi_2_bar';
|
||||
return 'signal_wifi_1_bar';
|
||||
});
|
||||
|
||||
return { icon, lastLatency };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-progress-circular {
|
||||
--v-progress-circular-size: 23px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div class="project-chooser">
|
||||
<button class="toggle" :disabled="projects.length === 1" @click="active = !active">
|
||||
<latency-indicator />
|
||||
{{ currentProject.name }}
|
||||
</button>
|
||||
<transition-expand>
|
||||
@@ -30,8 +31,10 @@
|
||||
import { defineComponent, toRefs, ref } from '@vue/composition-api';
|
||||
import { useProjectsStore } from '@/stores/projects';
|
||||
import router from '@/router';
|
||||
import LatencyIndicator from '../latency-indicator';
|
||||
|
||||
export default defineComponent({
|
||||
components: { LatencyIndicator },
|
||||
setup() {
|
||||
const projectsStore = useProjectsStore();
|
||||
const { projects, currentProjectKey } = toRefs(projectsStore.state);
|
||||
@@ -72,10 +75,16 @@ export default defineComponent({
|
||||
background-color: var(--background-normal-alt);
|
||||
|
||||
.toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
padding: 0 20px;
|
||||
text-align: left;
|
||||
|
||||
.latency-indicator {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.options-wrapper {
|
||||
|
||||
Reference in New Issue
Block a user