summaryrefslogtreecommitdiff
path: root/packages/frontend/src/widgets
diff options
context:
space:
mode:
authorMarie <Marie@kaifa.ch>2023-12-23 02:09:23 +0100
committerMarie <Marie@kaifa.ch>2023-12-23 02:09:23 +0100
commit5db583a3eb61d50de14d875ebf7ecef20490e313 (patch)
tree783dd43d2ac660c32e745a4485d499e9ddc43324 /packages/frontend/src/widgets
parentadd: Custom MOTDs (diff)
parentUpdate CHANGELOG.md (diff)
downloadsharkey-5db583a3eb61d50de14d875ebf7ecef20490e313.tar.gz
sharkey-5db583a3eb61d50de14d875ebf7ecef20490e313.tar.bz2
sharkey-5db583a3eb61d50de14d875ebf7ecef20490e313.zip
merge: upstream
Diffstat (limited to 'packages/frontend/src/widgets')
-rw-r--r--packages/frontend/src/widgets/WidgetActivity.chart.vue35
-rw-r--r--packages/frontend/src/widgets/WidgetActivity.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetAichan.vue3
-rw-r--r--packages/frontend/src/widgets/WidgetAiscript.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetAiscriptApp.vue6
-rw-r--r--packages/frontend/src/widgets/WidgetBirthdayFollowings.vue127
-rw-r--r--packages/frontend/src/widgets/WidgetButton.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetCalendar.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetClicker.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetClock.vue10
-rw-r--r--packages/frontend/src/widgets/WidgetDigitalClock.vue9
-rw-r--r--packages/frontend/src/widgets/WidgetFederation.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetInstanceCloud.vue12
-rw-r--r--packages/frontend/src/widgets/WidgetInstanceInfo.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetJobQueue.vue27
-rw-r--r--packages/frontend/src/widgets/WidgetMemo.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetNotifications.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetOnlineUsers.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetPhotos.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetPostForm.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetProfile.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetRss.vue10
-rw-r--r--packages/frontend/src/widgets/WidgetRssTicker.vue14
-rw-r--r--packages/frontend/src/widgets/WidgetSearch.vue48
-rw-r--r--packages/frontend/src/widgets/WidgetSlideshow.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetTimeline.vue4
-rw-r--r--packages/frontend/src/widgets/WidgetTrends.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetUnixClock.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetUserList.vue19
-rw-r--r--packages/frontend/src/widgets/index.ts2
-rw-r--r--packages/frontend/src/widgets/server-metric/cpu-mem.vue56
-rw-r--r--packages/frontend/src/widgets/server-metric/cpu.vue6
-rw-r--r--packages/frontend/src/widgets/server-metric/disk.vue10
-rw-r--r--packages/frontend/src/widgets/server-metric/mem.vue18
-rw-r--r--packages/frontend/src/widgets/server-metric/net.vue60
-rw-r--r--packages/frontend/src/widgets/server-metric/pie.vue6
36 files changed, 328 insertions, 186 deletions
diff --git a/packages/frontend/src/widgets/WidgetActivity.chart.vue b/packages/frontend/src/widgets/WidgetActivity.chart.vue
index 9cfd845ace..a207071324 100644
--- a/packages/frontend/src/widgets/WidgetActivity.chart.vue
+++ b/packages/frontend/src/widgets/WidgetActivity.chart.vue
@@ -34,18 +34,19 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
+import { ref } from 'vue';
const props = defineProps<{
activity: any[]
}>();
-let viewBoxX: number = $ref(147);
-let viewBoxY: number = $ref(60);
-let zoom: number = $ref(1);
-let pos: number = $ref(0);
-let pointsNote: any = $ref(null);
-let pointsReply: any = $ref(null);
-let pointsRenote: any = $ref(null);
-let pointsTotal: any = $ref(null);
+const viewBoxX = ref(147);
+const viewBoxY = ref(60);
+const zoom = ref(1);
+const pos = ref(0);
+const pointsNote = ref<any>(null);
+const pointsReply = ref<any>(null);
+const pointsRenote = ref<any>(null);
+const pointsTotal = ref<any>(null);
function dragListen(fn) {
window.addEventListener('mousemove', fn);
@@ -62,17 +63,17 @@ function dragClear(fn) {
function onMousedown(ev) {
const clickX = ev.clientX;
const clickY = ev.clientY;
- const baseZoom = zoom;
- const basePos = pos;
+ const baseZoom = zoom.value;
+ const basePos = pos.value;
// 動かした時
dragListen(me => {
let moveLeft = me.clientX - clickX;
let moveTop = me.clientY - clickY;
- zoom = Math.max(1, baseZoom + (-moveTop / 20));
- pos = Math.min(0, basePos + moveLeft);
- if (pos < -(((props.activity.length - 1) * zoom) - viewBoxX)) pos = -(((props.activity.length - 1) * zoom) - viewBoxX);
+ zoom.value = Math.max(1, baseZoom + (-moveTop / 20));
+ pos.value = Math.min(0, basePos + moveLeft);
+ if (pos.value < -(((props.activity.length - 1) * zoom.value) - viewBoxX.value)) pos.value = -(((props.activity.length - 1) * zoom.value) - viewBoxX.value);
render();
});
@@ -82,10 +83,10 @@ function render() {
const peak = Math.max(...props.activity.map(d => d.total));
if (peak !== 0) {
const activity = props.activity.slice().reverse();
- pointsNote = activity.map((d, i) => `${(i * zoom) + pos},${(1 - (d.notes / peak)) * viewBoxY}`).join(' ');
- pointsReply = activity.map((d, i) => `${(i * zoom) + pos},${(1 - (d.replies / peak)) * viewBoxY}`).join(' ');
- pointsRenote = activity.map((d, i) => `${(i * zoom) + pos},${(1 - (d.renotes / peak)) * viewBoxY}`).join(' ');
- pointsTotal = activity.map((d, i) => `${(i * zoom) + pos},${(1 - (d.total / peak)) * viewBoxY}`).join(' ');
+ pointsNote.value = activity.map((d, i) => `${(i * zoom.value) + pos.value},${(1 - (d.notes / peak)) * viewBoxY.value}`).join(' ');
+ pointsReply.value = activity.map((d, i) => `${(i * zoom.value) + pos.value},${(1 - (d.replies / peak)) * viewBoxY.value}`).join(' ');
+ pointsRenote.value = activity.map((d, i) => `${(i * zoom.value) + pos.value},${(1 - (d.renotes / peak)) * viewBoxY.value}`).join(' ');
+ pointsTotal.value = activity.map((d, i) => `${(i * zoom.value) + pos.value},${(1 - (d.total / peak)) * viewBoxY.value}`).join(' ');
}
}
</script>
diff --git a/packages/frontend/src/widgets/WidgetActivity.vue b/packages/frontend/src/widgets/WidgetActivity.vue
index 788a9f2c7b..b107a47d8c 100644
--- a/packages/frontend/src/widgets/WidgetActivity.vue
+++ b/packages/frontend/src/widgets/WidgetActivity.vue
@@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import XCalendar from './WidgetActivity.calendar.vue';
import XChart from './WidgetActivity.chart.vue';
import { GetFormResultType } from '@/scripts/form.js';
diff --git a/packages/frontend/src/widgets/WidgetAichan.vue b/packages/frontend/src/widgets/WidgetAichan.vue
index 76b35f6fed..fef026244c 100644
--- a/packages/frontend/src/widgets/WidgetAichan.vue
+++ b/packages/frontend/src/widgets/WidgetAichan.vue
@@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, onUnmounted, shallowRef } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
const name = 'ai';
@@ -72,5 +72,6 @@ defineExpose<WidgetComponentExpose>({
height: 350px;
border: none;
pointer-events: none;
+ color-scheme: light;
}
</style>
diff --git a/packages/frontend/src/widgets/WidgetAiscript.vue b/packages/frontend/src/widgets/WidgetAiscript.vue
index 8fb4ebe0f2..c17e9728a5 100644
--- a/packages/frontend/src/widgets/WidgetAiscript.vue
+++ b/packages/frontend/src/widgets/WidgetAiscript.vue
@@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
import { Interpreter, Parser, utils } from '@syuilo/aiscript';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import * as os from '@/os.js';
import MkContainer from '@/components/MkContainer.vue';
diff --git a/packages/frontend/src/widgets/WidgetAiscriptApp.vue b/packages/frontend/src/widgets/WidgetAiscriptApp.vue
index 53b6020ffc..10248a840a 100644
--- a/packages/frontend/src/widgets/WidgetAiscriptApp.vue
+++ b/packages/frontend/src/widgets/WidgetAiscriptApp.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, Ref, ref, watch } from 'vue';
import { Interpreter, Parser } from '@syuilo/aiscript';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import * as os from '@/os.js';
import { createAiScriptEnv } from '@/scripts/aiscript/api.js';
@@ -52,7 +52,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
const parser = new Parser();
const root = ref<AsUiRoot>();
-const components: Ref<AsUiComponent>[] = $ref([]);
+const components = ref<Ref<AsUiComponent>[]>([]);
async function run() {
const aiscript = new Interpreter({
@@ -60,7 +60,7 @@ async function run() {
storageKey: 'widget',
token: $i?.token,
}),
- ...registerAsUiLib(components, (_root) => {
+ ...registerAsUiLib(components.value, (_root) => {
root.value = _root.value;
}),
}, {
diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
new file mode 100644
index 0000000000..7c4455516d
--- /dev/null
+++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
@@ -0,0 +1,127 @@
+<!--
+SPDX-FileCopyrightText: syuilo and other misskey contributors
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkContainer :showHeader="widgetProps.showHeader" class="mkw-bdayfollowings">
+ <template #icon><i class="ti ti-cake"></i></template>
+ <template #header>{{ i18n.ts._widgets.birthdayFollowings }}</template>
+
+ <div :class="$style.bdayFRoot">
+ <MkLoading v-if="fetching"/>
+ <div v-else-if="users.length > 0" :class="$style.bdayFGrid">
+ <MkAvatar v-for="user in users" :key="user.id" :user="user.followee" link preview></MkAvatar>
+ </div>
+ <div v-else :class="$style.bdayFFallback">
+ <img :src="infoImageUrl" class="_ghost" :class="$style.bdayFFallbackImage"/>
+ <div>{{ i18n.ts.nothing }}</div>
+ </div>
+ </div>
+</MkContainer>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+import * as Misskey from 'misskey-js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { GetFormResultType } from '@/scripts/form.js';
+import MkContainer from '@/components/MkContainer.vue';
+import * as os from '@/os.js';
+import { useInterval } from '@/scripts/use-interval.js';
+import { i18n } from '@/i18n.js';
+import { infoImageUrl } from '@/instance.js';
+import { $i } from '@/account.js';
+
+const name = i18n.ts._widgets.birthdayFollowings;
+
+const widgetPropsDef = {
+ showHeader: {
+ type: 'boolean' as const,
+ default: true,
+ },
+};
+
+type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
+
+const props = defineProps<WidgetComponentProps<WidgetProps>>();
+const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
+
+const { widgetProps, configure } = useWidgetPropsManager(name,
+ widgetPropsDef,
+ props,
+ emit,
+);
+
+const users = ref<Misskey.entities.FollowingFolloweePopulated[]>([]);
+const fetching = ref(true);
+let lastFetchedAt = '1970-01-01';
+
+const fetch = () => {
+ if (!$i) {
+ users.value = [];
+ fetching.value = false;
+ return;
+ }
+
+ const lfAtD = new Date(lastFetchedAt);
+ lfAtD.setHours(0, 0, 0, 0);
+ const now = new Date();
+ now.setHours(0, 0, 0, 0);
+
+ if (now > lfAtD) {
+ os.api('users/following', {
+ limit: 18,
+ birthday: now.toISOString(),
+ userId: $i.id,
+ }).then(res => {
+ users.value = res;
+ fetching.value = false;
+ });
+
+ lastFetchedAt = now.toISOString();
+ }
+};
+
+useInterval(fetch, 1000 * 60, {
+ immediate: true,
+ afterMounted: true,
+});
+
+defineExpose<WidgetComponentExpose>({
+ name,
+ configure,
+ id: props.widget ? props.widget.id : null,
+});
+</script>
+
+<style lang="scss" module>
+.bdayFRoot {
+ overflow: hidden;
+ min-height: calc(calc(calc(50px * 3) - 8px) + calc(var(--margin) * 2));
+}
+.bdayFGrid {
+ display: grid;
+ grid-template-columns: repeat(6, 42px);
+ grid-template-rows: repeat(3, 42px);
+ place-content: center;
+ gap: 8px;
+ margin: var(--margin) auto;
+}
+
+.bdayFFallback {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.bdayFFallbackImage {
+ height: 96px;
+ width: auto;
+ max-width: 90%;
+ margin-bottom: 8px;
+ border-radius: var(--radius);
+}
+</style>
diff --git a/packages/frontend/src/widgets/WidgetButton.vue b/packages/frontend/src/widgets/WidgetButton.vue
index a7bdd4c49c..11082c1e3f 100644
--- a/packages/frontend/src/widgets/WidgetButton.vue
+++ b/packages/frontend/src/widgets/WidgetButton.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { Interpreter, Parser } from '@syuilo/aiscript';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import * as os from '@/os.js';
import { createAiScriptEnv } from '@/scripts/aiscript/api.js';
diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue
index 0ad166c6ba..b3f814a0a7 100644
--- a/packages/frontend/src/widgets/WidgetCalendar.vue
+++ b/packages/frontend/src/widgets/WidgetCalendar.vue
@@ -39,7 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import { i18n } from '@/i18n.js';
import { useInterval } from '@/scripts/use-interval.js';
diff --git a/packages/frontend/src/widgets/WidgetClicker.vue b/packages/frontend/src/widgets/WidgetClicker.vue
index 2b3b391165..aa49269017 100644
--- a/packages/frontend/src/widgets/WidgetClicker.vue
+++ b/packages/frontend/src/widgets/WidgetClicker.vue
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import MkClickerGame from '@/components/MkClickerGame.vue';
diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue
index e4ea2c97dd..22f053db59 100644
--- a/packages/frontend/src/widgets/WidgetClock.vue
+++ b/packages/frontend/src/widgets/WidgetClock.vue
@@ -29,8 +29,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { computed } from 'vue';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import MkAnalogClock from '@/components/MkAnalogClock.vue';
@@ -134,15 +134,15 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
emit,
);
-const tzAbbrev = $computed(() => (widgetProps.timezone === null
+const tzAbbrev = computed(() => (widgetProps.timezone === null
? timezones.find((tz) => tz.name.toLowerCase() === Intl.DateTimeFormat().resolvedOptions().timeZone.toLowerCase())?.abbrev
: timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.abbrev) ?? '?');
-const tzOffset = $computed(() => widgetProps.timezone === null
+const tzOffset = computed(() => widgetProps.timezone === null
? 0 - new Date().getTimezoneOffset()
: timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.offset ?? 0);
-const tzOffsetLabel = $computed(() => (tzOffset >= 0 ? '+' : '-') + Math.floor(tzOffset / 60).toString().padStart(2, '0') + ':' + (tzOffset % 60).toString().padStart(2, '0'));
+const tzOffsetLabel = computed(() => (tzOffset.value >= 0 ? '+' : '-') + Math.floor(tzOffset.value / 60).toString().padStart(2, '0') + ':' + (tzOffset.value % 60).toString().padStart(2, '0'));
defineExpose<WidgetComponentExpose>({
name,
diff --git a/packages/frontend/src/widgets/WidgetDigitalClock.vue b/packages/frontend/src/widgets/WidgetDigitalClock.vue
index 9ff5f8dcef..a4b90c49d3 100644
--- a/packages/frontend/src/widgets/WidgetDigitalClock.vue
+++ b/packages/frontend/src/widgets/WidgetDigitalClock.vue
@@ -14,7 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { computed } from 'vue';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import { timezones } from '@/scripts/timezones.js';
import MkDigitalClock from '@/components/MkDigitalClock.vue';
@@ -63,15 +64,15 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
emit,
);
-const tzAbbrev = $computed(() => (widgetProps.timezone === null
+const tzAbbrev = computed(() => (widgetProps.timezone === null
? timezones.find((tz) => tz.name.toLowerCase() === Intl.DateTimeFormat().resolvedOptions().timeZone.toLowerCase())?.abbrev
: timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.abbrev) ?? '?');
-const tzOffset = $computed(() => widgetProps.timezone === null
+const tzOffset = computed(() => widgetProps.timezone === null
? 0 - new Date().getTimezoneOffset()
: timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.offset ?? 0);
-const tzOffsetLabel = $computed(() => (tzOffset >= 0 ? '+' : '-') + Math.floor(tzOffset / 60).toString().padStart(2, '0') + ':' + (tzOffset % 60).toString().padStart(2, '0'));
+const tzOffsetLabel = computed(() => (tzOffset.value >= 0 ? '+' : '-') + Math.floor(tzOffset.value / 60).toString().padStart(2, '0') + ':' + (tzOffset.value % 60).toString().padStart(2, '0'));
defineExpose<WidgetComponentExpose>({
name,
diff --git a/packages/frontend/src/widgets/WidgetFederation.vue b/packages/frontend/src/widgets/WidgetFederation.vue
index e6ee590c15..605c24aaa3 100644
--- a/packages/frontend/src/widgets/WidgetFederation.vue
+++ b/packages/frontend/src/widgets/WidgetFederation.vue
@@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import MkMiniChart from '@/components/MkMiniChart.vue';
diff --git a/packages/frontend/src/widgets/WidgetInstanceCloud.vue b/packages/frontend/src/widgets/WidgetInstanceCloud.vue
index 4ae77e86fc..0fc96c0d35 100644
--- a/packages/frontend/src/widgets/WidgetInstanceCloud.vue
+++ b/packages/frontend/src/widgets/WidgetInstanceCloud.vue
@@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { shallowRef } from 'vue';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import MkTagCloud from '@/components/MkTagCloud.vue';
@@ -47,8 +47,8 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
emit,
);
-let cloud = $shallowRef<InstanceType<typeof MkTagCloud> | null>();
-let activeInstances = $shallowRef(null);
+const cloud = shallowRef<InstanceType<typeof MkTagCloud> | null>();
+const activeInstances = shallowRef(null);
function onInstanceClick(i) {
os.pageWindow(`/instance-info/${i.host}`);
@@ -59,8 +59,8 @@ useInterval(() => {
sort: '+latestRequestReceivedAt',
limit: 25,
}).then(res => {
- activeInstances = res;
- if (cloud) cloud.update();
+ activeInstances.value = res;
+ if (cloud.value) cloud.value.update();
});
}, 1000 * 60 * 3, {
immediate: true,
diff --git a/packages/frontend/src/widgets/WidgetInstanceInfo.vue b/packages/frontend/src/widgets/WidgetInstanceInfo.vue
index 3fa811fa13..2133deb363 100644
--- a/packages/frontend/src/widgets/WidgetInstanceInfo.vue
+++ b/packages/frontend/src/widgets/WidgetInstanceInfo.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import { host } from '@/config.js';
import { instance } from '@/instance.js';
diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue
index 09c27bfdec..c54682bb87 100644
--- a/packages/frontend/src/widgets/WidgetJobQueue.vue
+++ b/packages/frontend/src/widgets/WidgetJobQueue.vue
@@ -51,13 +51,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onUnmounted, reactive } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { onUnmounted, reactive, ref } from 'vue';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import { useStream } from '@/stream.js';
import number from '@/filters/number.js';
import * as sound from '@/scripts/sound.js';
import { deepClone } from '@/scripts/clone.js';
+import { defaultStore } from '@/store.js';
const name = 'jobQueue';
@@ -99,7 +100,18 @@ const current = reactive({
},
});
const prev = reactive({} as typeof current);
-const jammedSound = sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1);
+const jammedAudioBuffer = ref<AudioBuffer | null>(null);
+const jammedSoundNodePlaying = ref<boolean>(false);
+
+if (defaultStore.state.sound_masterVolume) {
+ sound.loadAudio({
+ type: 'syuilo/queue-jammed',
+ volume: 1,
+ }).then(buf => {
+ if (!buf) throw new Error('[WidgetJobQueue] Failed to initialize AudioBuffer');
+ jammedAudioBuffer.value = buf;
+ });
+}
for (const domain of ['inbox', 'deliver']) {
prev[domain] = deepClone(current[domain]);
@@ -113,8 +125,13 @@ const onStats = (stats) => {
current[domain].waiting = stats[domain].waiting;
current[domain].delayed = stats[domain].delayed;
- if (current[domain].waiting > 0 && widgetProps.sound && jammedSound.paused) {
- jammedSound.play();
+ if (current[domain].waiting > 0 && widgetProps.sound && jammedAudioBuffer.value && !jammedSoundNodePlaying.value) {
+ const soundNode = sound.createSourceNode(jammedAudioBuffer.value, 1);
+ if (soundNode) {
+ jammedSoundNodePlaying.value = true;
+ soundNode.onended = () => jammedSoundNodePlaying.value = false;
+ soundNode.start();
+ }
}
}
};
diff --git a/packages/frontend/src/widgets/WidgetMemo.vue b/packages/frontend/src/widgets/WidgetMemo.vue
index c2d5ef566c..8e9e67ade5 100644
--- a/packages/frontend/src/widgets/WidgetMemo.vue
+++ b/packages/frontend/src/widgets/WidgetMemo.vue
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, watch } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import { defaultStore } from '@/store.js';
diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue
index 6e38b8308c..e858741aa1 100644
--- a/packages/frontend/src/widgets/WidgetNotifications.vue
+++ b/packages/frontend/src/widgets/WidgetNotifications.vue
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { defineAsyncComponent } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import XNotifications from '@/components/MkNotifications.vue';
diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue
index 46fe991f37..0a6fec7f2e 100644
--- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue
+++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import * as os from '@/os.js';
import { useInterval } from '@/scripts/use-interval.js';
diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue
index c07f2dd262..808f023174 100644
--- a/packages/frontend/src/widgets/WidgetPhotos.vue
+++ b/packages/frontend/src/widgets/WidgetPhotos.vue
@@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onUnmounted, ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import { useStream } from '@/stream.js';
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
diff --git a/packages/frontend/src/widgets/WidgetPostForm.vue b/packages/frontend/src/widgets/WidgetPostForm.vue
index 320b47a4ff..9979ae256e 100644
--- a/packages/frontend/src/widgets/WidgetPostForm.vue
+++ b/packages/frontend/src/widgets/WidgetPostForm.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkPostForm from '@/components/MkPostForm.vue';
diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue
index fc54af2d71..3ff57bab86 100644
--- a/packages/frontend/src/widgets/WidgetProfile.vue
+++ b/packages/frontend/src/widgets/WidgetProfile.vue
@@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import { $i } from '@/account.js';
import { userPage } from '@/filters/user.js';
diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue
index 1ada9f4be8..a718548731 100644
--- a/packages/frontend/src/widgets/WidgetRss.vue
+++ b/packages/frontend/src/widgets/WidgetRss.vue
@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, watch, computed } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import { url as base } from '@/config.js';
@@ -72,7 +72,7 @@ const fetchEndpoint = computed(() => {
url.searchParams.set('url', widgetProps.url);
return url;
});
-let intervalClear = $ref<(() => void) | undefined>();
+const intervalClear = ref<(() => void) | undefined>();
const tick = () => {
if (document.visibilityState === 'hidden' && rawItems.value.length !== 0) return;
@@ -87,10 +87,10 @@ const tick = () => {
watch(() => fetchEndpoint, tick);
watch(() => widgetProps.refreshIntervalSec, () => {
- if (intervalClear) {
- intervalClear();
+ if (intervalClear.value) {
+ intervalClear.value();
}
- intervalClear = useInterval(tick, Math.max(10000, widgetProps.refreshIntervalSec * 1000), {
+ intervalClear.value = useInterval(tick, Math.max(10000, widgetProps.refreshIntervalSec * 1000), {
immediate: true,
afterMounted: true,
});
diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue
index 790f94f7c3..607bb2f0ab 100644
--- a/packages/frontend/src/widgets/WidgetRssTicker.vue
+++ b/packages/frontend/src/widgets/WidgetRssTicker.vue
@@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, watch, computed } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import MarqueeText from '@/components/MkMarquee.vue';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
@@ -101,9 +101,9 @@ const fetchEndpoint = computed(() => {
url.searchParams.set('url', widgetProps.url);
return url;
});
-let intervalClear = $ref<(() => void) | undefined>();
+const intervalClear = ref<(() => void) | undefined>();
-let key = $ref(0);
+const key = ref(0);
const tick = () => {
if (document.visibilityState === 'hidden' && rawItems.value.length !== 0) return;
@@ -113,16 +113,16 @@ const tick = () => {
.then(feed => {
rawItems.value = feed.items ?? [];
fetching.value = false;
- key++;
+ key.value++;
});
};
watch(() => fetchEndpoint, tick);
watch(() => widgetProps.refreshIntervalSec, () => {
- if (intervalClear) {
- intervalClear();
+ if (intervalClear.value) {
+ intervalClear.value();
}
- intervalClear = useInterval(tick, Math.max(10000, widgetProps.refreshIntervalSec * 1000), {
+ intervalClear.value = useInterval(tick, Math.max(10000, widgetProps.refreshIntervalSec * 1000), {
immediate: true,
afterMounted: true,
});
diff --git a/packages/frontend/src/widgets/WidgetSearch.vue b/packages/frontend/src/widgets/WidgetSearch.vue
index 979341e1ae..c114707b23 100644
--- a/packages/frontend/src/widgets/WidgetSearch.vue
+++ b/packages/frontend/src/widgets/WidgetSearch.vue
@@ -15,8 +15,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, defineAsyncComponent, onMounted } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { defineAsyncComponent, ref } from 'vue';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import MkInput from '@/components/MkInput.vue';
import MkContainer from '@/components/MkContainer.vue';
import { i18n } from '@/i18n.js';
@@ -54,14 +54,12 @@ function onInputKeydown(evt: KeyboardEvent) {
const router = useRouter();
-let key = $ref(0);
-let searchQuery = $ref('');
-let notePagination = $ref();
-let searchOrigin = $ref('combined');
-let user = $ref(null);
-let isLocalOnly = $ref(false);
-let order = $ref(true);
-let filetype = $ref(null);
+let key = ref(0);
+let searchQuery = ref('');
+let notePagination = ref();
+let isLocalOnly = ref(false);
+let order = ref(true);
+let filetype = ref<null | string>(null);
function options(ev) {
os.popupMenu([{
@@ -74,7 +72,7 @@ function options(ev) {
icon: 'ph-image ph-bold ph-lg',
text: 'With Images',
action: () => {
- filetype = 'image';
+ filetype.value = 'image';
},
},
{
@@ -82,7 +80,7 @@ function options(ev) {
icon: 'ph-music-notes-simple ph-bold ph-lg',
text: 'With Audios',
action: () => {
- filetype = 'audio';
+ filetype.value = 'audio';
},
},
{
@@ -90,20 +88,14 @@ function options(ev) {
icon: 'ph-video ph-bold ph-lg',
text: 'With Videos',
action: () => {
- filetype = 'video';
+ filetype.value = 'video';
},
}],
}], ev.currentTarget ?? ev.target);
}
-function selectUser() {
- os.selectUser().then(_user => {
- user = _user;
- });
-}
-
async function search() {
- const query = searchQuery.toString().trim();
+ const query = searchQuery.value.toString().trim();
if (query == null || query === '') return;
@@ -125,24 +117,24 @@ async function search() {
return;
}
- notePagination = {
+ notePagination.value = {
endpoint: 'notes/search',
limit: 10,
params: {
query: searchQuery,
- userId: user ? user.id : null,
- order: order ? 'desc' : 'asc',
- filetype: filetype,
+ userId: null,
+ order: order.value ? 'desc' : 'asc',
+ filetype: filetype.value,
},
};
- if (isLocalOnly) notePagination.params.host = '.';
+ if (isLocalOnly.value) notePagination.value.params.host = '.';
- key++;
+ key.value++;
os.popup(defineAsyncComponent(() => import('@/components/SkSearchResultWindow.vue')), {
- noteKey: key,
- notePagination: notePagination,
+ noteKey: key.value,
+ notePagination: notePagination.value,
}, {
}, 'closed');
}
diff --git a/packages/frontend/src/widgets/WidgetSlideshow.vue b/packages/frontend/src/widgets/WidgetSlideshow.vue
index 82b6246add..eccb9a00bf 100644
--- a/packages/frontend/src/widgets/WidgetSlideshow.vue
+++ b/packages/frontend/src/widgets/WidgetSlideshow.vue
@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, ref, shallowRef } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import * as os from '@/os.js';
import { useInterval } from '@/scripts/use-interval.js';
diff --git a/packages/frontend/src/widgets/WidgetTimeline.vue b/packages/frontend/src/widgets/WidgetTimeline.vue
index 0ebffa105e..070466f476 100644
--- a/packages/frontend/src/widgets/WidgetTimeline.vue
+++ b/packages/frontend/src/widgets/WidgetTimeline.vue
@@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import * as os from '@/os.js';
import MkContainer from '@/components/MkContainer.vue';
@@ -136,7 +136,7 @@ const choose = async (ev) => {
text: i18n.ts._timelines.global,
icon: 'ph-globe-hemisphere-west ph-bold ph-lg',
action: () => { setSrc('global'); },
- }, antennaItems.length > 0 ? null : undefined, ...antennaItems, listItems.length > 0 ? null : undefined, ...listItems], ev.currentTarget ?? ev.target).then(() => {
+ }, antennaItems.length > 0 ? { type: 'divider' } : undefined, ...antennaItems, listItems.length > 0 ? { type: 'divider' } : undefined, ...listItems], ev.currentTarget ?? ev.target).then(() => {
menuOpened.value = false;
});
};
diff --git a/packages/frontend/src/widgets/WidgetTrends.vue b/packages/frontend/src/widgets/WidgetTrends.vue
index ea7b9078f3..738cd70b03 100644
--- a/packages/frontend/src/widgets/WidgetTrends.vue
+++ b/packages/frontend/src/widgets/WidgetTrends.vue
@@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import MkMiniChart from '@/components/MkMiniChart.vue';
diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue
index 33585cd721..35f29b5e21 100644
--- a/packages/frontend/src/widgets/WidgetUnixClock.vue
+++ b/packages/frontend/src/widgets/WidgetUnixClock.vue
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onUnmounted, ref, watch } from 'vue';
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
const name = 'unixClock';
diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue
index 159318c2ca..f5c1d2d3a3 100644
--- a/packages/frontend/src/widgets/WidgetUserList.vue
+++ b/packages/frontend/src/widgets/WidgetUserList.vue
@@ -24,7 +24,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
+import { ref } from 'vue';
+import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import { GetFormResultType } from '@/scripts/form.js';
import MkContainer from '@/components/MkContainer.vue';
import * as os from '@/os.js';
@@ -57,9 +58,9 @@ const { widgetProps, configure, save } = useWidgetPropsManager(name,
emit,
);
-let list = $ref();
-let users = $ref([]);
-let fetching = $ref(true);
+const list = ref();
+const users = ref([]);
+const fetching = ref(true);
async function chooseList() {
const lists = await os.api('users/lists/list');
@@ -79,19 +80,19 @@ async function chooseList() {
const fetch = () => {
if (widgetProps.listId == null) {
- fetching = false;
+ fetching.value = false;
return;
}
os.api('users/lists/show', {
listId: widgetProps.listId,
}).then(_list => {
- list = _list;
+ list.value = _list;
os.api('users/show', {
- userIds: list.userIds,
+ userIds: list.value.userIds,
}).then(_users => {
- users = _users;
- fetching = false;
+ users.value = _users;
+ fetching.value = false;
});
});
};
diff --git a/packages/frontend/src/widgets/index.ts b/packages/frontend/src/widgets/index.ts
index ae3bd09c86..b783d783bc 100644
--- a/packages/frontend/src/widgets/index.ts
+++ b/packages/frontend/src/widgets/index.ts
@@ -34,6 +34,7 @@ export default function(app: App) {
app.component('WidgetUserList', defineAsyncComponent(() => import('./WidgetUserList.vue')));
app.component('WidgetClicker', defineAsyncComponent(() => import('./WidgetClicker.vue')));
app.component('WidgetSearch', defineAsyncComponent(() => import('./WidgetSearch.vue')));
+ app.component('WidgetBirthdayFollowings', defineAsyncComponent(() => import('./WidgetBirthdayFollowings.vue')));
}
export const widgets = [
@@ -65,4 +66,5 @@ export const widgets = [
'userList',
'clicker',
'search',
+ 'birthdayFollowings',
];
diff --git a/packages/frontend/src/widgets/server-metric/cpu-mem.vue b/packages/frontend/src/widgets/server-metric/cpu-mem.vue
index c656d75429..9196ae209f 100644
--- a/packages/frontend/src/widgets/server-metric/cpu-mem.vue
+++ b/packages/frontend/src/widgets/server-metric/cpu-mem.vue
@@ -75,7 +75,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, onBeforeUnmount } from 'vue';
+import { onMounted, onBeforeUnmount, ref } from 'vue';
import { v4 as uuid } from 'uuid';
const props = defineProps<{
@@ -83,23 +83,23 @@ const props = defineProps<{
meta: any
}>();
-let viewBoxX: number = $ref(50);
-let viewBoxY: number = $ref(30);
-let stats: any[] = $ref([]);
+const viewBoxX = ref<number>(50);
+const viewBoxY = ref<number>(30);
+const stats = ref<any[]>([]);
const cpuGradientId = uuid();
const cpuMaskId = uuid();
const memGradientId = uuid();
const memMaskId = uuid();
-let cpuPolylinePoints: string = $ref('');
-let memPolylinePoints: string = $ref('');
-let cpuPolygonPoints: string = $ref('');
-let memPolygonPoints: string = $ref('');
-let cpuHeadX: any = $ref(null);
-let cpuHeadY: any = $ref(null);
-let memHeadX: any = $ref(null);
-let memHeadY: any = $ref(null);
-let cpuP: string = $ref('');
-let memP: string = $ref('');
+const cpuPolylinePoints = ref<string>('');
+const memPolylinePoints = ref<string>('');
+const cpuPolygonPoints = ref<string>('');
+const memPolygonPoints = ref<string>('');
+const cpuHeadX = ref<any>(null);
+const cpuHeadY = ref<any>(null);
+const memHeadX = ref<any>(null);
+const memHeadY = ref<any>(null);
+const cpuP = ref<string>('');
+const memP = ref<string>('');
onMounted(() => {
props.connection.on('stats', onStats);
@@ -115,24 +115,24 @@ onBeforeUnmount(() => {
});
function onStats(connStats) {
- stats.push(connStats);
- if (stats.length > 50) stats.shift();
+ stats.value.push(connStats);
+ if (stats.value.length > 50) stats.value.shift();
- let cpuPolylinePointsStats = stats.map((s, i) => [viewBoxX - ((stats.length - 1) - i), (1 - s.cpu) * viewBoxY]);
- let memPolylinePointsStats = stats.map((s, i) => [viewBoxX - ((stats.length - 1) - i), (1 - (s.mem.active / props.meta.mem.total)) * viewBoxY]);
- cpuPolylinePoints = cpuPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
- memPolylinePoints = memPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
+ let cpuPolylinePointsStats = stats.value.map((s, i) => [viewBoxX.value - ((stats.value.length - 1) - i), (1 - s.cpu) * viewBoxY.value]);
+ let memPolylinePointsStats = stats.value.map((s, i) => [viewBoxX.value - ((stats.value.length - 1) - i), (1 - (s.mem.active / props.meta.mem.total)) * viewBoxY.value]);
+ cpuPolylinePoints.value = cpuPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
+ memPolylinePoints.value = memPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
- cpuPolygonPoints = `${viewBoxX - (stats.length - 1)},${viewBoxY} ${cpuPolylinePoints} ${viewBoxX},${viewBoxY}`;
- memPolygonPoints = `${viewBoxX - (stats.length - 1)},${viewBoxY} ${memPolylinePoints} ${viewBoxX},${viewBoxY}`;
+ cpuPolygonPoints.value = `${viewBoxX.value - (stats.value.length - 1)},${viewBoxY.value} ${cpuPolylinePoints.value} ${viewBoxX.value},${viewBoxY.value}`;
+ memPolygonPoints.value = `${viewBoxX.value - (stats.value.length - 1)},${viewBoxY.value} ${memPolylinePoints.value} ${viewBoxX.value},${viewBoxY.value}`;
- cpuHeadX = cpuPolylinePointsStats.at(-1)![0];
- cpuHeadY = cpuPolylinePointsStats.at(-1)![1];
- memHeadX = memPolylinePointsStats.at(-1)![0];
- memHeadY = memPolylinePointsStats.at(-1)![1];
+ cpuHeadX.value = cpuPolylinePointsStats.at(-1)![0];
+ cpuHeadY.value = cpuPolylinePointsStats.at(-1)![1];
+ memHeadX.value = memPolylinePointsStats.at(-1)![0];
+ memHeadY.value = memPolylinePointsStats.at(-1)![1];
- cpuP = (connStats.cpu * 100).toFixed(0);
- memP = (connStats.mem.active / props.meta.mem.total * 100).toFixed(0);
+ cpuP.value = (connStats.cpu * 100).toFixed(0);
+ memP.value = (connStats.mem.active / props.meta.mem.total * 100).toFixed(0);
}
function onStatsLog(statsLog) {
diff --git a/packages/frontend/src/widgets/server-metric/cpu.vue b/packages/frontend/src/widgets/server-metric/cpu.vue
index 65da16a632..cffbdb27ce 100644
--- a/packages/frontend/src/widgets/server-metric/cpu.vue
+++ b/packages/frontend/src/widgets/server-metric/cpu.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, onBeforeUnmount } from 'vue';
+import { onMounted, onBeforeUnmount, ref } from 'vue';
import XPie from './pie.vue';
const props = defineProps<{
@@ -23,10 +23,10 @@ const props = defineProps<{
meta: any
}>();
-let usage: number = $ref(0);
+const usage = ref<number>(0);
function onStats(stats) {
- usage = stats.cpu;
+ usage.value = stats.cpu;
}
onMounted(() => {
diff --git a/packages/frontend/src/widgets/server-metric/disk.vue b/packages/frontend/src/widgets/server-metric/disk.vue
index b9774da0cf..18f8560265 100644
--- a/packages/frontend/src/widgets/server-metric/disk.vue
+++ b/packages/frontend/src/widgets/server-metric/disk.vue
@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { } from 'vue';
+import { computed } from 'vue';
import XPie from './pie.vue';
import bytes from '@/filters/bytes.js';
@@ -24,10 +24,10 @@ const props = defineProps<{
meta: any; // TODO
}>();
-const usage = $computed(() => props.meta.fs.used / props.meta.fs.total);
-const total = $computed(() => props.meta.fs.total);
-const used = $computed(() => props.meta.fs.used);
-const available = $computed(() => props.meta.fs.total - props.meta.fs.used);
+const usage = computed(() => props.meta.fs.used / props.meta.fs.total);
+const total = computed(() => props.meta.fs.total);
+const used = computed(() => props.meta.fs.used);
+const available = computed(() => props.meta.fs.total - props.meta.fs.used);
</script>
<style lang="scss" scoped>
diff --git a/packages/frontend/src/widgets/server-metric/mem.vue b/packages/frontend/src/widgets/server-metric/mem.vue
index 5a57ef6e1e..118fd68fe8 100644
--- a/packages/frontend/src/widgets/server-metric/mem.vue
+++ b/packages/frontend/src/widgets/server-metric/mem.vue
@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, onBeforeUnmount } from 'vue';
+import { onMounted, onBeforeUnmount, ref } from 'vue';
import XPie from './pie.vue';
import bytes from '@/filters/bytes.js';
@@ -25,16 +25,16 @@ const props = defineProps<{
meta: any
}>();
-let usage: number = $ref(0);
-let total: number = $ref(0);
-let used: number = $ref(0);
-let free: number = $ref(0);
+const usage = ref<number>(0);
+const total = ref<number>(0);
+const used = ref<number>(0);
+const free = ref<number>(0);
function onStats(stats) {
- usage = stats.mem.active / props.meta.mem.total;
- total = props.meta.mem.total;
- used = stats.mem.active;
- free = total - used;
+ usage.value = stats.mem.active / props.meta.mem.total;
+ total.value = props.meta.mem.total;
+ used.value = stats.mem.active;
+ free.value = total.value - used.value;
}
onMounted(() => {
diff --git a/packages/frontend/src/widgets/server-metric/net.vue b/packages/frontend/src/widgets/server-metric/net.vue
index 5593128660..e6a8bfc22a 100644
--- a/packages/frontend/src/widgets/server-metric/net.vue
+++ b/packages/frontend/src/widgets/server-metric/net.vue
@@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, onBeforeUnmount } from 'vue';
+import { onMounted, onBeforeUnmount, ref } from 'vue';
import bytes from '@/filters/bytes.js';
const props = defineProps<{
@@ -57,19 +57,19 @@ const props = defineProps<{
meta: any
}>();
-let viewBoxX: number = $ref(50);
-let viewBoxY: number = $ref(30);
-let stats: any[] = $ref([]);
-let inPolylinePoints: string = $ref('');
-let outPolylinePoints: string = $ref('');
-let inPolygonPoints: string = $ref('');
-let outPolygonPoints: string = $ref('');
-let inHeadX: any = $ref(null);
-let inHeadY: any = $ref(null);
-let outHeadX: any = $ref(null);
-let outHeadY: any = $ref(null);
-let inRecent: number = $ref(0);
-let outRecent: number = $ref(0);
+const viewBoxX = ref<number>(50);
+const viewBoxY = ref<number>(30);
+const stats = ref<any[]>([]);
+const inPolylinePoints = ref<string>('');
+const outPolylinePoints = ref<string>('');
+const inPolygonPoints = ref<string>('');
+const outPolygonPoints = ref<string>('');
+const inHeadX = ref<any>(null);
+const inHeadY = ref<any>(null);
+const outHeadX = ref<any>(null);
+const outHeadY = ref<any>(null);
+const inRecent = ref<number>(0);
+const outRecent = ref<number>(0);
onMounted(() => {
props.connection.on('stats', onStats);
@@ -85,27 +85,27 @@ onBeforeUnmount(() => {
});
function onStats(connStats) {
- stats.push(connStats);
- if (stats.length > 50) stats.shift();
+ stats.value.push(connStats);
+ if (stats.value.length > 50) stats.value.shift();
- const inPeak = Math.max(1024 * 64, Math.max(...stats.map(s => s.net.rx)));
- const outPeak = Math.max(1024 * 64, Math.max(...stats.map(s => s.net.tx)));
+ const inPeak = Math.max(1024 * 64, Math.max(...stats.value.map(s => s.net.rx)));
+ const outPeak = Math.max(1024 * 64, Math.max(...stats.value.map(s => s.net.tx)));
- let inPolylinePointsStats = stats.map((s, i) => [viewBoxX - ((stats.length - 1) - i), (1 - (s.net.rx / inPeak)) * viewBoxY]);
- let outPolylinePointsStats = stats.map((s, i) => [viewBoxX - ((stats.length - 1) - i), (1 - (s.net.tx / outPeak)) * viewBoxY]);
- inPolylinePoints = inPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
- outPolylinePoints = outPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
+ let inPolylinePointsStats = stats.value.map((s, i) => [viewBoxX.value - ((stats.value.length - 1) - i), (1 - (s.net.rx / inPeak)) * viewBoxY.value]);
+ let outPolylinePointsStats = stats.value.map((s, i) => [viewBoxX.value - ((stats.value.length - 1) - i), (1 - (s.net.tx / outPeak)) * viewBoxY.value]);
+ inPolylinePoints.value = inPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
+ outPolylinePoints.value = outPolylinePointsStats.map(xy => `${xy[0]},${xy[1]}`).join(' ');
- inPolygonPoints = `${viewBoxX - (stats.length - 1)},${viewBoxY} ${inPolylinePoints} ${viewBoxX},${viewBoxY}`;
- outPolygonPoints = `${viewBoxX - (stats.length - 1)},${viewBoxY} ${outPolylinePoints} ${viewBoxX},${viewBoxY}`;
+ inPolygonPoints.value = `${viewBoxX.value - (stats.value.length - 1)},${viewBoxY.value} ${inPolylinePoints.value} ${viewBoxX.value},${viewBoxY.value}`;
+ outPolygonPoints.value = `${viewBoxX.value - (stats.value.length - 1)},${viewBoxY.value} ${outPolylinePoints.value} ${viewBoxX.value},${viewBoxY.value}`;
- inHeadX = inPolylinePointsStats.at(-1)![0];
- inHeadY = inPolylinePointsStats.at(-1)![1];
- outHeadX = outPolylinePointsStats.at(-1)![0];
- outHeadY = outPolylinePointsStats.at(-1)![1];
+ inHeadX.value = inPolylinePointsStats.at(-1)![0];
+ inHeadY.value = inPolylinePointsStats.at(-1)![1];
+ outHeadX.value = outPolylinePointsStats.at(-1)![0];
+ outHeadY.value = outPolylinePointsStats.at(-1)![1];
- inRecent = connStats.net.rx;
- outRecent = connStats.net.tx;
+ inRecent.value = connStats.net.rx;
+ outRecent.value = connStats.net.tx;
}
function onStatsLog(statsLog) {
diff --git a/packages/frontend/src/widgets/server-metric/pie.vue b/packages/frontend/src/widgets/server-metric/pie.vue
index c8a1496101..fd18a6a4f2 100644
--- a/packages/frontend/src/widgets/server-metric/pie.vue
+++ b/packages/frontend/src/widgets/server-metric/pie.vue
@@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { } from 'vue';
+import { computed } from 'vue';
const props = defineProps<{
value: number;
@@ -36,8 +36,8 @@ const props = defineProps<{
const r = 0.45;
-const color = $computed(() => `hsl(${180 - (props.value * 180)}, 80%, 70%)`);
-const strokeDashoffset = $computed(() => (1 - props.value) * (Math.PI * (r * 2)));
+const color = computed(() => `hsl(${180 - (props.value * 180)}, 80%, 70%)`);
+const strokeDashoffset = computed(() => (1 - props.value) * (Math.PI * (r * 2)));
</script>
<style lang="scss" module>