Merge branch 'develop' into fetch

This commit is contained in:
tamaina 2023-01-03 14:09:34 +00:00
commit 560c1c2128
139 changed files with 519 additions and 1012 deletions

View File

@ -20,6 +20,9 @@ You should also include the user name that made the change.
- You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic - You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic
- 新たに動的なPagesを作ることはできなくなりました - 新たに動的なPagesを作ることはできなくなりました
- 代わりに今後AiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能の実装を予定しています。 - 代わりに今後AiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能の実装を予定しています。
- AiScriptが0.12.0にアップデートされました
- 0.12.0の変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120
- 0.12.0未満のプラグインは読み込むことはできません
- iOS15以下のデバイスはサポートされなくなりました - iOS15以下のデバイスはサポートされなくなりました
- API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました - API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました
- 絵文字画像を表示するには、`<instance host>/emoji/<emoji name>.webp`にリクエストすると画像が返ります。 - 絵文字画像を表示するには、`<instance host>/emoji/<emoji name>.webp`にリクエストすると画像が返ります。
@ -27,6 +30,7 @@ You should also include the user name that made the change.
- remote: `https://p1.a9z.dev/emoji/syuilo_birth_present@mk.f72u.net.webp` - remote: `https://p1.a9z.dev/emoji/syuilo_birth_present@mk.f72u.net.webp`
- API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました - API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました
- API: `user`エンティティに`avatarColor`および`bannerColor`プロパティが含まれなくなりました - API: `user`エンティティに`avatarColor`および`bannerColor`プロパティが含まれなくなりました
- API: `instance`エンティティに`latestStatus`、`lastCommunicatedAt`、`latestRequestSentAt`プロパティが含まれなくなりました
### Improvements ### Improvements
- Push notification of Antenna note @tamaina - Push notification of Antenna note @tamaina
@ -41,6 +45,7 @@ You should also include the user name that made the change.
- Server: delete outdated notifications regularly to improve db performance @syuilo - Server: delete outdated notifications regularly to improve db performance @syuilo
- Server: delete outdated hard-mutes regularly to improve db performance @syuilo - Server: delete outdated hard-mutes regularly to improve db performance @syuilo
- Server: delete outdated notes of antenna regularly to improve db performance @syuilo - Server: delete outdated notes of antenna regularly to improve db performance @syuilo
- Server: improve activitypub deliver performance @syuilo
- Client: use tabler-icons instead of fontawesome to better design @syuilo - Client: use tabler-icons instead of fontawesome to better design @syuilo
- Client: Add new gabber kick sounds (thanks for noizenecio) - Client: Add new gabber kick sounds (thanks for noizenecio)
- Client: Add link to user RSS feed in profile menu @ssmucny - Client: Add link to user RSS feed in profile menu @ssmucny

View File

@ -167,7 +167,6 @@ annotation: "注釈"
federation: "連合" federation: "連合"
instances: "インスタンス" instances: "インスタンス"
registeredAt: "初観測" registeredAt: "初観測"
latestRequestSentAt: "直近のリクエスト送信"
latestRequestReceivedAt: "直近のリクエスト受信" latestRequestReceivedAt: "直近のリクエスト受信"
latestStatus: "直近のステータス" latestStatus: "直近のステータス"
storageUsage: "ストレージ使用量" storageUsage: "ストレージ使用量"

View File

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.0.0-beta.17", "version": "13.0.0-beta.20",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -0,0 +1,11 @@
export class removeLatestRequestSentAt1672703171386 {
name = 'removeLatestRequestSentAt1672703171386'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "latestRequestSentAt"`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "instance" ADD "latestRequestSentAt" TIMESTAMP WITH TIME ZONE`);
}
}

View File

@ -0,0 +1,11 @@
export class removeLastCommunicatedAt1672704017999 {
name = 'removeLastCommunicatedAt1672704017999'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "lastCommunicatedAt"`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "instance" ADD "lastCommunicatedAt" TIMESTAMP WITH TIME ZONE NOT NULL`);
}
}

View File

@ -0,0 +1,11 @@
export class removeLatestStatus1672704136584 {
name = 'removeLatestStatus1672704136584'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "latestStatus"`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "instance" ADD "latestStatus" integer`);
}
}

View File

@ -37,7 +37,6 @@
"@nestjs/testing": "9.2.1", "@nestjs/testing": "9.2.1",
"@peertube/http-signature": "1.7.0", "@peertube/http-signature": "1.7.0",
"@sinonjs/fake-timers": "10.0.2", "@sinonjs/fake-timers": "10.0.2",
"@syuilo/aiscript": "0.11.1",
"accepts": "^1.3.8", "accepts": "^1.3.8",
"ajv": "8.11.2", "ajv": "8.11.2",
"archiver": "5.3.1", "archiver": "5.3.1",

View File

@ -22,7 +22,7 @@ export class FederatedInstanceService {
} }
@bindThis @bindThis
public async registerOrFetchInstanceDoc(host: string): Promise<Instance> { public async fetch(host: string): Promise<Instance> {
host = this.utilityService.toPuny(host); host = this.utilityService.toPuny(host);
const cached = this.cache.get(host); const cached = this.cache.get(host);
@ -35,7 +35,6 @@ export class FederatedInstanceService {
id: this.idService.genId(), id: this.idService.genId(),
host, host,
caughtAt: new Date(), caughtAt: new Date(),
lastCommunicatedAt: new Date(),
}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0])); }).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
this.cache.set(host, i); this.cache.set(host, i);
@ -45,4 +44,17 @@ export class FederatedInstanceService {
return index; return index;
} }
} }
@bindThis
public async updateCachePartial(host: string, data: Partial<Instance>): Promise<void> {
host = this.utilityService.toPuny(host);
const cached = this.cache.get(host);
if (cached == null) return;
this.cache.set(host, {
...cached,
...data,
});
}
} }

View File

@ -428,7 +428,7 @@ export class NoteCreateService {
// Register host // Register host
if (this.userEntityService.isRemoteUser(user)) { if (this.userEntityService.isRemoteUser(user)) {
this.federatedInstanceService.registerOrFetchInstanceDoc(user.host).then(i => { this.federatedInstanceService.fetch(user.host).then(i => {
this.instancesRepository.increment({ id: i.id }, 'notesCount', 1); this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
this.instanceChart.updateNote(i.host, note, true); this.instanceChart.updateNote(i.host, note, true);
}); });

View File

@ -100,7 +100,7 @@ export class NoteDeleteService {
this.perUserNotesChart.update(user, note, false); this.perUserNotesChart.update(user, note, false);
if (this.userEntityService.isRemoteUser(user)) { if (this.userEntityService.isRemoteUser(user)) {
this.federatedInstanceService.registerOrFetchInstanceDoc(user.host).then(i => { this.federatedInstanceService.fetch(user.host).then(i => {
this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1); this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1);
this.instanceChart.updateNote(i.host, note, false); this.instanceChart.updateNote(i.host, note, false);
}); });

View File

@ -205,12 +205,12 @@ export class UserFollowingService {
//#region Update instance stats //#region Update instance stats
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
this.federatedInstanceService.registerOrFetchInstanceDoc(follower.host).then(i => { this.federatedInstanceService.fetch(follower.host).then(i => {
this.instancesRepository.increment({ id: i.id }, 'followingCount', 1); this.instancesRepository.increment({ id: i.id }, 'followingCount', 1);
this.instanceChart.updateFollowing(i.host, true); this.instanceChart.updateFollowing(i.host, true);
}); });
} else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { } else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
this.federatedInstanceService.registerOrFetchInstanceDoc(followee.host).then(i => { this.federatedInstanceService.fetch(followee.host).then(i => {
this.instancesRepository.increment({ id: i.id }, 'followersCount', 1); this.instancesRepository.increment({ id: i.id }, 'followersCount', 1);
this.instanceChart.updateFollowers(i.host, true); this.instanceChart.updateFollowers(i.host, true);
}); });
@ -323,12 +323,12 @@ export class UserFollowingService {
//#region Update instance stats //#region Update instance stats
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
this.federatedInstanceService.registerOrFetchInstanceDoc(follower.host).then(i => { this.federatedInstanceService.fetch(follower.host).then(i => {
this.instancesRepository.decrement({ id: i.id }, 'followingCount', 1); this.instancesRepository.decrement({ id: i.id }, 'followingCount', 1);
this.instanceChart.updateFollowing(i.host, false); this.instanceChart.updateFollowing(i.host, false);
}); });
} else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { } else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
this.federatedInstanceService.registerOrFetchInstanceDoc(followee.host).then(i => { this.federatedInstanceService.fetch(followee.host).then(i => {
this.instancesRepository.decrement({ id: i.id }, 'followersCount', 1); this.instancesRepository.decrement({ id: i.id }, 'followersCount', 1);
this.instanceChart.updateFollowers(i.host, false); this.instanceChart.updateFollowers(i.host, false);
}); });

View File

@ -348,7 +348,7 @@ export class ApPersonService implements OnModuleInit {
} }
// Register host // Register host
this.federatedInstanceService.registerOrFetchInstanceDoc(host).then(i => { this.federatedInstanceService.fetch(host).then(i => {
this.instancesRepository.increment({ id: i.id }, 'usersCount', 1); this.instancesRepository.increment({ id: i.id }, 'usersCount', 1);
this.instanceChart.newUser(i.host); this.instanceChart.newUser(i.host);
this.fetchInstanceMetadataService.fetchInstanceMetadata(i); this.fetchInstanceMetadataService.fetchInstanceMetadata(i);

View File

@ -86,7 +86,7 @@ export default class FederationChart extends Chart<typeof schema> {
.where(`instance.host IN (${ subInstancesQuery.getQuery() })`) .where(`instance.host IN (${ subInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts }) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere('instance.isSuspended = false') .andWhere('instance.isSuspended = false')
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) .andWhere('instance.isNotResponding = false')
.getRawOne() .getRawOne()
.then(x => parseInt(x.count, 10)), .then(x => parseInt(x.count, 10)),
this.instancesRepository.createQueryBuilder('instance') this.instancesRepository.createQueryBuilder('instance')
@ -94,7 +94,7 @@ export default class FederationChart extends Chart<typeof schema> {
.where(`instance.host IN (${ pubInstancesQuery.getQuery() })`) .where(`instance.host IN (${ pubInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts }) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere('instance.isSuspended = false') .andWhere('instance.isSuspended = false')
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) .andWhere('instance.isNotResponding = false')
.getRawOne() .getRawOne()
.then(x => parseInt(x.count, 10)), .then(x => parseInt(x.count, 10)),
]); ]);

View File

@ -7,8 +7,8 @@ import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import type { Instance } from '@/models/entities/Instance.js'; import type { Instance } from '@/models/entities/Instance.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable() @Injectable()
export class InstanceEntityService { export class InstanceEntityService {
@ -33,8 +33,6 @@ export class InstanceEntityService {
notesCount: instance.notesCount, notesCount: instance.notesCount,
followingCount: instance.followingCount, followingCount: instance.followingCount,
followersCount: instance.followersCount, followersCount: instance.followersCount,
latestRequestSentAt: instance.latestRequestSentAt ? instance.latestRequestSentAt.toISOString() : null,
lastCommunicatedAt: instance.lastCommunicatedAt.toISOString(),
isNotResponding: instance.isNotResponding, isNotResponding: instance.isNotResponding,
isSuspended: instance.isSuspended, isSuspended: instance.isSuspended,
isBlocked: meta.blockedHosts.includes(instance.host), isBlocked: meta.blockedHosts.includes(instance.host),

View File

@ -59,22 +59,6 @@ export class Instance {
}) })
public followersCount: number; public followersCount: number;
/**
*
*/
@Column('timestamp with time zone', {
nullable: true,
})
public latestRequestSentAt: Date | null;
/**
* HTTPステータスコード
*/
@Column('integer', {
nullable: true,
})
public latestStatus: number | null;
/** /**
* *
*/ */
@ -83,12 +67,6 @@ export class Instance {
}) })
public latestRequestReceivedAt: Date | null; public latestRequestReceivedAt: Date | null;
/**
*
*/
@Column('timestamp with time zone')
public lastCommunicatedAt: Date;
/** /**
* *
*/ */

View File

@ -32,16 +32,6 @@ export const packedFederationInstanceSchema = {
type: 'number', type: 'number',
optional: false, nullable: false, optional: false, nullable: false,
}, },
latestRequestSentAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
lastCommunicatedAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
isNotResponding: { isNotResponding: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,

View File

@ -15,10 +15,10 @@ import ApRequestChart from '@/core/chart/charts/ap-request.js';
import FederationChart from '@/core/chart/charts/federation.js'; import FederationChart from '@/core/chart/charts/federation.js';
import { StatusError } from '@/misc/status-error.js'; import { StatusError } from '@/misc/status-error.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js'; import { QueueLoggerService } from '../QueueLoggerService.js';
import type Bull from 'bull'; import type Bull from 'bull';
import type { DeliverJobData } from '../types.js'; import type { DeliverJobData } from '../types.js';
import { bindThis } from '@/decorators.js';
@Injectable() @Injectable()
export class DeliverProcessorService { export class DeliverProcessorService {
@ -48,7 +48,6 @@ export class DeliverProcessorService {
) { ) {
this.logger = this.queueLoggerService.logger.createSubLogger('deliver'); this.logger = this.queueLoggerService.logger.createSubLogger('deliver');
this.suspendedHostsCache = new Cache<Instance[]>(1000 * 60 * 60); this.suspendedHostsCache = new Cache<Instance[]>(1000 * 60 * 60);
this.latest = null;
} }
@bindThis @bindThis
@ -76,20 +75,18 @@ export class DeliverProcessorService {
} }
try { try {
if (this.latest !== (this.latest = JSON.stringify(job.data.content, null, 2))) {
this.logger.debug(`delivering ${this.latest}`);
}
await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content); await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content);
// Update stats // Update stats
this.federatedInstanceService.registerOrFetchInstanceDoc(host).then(i => { this.federatedInstanceService.fetch(host).then(i => {
this.instancesRepository.update(i.id, { if (i.isNotResponding) {
latestRequestSentAt: new Date(), this.instancesRepository.update(i.id, {
latestStatus: 200, isNotResponding: false,
lastCommunicatedAt: new Date(), });
isNotResponding: false, this.federatedInstanceService.updateCachePartial(host, {
}); isNotResponding: false,
});
}
this.fetchInstanceMetadataService.fetchInstanceMetadata(i); this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
@ -100,13 +97,16 @@ export class DeliverProcessorService {
return 'Success'; return 'Success';
} catch (res) { } catch (res) {
// Update stats // Update stats
this.federatedInstanceService.registerOrFetchInstanceDoc(host).then(i => { this.federatedInstanceService.fetch(host).then(i => {
this.instancesRepository.update(i.id, { if (!i.isNotResponding) {
latestRequestSentAt: new Date(), this.instancesRepository.update(i.id, {
latestStatus: res instanceof StatusError ? res.statusCode : null, isNotResponding: true,
isNotResponding: true, });
}); this.federatedInstanceService.updateCachePartial(host, {
isNotResponding: true,
});
}
this.instanceChart.requestSent(i.host, false); this.instanceChart.requestSent(i.host, false);
this.apRequestChart.deliverFail(); this.apRequestChart.deliverFail();
@ -114,17 +114,17 @@ export class DeliverProcessorService {
}); });
if (res instanceof StatusError) { if (res instanceof StatusError) {
// 4xx // 4xx
if (res.isClientError) { if (res.isClientError) {
// HTTPステータスコード4xxはクライアントエラーであり、それはつまり // HTTPステータスコード4xxはクライアントエラーであり、それはつまり
// 何回再送しても成功することはないということなのでエラーにはしないでおく // 何回再送しても成功することはないということなのでエラーにはしないでおく
return `${res.statusCode} ${res.statusMessage}`; return `${res.statusCode} ${res.statusMessage}`;
} }
// 5xx etc. // 5xx etc.
throw `${res.statusCode} ${res.statusMessage}`; throw `${res.statusCode} ${res.statusMessage}`;
} else { } else {
// DNS error, socket error, timeout ... // DNS error, socket error, timeout ...
throw res; throw res;
} }
} }

View File

@ -176,10 +176,12 @@ export class InboxProcessorService {
} }
// Update stats // Update stats
this.federatedInstanceService.registerOrFetchInstanceDoc(authUser.user.host).then(i => { this.federatedInstanceService.fetch(authUser.user.host).then(i => {
this.instancesRepository.update(i.id, { this.instancesRepository.update(i.id, {
latestRequestReceivedAt: new Date(), latestRequestReceivedAt: new Date(),
lastCommunicatedAt: new Date(), isNotResponding: false,
});
this.federatedInstanceService.updateCachePartial(host, {
isNotResponding: false, isNotResponding: false,
}); });

View File

@ -64,8 +64,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; case '-followers': query.orderBy('instance.followersCount', 'ASC'); break;
case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break;
case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break;
case '+lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'DESC'); break; case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC'); break;
case '-lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'ASC'); break; case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC'); break;
default: query.orderBy('instance.id', 'DESC'); break; default: query.orderBy('instance.id', 'DESC'); break;
} }

View File

@ -139,10 +139,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.noSuchUser); throw new ApiError(meta.errors.noSuchUser);
} }
if (me == null && ip != null) { if (user.host == null) {
this.perUserPvChart.commitByVisitor(user, ip); if (me == null && ip != null) {
} else if (me && me.id !== user.id) { this.perUserPvChart.commitByVisitor(user, ip);
this.perUserPvChart.commitByUser(user, me.id); } else if (me && me.id !== user.id) {
this.perUserPvChart.commitByUser(user, me.id);
}
} }
return await this.userEntityService.pack(user, me, { return await this.userEntityService.pack(user, me, {

View File

@ -11,7 +11,7 @@
"@rollup/plugin-alias": "4.0.2", "@rollup/plugin-alias": "4.0.2",
"@rollup/plugin-json": "6.0.0", "@rollup/plugin-json": "6.0.0",
"@rollup/pluginutils": "5.0.2", "@rollup/pluginutils": "5.0.2",
"@syuilo/aiscript": "0.11.1", "@syuilo/aiscript": "0.12.0",
"@tabler/icons": "^1.118.0", "@tabler/icons": "^1.118.0",
"@vitejs/plugin-vue": "4.0.0", "@vitejs/plugin-vue": "4.0.0",
"@vue/compiler-sfc": "3.2.45", "@vue/compiler-sfc": "3.2.45",

View File

@ -23,7 +23,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref, shallowRef } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import XWindow from '@/components/MkWindow.vue'; import XWindow from '@/components/MkWindow.vue';
import MkTextarea from '@/components/form/textarea.vue'; import MkTextarea from '@/components/form/textarea.vue';
@ -40,7 +40,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const uiWindow = ref<InstanceType<typeof XWindow>>(); const uiWindow = shallowRef<InstanceType<typeof XWindow>>();
const comment = ref(props.initialComment || ''); const comment = ref(props.initialComment || '');
function send() { function send() {

View File

@ -16,9 +16,9 @@
</li> </li>
</ol> </ol>
<ol v-else-if="emojis.length > 0" ref="suggests" class="emojis"> <ol v-else-if="emojis.length > 0" ref="suggests" class="emojis">
<li v-for="emoji in emojis" tabindex="-1" :key="emoji.emoji" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> <li v-for="emoji in emojis" :key="emoji.emoji" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
<div class="emoji"> <div class="emoji">
<MkEmoji :emoji="emoji.emoji" /> <MkEmoji :emoji="emoji.emoji"/>
</div> </div>
<!-- eslint-disable-next-line vue/no-v-html --> <!-- eslint-disable-next-line vue/no-v-html -->
<span v-if="q" class="name" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span> <span v-if="q" class="name" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span>
@ -35,7 +35,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { markRaw, ref, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'; import { markRaw, ref, shallowRef, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
import sanitizeHtml from 'sanitize-html';
import contains from '@/scripts/contains'; import contains from '@/scripts/contains';
import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base';
import { acct } from '@/filters/user'; import { acct } from '@/filters/user';
@ -45,7 +46,6 @@ import { defaultStore } from '@/store';
import { emojilist } from '@/scripts/emojilist'; import { emojilist } from '@/scripts/emojilist';
import { instance } from '@/instance'; import { instance } from '@/instance';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import sanitizeHtml from 'sanitize-html';
type EmojiDef = { type EmojiDef = {
emoji: string; emoji: string;
@ -136,7 +136,7 @@ const emit = defineEmits<{
}>(); }>();
const suggests = ref<Element>(); const suggests = ref<Element>();
const rootEl = ref<HTMLDivElement>(); const rootEl = shallowRef<HTMLDivElement>();
const fetching = ref(true); const fetching = ref(true);
const users = ref<any[]>([]); const users = ref<any[]>([]);

View File

@ -47,8 +47,8 @@ const emit = defineEmits<{
(ev: 'click', payload: MouseEvent): void; (ev: 'click', payload: MouseEvent): void;
}>(); }>();
let el = $ref<HTMLElement | null>(null); let el = $shallowRef<HTMLElement | null>(null);
let ripples = $ref<HTMLElement | null>(null); let ripples = $shallowRef<HTMLElement | null>(null);
onMounted(() => { onMounted(() => {
if (props.autofocus) { if (props.autofocus) {

View File

@ -6,7 +6,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'; import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch } from 'vue';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
@ -42,7 +42,7 @@ const emit = defineEmits<{
const available = ref(false); const available = ref(false);
const captchaEl = ref<HTMLDivElement | undefined>(); const captchaEl = shallowRef<HTMLDivElement | undefined>();
const variable = computed(() => { const variable = computed(() => {
switch (props.provider) { switch (props.provider) {
@ -62,7 +62,7 @@ const src = computed(() => {
} }
}); });
const scriptId = computed(() => `script-${props.provider}`) const scriptId = computed(() => `script-${props.provider}`);
const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown as Captcha); const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown as Captcha);

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="cbbedffa"> <div class="cbbedffa">
<canvas ref="chartEl"></canvas> <canvas ref="chartEl"></canvas>
<MkChartLegend ref="legendEl" style="margin-top: 8px;"/>
<div v-if="fetching" class="fetching"> <div v-if="fetching" class="fetching">
<MkLoading/> <MkLoading/>
</div> </div>
@ -13,9 +14,8 @@
id-denylist violation when setting it. This is causing about 60+ lint issues. id-denylist violation when setting it. This is causing about 60+ lint issues.
As this is part of Chart.js's API it makes sense to disable the check here. As this is part of Chart.js's API it makes sense to disable the check here.
*/ */
import { onMounted, ref, watch, PropType, onUnmounted } from 'vue'; import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import 'chartjs-adapter-date-fns';
import { enUS } from 'date-fns/locale'; import { enUS } from 'date-fns/locale';
import gradient from 'chartjs-plugin-gradient'; import gradient from 'chartjs-plugin-gradient';
import * as os from '@/os'; import * as os from '@/os';
@ -25,6 +25,8 @@ import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color'; import { alpha } from '@/scripts/color';
import date from '@/filters/date'; import date from '@/filters/date';
import { initChart } from '@/scripts/init-chart'; import { initChart } from '@/scripts/init-chart';
import { chartLegend } from '@/scripts/chart-legend';
import MkChartLegend from '@/components/MkChartLegend.vue';
initChart(); initChart();
@ -68,6 +70,8 @@ const props = defineProps({
}, },
}); });
let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>();
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
const negate = arr => arr.map(x => -x); const negate = arr => arr.map(x => -x);
@ -102,7 +106,7 @@ let chartData: {
}[]; }[];
} = null; } = null;
const chartEl = ref<HTMLCanvasElement>(null); const chartEl = shallowRef<HTMLCanvasElement>(null);
const fetching = ref(true); const fetching = ref(true);
const getDate = (ago: number) => { const getDate = (ago: number) => {
@ -221,11 +225,7 @@ const render = () => {
}, },
plugins: { plugins: {
legend: { legend: {
display: props.detailed, display: false,
position: 'bottom',
labels: {
boxWidth: 16,
},
}, },
tooltip: { tooltip: {
enabled: false, enabled: false,
@ -265,7 +265,7 @@ const render = () => {
gradient, gradient,
}, },
}, },
plugins: [chartVLine(vLineColor)], plugins: [chartVLine(vLineColor), ...(props.detailed ? [chartLegend(legendEl)] : [])],
}); });
}; };

View File

@ -0,0 +1,75 @@
<template>
<div :class="$style.root">
<button v-for="item in items" class="_button item" :class="{ disabled: item.hidden }" @click="onClick(item)">
<span class="box" :style="{ background: chart.config.type === 'line' ? item.strokeStyle?.toString() : item.fillStyle?.toString() }"></span>
{{ item.text }}
</button>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue';
import { Chart, LegendItem } from 'chart.js';
const props = defineProps({
});
let chart = $shallowRef<Chart>();
let items = $shallowRef<LegendItem[]>([]);
function update(_chart: Chart, _items: LegendItem[]) {
chart = _chart,
items = _items;
}
function onClick(item: LegendItem) {
if (chart == null) return;
const { type } = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item
chart.toggleDataVisibility(item.index);
} else {
chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex));
}
chart.update();
}
defineExpose({
update,
});
</script>
<style lang="scss" module>
.root {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
&:global {
> .item {
font-size: 85%;
padding: 4px 12px 4px 8px;
border: solid 1px var(--divider);
border-radius: 999px;
&:hover {
border-color: var(--inputBorderHover);
}
&.disabled {
text-decoration: line-through;
opacity: 0.6;
}
> .box {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 100%;
vertical-align: -10%;
}
}
}
}
</style>

View File

@ -22,7 +22,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
let rootEl = $ref<HTMLDivElement>(); let rootEl = $shallowRef<HTMLDivElement>();
let zIndex = $ref<number>(os.claimZIndex('high')); let zIndex = $ref<number>(os.claimZIndex('high'));

View File

@ -50,8 +50,8 @@ const props = defineProps<{
}>(); }>();
const imgUrl = getProxiedImageUrl(props.file.url); const imgUrl = getProxiedImageUrl(props.file.url);
let dialogEl = $ref<InstanceType<typeof XModalWindow>>(); let dialogEl = $shallowRef<InstanceType<typeof XModalWindow>>();
let imgEl = $ref<HTMLImageElement>(); let imgEl = $shallowRef<HTMLImageElement>();
let cropper: Cropper | null = null; let cropper: Cropper | null = null;
let loading = $ref(true); let loading = $ref(true);

View File

@ -39,7 +39,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'; import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/form/input.vue'; import MkInput from '@/components/form/input.vue';
@ -94,7 +94,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const modal = ref<InstanceType<typeof MkModal>>(); const modal = shallowRef<InstanceType<typeof MkModal>>();
const inputValue = ref(props.input?.default || null); const inputValue = ref(props.input?.default || null);
const selectedValue = ref(props.select?.default || null); const selectedValue = ref(props.select?.default || null);

View File

@ -88,7 +88,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { markRaw, nextTick, onActivated, onBeforeUnmount, onMounted, ref, watch } from 'vue'; import { markRaw, nextTick, onActivated, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkButton from './MkButton.vue'; import MkButton from './MkButton.vue';
import XNavFolder from '@/components/MkDrive.navFolder.vue'; import XNavFolder from '@/components/MkDrive.navFolder.vue';
@ -118,8 +118,8 @@ const emit = defineEmits<{
(ev: 'open-folder', v: Misskey.entities.DriveFolder): void; (ev: 'open-folder', v: Misskey.entities.DriveFolder): void;
}>(); }>();
const loadMoreFiles = ref<InstanceType<typeof MkButton>>(); const loadMoreFiles = shallowRef<InstanceType<typeof MkButton>>();
const fileInput = ref<HTMLInputElement>(); const fileInput = shallowRef<HTMLInputElement>();
const folder = ref<Misskey.entities.DriveFolder | null>(null); const folder = ref<Misskey.entities.DriveFolder | null>(null);
const files = ref<Misskey.entities.DriveFile[]>([]); const files = ref<Misskey.entities.DriveFile[]>([]);

View File

@ -19,7 +19,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref, shallowRef } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import XDrive from '@/components/MkDrive.vue'; import XDrive from '@/components/MkDrive.vue';
import XModalWindow from '@/components/MkModalWindow.vue'; import XModalWindow from '@/components/MkModalWindow.vue';
@ -38,7 +38,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const dialog = ref<InstanceType<typeof XModalWindow>>(); const dialog = shallowRef<InstanceType<typeof XModalWindow>>();
const selected = ref<Misskey.entities.DriveFile[]>([]); const selected = ref<Misskey.entities.DriveFile[]>([]);

View File

@ -77,7 +77,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, watch, onMounted } from 'vue'; import { ref, shallowRef, computed, watch, onMounted } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import XSection from '@/components/MkEmojiPicker.section.vue'; import XSection from '@/components/MkEmojiPicker.section.vue';
import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist'; import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist';
@ -102,8 +102,8 @@ const emit = defineEmits<{
(ev: 'chosen', v: string): void; (ev: 'chosen', v: string): void;
}>(); }>();
const search = ref<HTMLInputElement>(); const search = shallowRef<HTMLInputElement>();
const emojis = ref<HTMLDivElement>(); const emojis = shallowRef<HTMLDivElement>();
const { const {
reactions: pinned, reactions: pinned,

View File

@ -26,7 +26,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { shallowRef } from 'vue';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
import MkEmojiPicker from '@/components/MkEmojiPicker.vue'; import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
@ -48,8 +48,8 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const modal = ref<InstanceType<typeof MkModal>>(); const modal = shallowRef<InstanceType<typeof MkModal>>();
const picker = ref<InstanceType<typeof MkEmojiPicker>>(); const picker = shallowRef<InstanceType<typeof MkEmojiPicker>>();
function chosen(emoji: any) { function chosen(emoji: any) {
emit('done', emoji); emit('done', emoji);

View File

@ -37,7 +37,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const dialog = $ref<InstanceType<typeof XModalWindow>>(); const dialog = $shallowRef<InstanceType<typeof XModalWindow>>();
let caption = $ref(props.default); let caption = $ref(props.default);

View File

@ -12,11 +12,10 @@ import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick, w
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import { enUS } from 'date-fns/locale'; import { enUS } from 'date-fns/locale';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { MatrixController, MatrixElement } from 'chartjs-chart-matrix';
import * as os from '@/os'; import * as os from '@/os';
import 'chartjs-adapter-date-fns';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip'; import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { MatrixController, MatrixElement } from 'chartjs-chart-matrix';
import { chartVLine } from '@/scripts/chart-vline'; import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color'; import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart'; import { initChart } from '@/scripts/init-chart';
@ -27,8 +26,8 @@ const props = defineProps<{
src: string; src: string;
}>(); }>();
const rootEl = $ref<HTMLDivElement>(null); const rootEl = $shallowRef<HTMLDivElement>(null);
const chartEl = $ref<HTMLCanvasElement>(null); const chartEl = $shallowRef<HTMLCanvasElement>(null);
const now = new Date(); const now = new Date();
let chartInstance: Chart = null; let chartInstance: Chart = null;
let fetching = $ref(true); let fetching = $ref(true);

View File

@ -28,7 +28,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const modal = $ref<InstanceType<typeof MkModal>>(); const modal = $shallowRef<InstanceType<typeof MkModal>>();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -24,7 +24,7 @@ const props = withDefaults(defineProps<{
cover: true, cover: true,
}); });
const canvas = $ref<HTMLCanvasElement>(); const canvas = $shallowRef<HTMLCanvasElement>();
let loaded = $ref(false); let loaded = $ref(false);
function draw() { function draw() {

View File

@ -94,8 +94,8 @@ const chartLimit = 500;
let chartSpan = $ref<'hour' | 'day'>('hour'); let chartSpan = $ref<'hour' | 'day'>('hour');
let chartSrc = $ref('active-users'); let chartSrc = $ref('active-users');
let heatmapSrc = $ref('active-users'); let heatmapSrc = $ref('active-users');
let subDoughnutEl = $ref<HTMLCanvasElement>(); let subDoughnutEl = $shallowRef<HTMLCanvasElement>();
let pubDoughnutEl = $ref<HTMLCanvasElement>(); let pubDoughnutEl = $shallowRef<HTMLCanvasElement>();
const { handler: externalTooltipHandler1 } = useChartTooltip({ const { handler: externalTooltipHandler1 } = useChartTooltip({
position: 'middle', position: 'middle',

View File

@ -44,7 +44,7 @@ const preferedModalType = (deviceKind === 'desktop' && props.src != null) ? 'pop
deviceKind === 'smartphone' ? 'drawer' : deviceKind === 'smartphone' ? 'drawer' :
'dialog'; 'dialog';
const modal = $ref<InstanceType<typeof MkModal>>(); const modal = $shallowRef<InstanceType<typeof MkModal>>();
const menu = defaultStore.state.menu; const menu = defaultStore.state.menu;

View File

@ -38,7 +38,7 @@ const props = withDefaults(defineProps<{
}>(), { }>(), {
}); });
const audioEl = $ref<HTMLAudioElement | null>(); const audioEl = $shallowRef<HTMLAudioElement | null>();
let hide = $ref(true); let hide = $ref(true);
function volumechange() { function volumechange() {

View File

@ -6,7 +6,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { on } from 'events'; import { on } from 'events';
import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue'; import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
import MkMenu from './MkMenu.vue'; import MkMenu from './MkMenu.vue';
import { MenuItem } from '@/types/menu'; import { MenuItem } from '@/types/menu';
import * as os from '@/os'; import * as os from '@/os';
@ -24,7 +24,7 @@ const emit = defineEmits<{
(ev: 'actioned'): void; (ev: 'actioned'): void;
}>(); }>();
const el = ref<HTMLElement>(); const el = shallowRef<HTMLElement>();
const align = 'left'; const align = 'left';
function setPosition() { function setPosition() {

View File

@ -78,11 +78,11 @@ const emit = defineEmits<{
(ev: 'close', actioned?: boolean): void; (ev: 'close', actioned?: boolean): void;
}>(); }>();
let itemsEl = $ref<HTMLDivElement>(); let itemsEl = $shallowRef<HTMLDivElement>();
let items2: InnerMenuItem[] = $ref([]); let items2: InnerMenuItem[] = $ref([]);
let child = $ref<InstanceType<typeof XChild>>(); let child = $shallowRef<InstanceType<typeof XChild>>();
let keymap = $computed(() => ({ let keymap = $computed(() => ({
'up|k|shift+tab': focusUp, 'up|k|shift+tab': focusUp,
@ -112,7 +112,7 @@ watch(() => props.items, () => {
}); });
let childMenu = $ref<MenuItem[] | null>(); let childMenu = $ref<MenuItem[] | null>();
let childTarget = $ref<HTMLElement | null>(); let childTarget = $shallowRef<HTMLElement | null>();
function closeChild() { function closeChild() {
childMenu = null; childMenu = null;
@ -203,7 +203,7 @@ onBeforeUnmount(() => {
> .item { > .item {
display: block; display: block;
position: relative; position: relative;
padding: 6px 16px; padding: 5px 16px;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
white-space: nowrap; white-space: nowrap;
@ -226,10 +226,6 @@ onBeforeUnmount(() => {
border-radius: 6px; border-radius: 6px;
} }
> * {
position: relative;
}
&:not(:disabled):hover { &:not(:disabled):hover {
color: var(--accent); color: var(--accent);
text-decoration: none; text-decoration: none;

View File

@ -61,7 +61,7 @@ let maxHeight = $ref<number>();
let fixed = $ref(false); let fixed = $ref(false);
let transformOrigin = $ref('center'); let transformOrigin = $ref('center');
let showing = $ref(true); let showing = $ref(true);
let content = $ref<HTMLElement>(); let content = $shallowRef<HTMLElement>();
const zIndex = os.claimZIndex(props.zPriority); const zIndex = os.claimZIndex(props.zPriority);
const type = $computed<ModalTypes>(() => { const type = $computed<ModalTypes>(() => {
if (props.preferType === 'auto') { if (props.preferType === 'auto') {

View File

@ -49,7 +49,7 @@ router.addListener('push', ctx => {
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();
let rootEl = $ref(); let rootEl = $ref();
let modal = $ref<InstanceType<typeof MkModal>>(); let modal = $shallowRef<InstanceType<typeof MkModal>>();
let path = $ref(props.initialPath); let path = $ref(props.initialPath);
let width = $ref(860); let width = $ref(860);
let height = $ref(660); let height = $ref(660);

View File

@ -41,9 +41,9 @@ const emit = defineEmits<{
(event: 'ok'): void; (event: 'ok'): void;
}>(); }>();
let modal = $ref<InstanceType<typeof MkModal>>(); let modal = $shallowRef<InstanceType<typeof MkModal>>();
let rootEl = $ref<HTMLElement>(); let rootEl = $shallowRef<HTMLElement>();
let headerEl = $ref<HTMLElement>(); let headerEl = $shallowRef<HTMLElement>();
let bodyWidth = $ref(0); let bodyWidth = $ref(0);
let bodyHeight = $ref(0); let bodyHeight = $ref(0);

View File

@ -59,7 +59,7 @@
</div> </div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/>
<div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote"/></div> <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div>
<button v-if="isLong && collapsed" class="fade _button" @click="collapsed = false"> <button v-if="isLong && collapsed" class="fade _button" @click="collapsed = false">
<span>{{ i18n.ts.showMore }}</span> <span>{{ i18n.ts.showMore }}</span>
</button> </button>
@ -101,7 +101,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, inject, onMounted, onUnmounted, reactive, ref, Ref } from 'vue'; import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef, Ref } from 'vue';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import MkNoteSub from '@/components/MkNoteSub.vue'; import MkNoteSub from '@/components/MkNoteSub.vue';
@ -156,11 +156,11 @@ const isRenote = (
note.poll == null note.poll == null
); );
const el = ref<HTMLElement>(); const el = shallowRef<HTMLElement>();
const menuButton = ref<HTMLElement>(); const menuButton = shallowRef<HTMLElement>();
const renoteButton = ref<InstanceType<typeof MkRenoteButton>>(); const renoteButton = shallowRef<InstanceType<typeof MkRenoteButton>>();
const renoteTime = ref<HTMLElement>(); const renoteTime = shallowRef<HTMLElement>();
const reactButton = ref<HTMLElement>(); const reactButton = shallowRef<HTMLElement>();
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note); let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
const isMyRenote = $i && ($i.id === note.userId); const isMyRenote = $i && ($i.id === note.userId);
const showContent = ref(false); const showContent = ref(false);
@ -529,7 +529,7 @@ function readPromo() {
> .renote { > .renote {
padding: 8px 0; padding: 8px 0;
> * { > .note {
padding: 16px; padding: 16px;
border: dashed 1px var(--renote); border: dashed 1px var(--renote);
border-radius: 8px; border-radius: 8px;

View File

@ -70,7 +70,7 @@
</div> </div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" class="url-preview"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" class="url-preview"/>
<div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote"/></div> <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div>
</div> </div>
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> <MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
</div> </div>
@ -112,7 +112,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, inject, onMounted, onUnmounted, reactive, ref } from 'vue'; import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef } from 'vue';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import MkNoteSub from '@/components/MkNoteSub.vue'; import MkNoteSub from '@/components/MkNoteSub.vue';
@ -166,11 +166,11 @@ const isRenote = (
note.poll == null note.poll == null
); );
const el = ref<HTMLElement>(); const el = shallowRef<HTMLElement>();
const menuButton = ref<HTMLElement>(); const menuButton = shallowRef<HTMLElement>();
const renoteButton = ref<InstanceType<typeof MkRenoteButton>>(); const renoteButton = shallowRef<InstanceType<typeof MkRenoteButton>>();
const renoteTime = ref<HTMLElement>(); const renoteTime = shallowRef<HTMLElement>();
const reactButton = ref<HTMLElement>(); const reactButton = shallowRef<HTMLElement>();
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note); let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
const isMyRenote = $i && ($i.id === note.userId); const isMyRenote = $i && ($i.id === note.userId);
const showContent = ref(false); const showContent = ref(false);
@ -491,7 +491,7 @@ if (appearNote.replyId) {
> .renote { > .renote {
padding: 8px 0; padding: 8px 0;
> * { > .note {
padding: 16px; padding: 16px;
border: dashed 1px var(--renote); border: dashed 1px var(--renote);
border-radius: 8px; border-radius: 8px;

View File

@ -18,7 +18,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { shallowRef } from 'vue';
import XNote from '@/components/MkNote.vue'; import XNote from '@/components/MkNote.vue';
import XList from '@/components/MkDateSeparatedList.vue'; import XList from '@/components/MkDateSeparatedList.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue';
@ -29,7 +29,7 @@ const props = defineProps<{
noGap?: boolean; noGap?: boolean;
}>(); }>();
const pagingComponent = ref<InstanceType<typeof MkPagination>>(); const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
defineExpose({ defineExpose({
pagingComponent, pagingComponent,

View File

@ -73,7 +73,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'; import { ref, shallowRef, onMounted, onUnmounted, watch } from 'vue';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import XReactionIcon from '@/components/MkReactionIcon.vue'; import XReactionIcon from '@/components/MkReactionIcon.vue';
import MkFollowButton from '@/components/MkFollowButton.vue'; import MkFollowButton from '@/components/MkFollowButton.vue';
@ -95,7 +95,7 @@ const props = withDefaults(defineProps<{
full: false, full: false,
}); });
const elRef = ref<HTMLElement>(null); const elRef = shallowRef<HTMLElement>(null);
const reactionRef = ref(null); const reactionRef = ref(null);
let readObserver: IntersectionObserver | undefined; let readObserver: IntersectionObserver | undefined;

View File

@ -56,7 +56,7 @@ const props = withDefaults(defineProps<{
let includingTypes = $computed(() => props.includingTypes || []); let includingTypes = $computed(() => props.includingTypes || []);
const dialog = $ref<InstanceType<typeof XModalWindow>>(); const dialog = $shallowRef<InstanceType<typeof XModalWindow>>();
let typesMap = $ref<Record<typeof notificationTypes[number], boolean>>({}); let typesMap = $ref<Record<typeof notificationTypes[number], boolean>>({});
let useGlobalSetting = $ref((includingTypes === null || includingTypes.length === 0) && props.showGlobalToggle); let useGlobalSetting = $ref((includingTypes === null || includingTypes.length === 0) && props.showGlobalToggle);

View File

@ -17,7 +17,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineComponent, markRaw, onUnmounted, onMounted, computed, ref } from 'vue'; import { defineComponent, markRaw, onUnmounted, onMounted, computed, shallowRef } from 'vue';
import { notificationTypes } from 'misskey-js'; import { notificationTypes } from 'misskey-js';
import MkPagination, { Paging } from '@/components/MkPagination.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue';
import XNotification from '@/components/MkNotification.vue'; import XNotification from '@/components/MkNotification.vue';
@ -33,7 +33,7 @@ const props = defineProps<{
unreadOnly?: boolean; unreadOnly?: boolean;
}>(); }>();
const pagingComponent = ref<InstanceType<typeof MkPagination>>(); const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
const pagination: Paging = { const pagination: Paging = {
endpoint: 'i/notifications' as const, endpoint: 'i/notifications' as const,

View File

@ -47,7 +47,7 @@ defineEmits<{
const router = new Router(routes, props.initialPath); const router = new Router(routes, props.initialPath);
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();
let windowEl = $ref<InstanceType<typeof XWindow>>(); let windowEl = $shallowRef<InstanceType<typeof XWindow>>();
const history = $ref<{ path: string; key: any; }[]>([{ const history = $ref<{ path: string; key: any; }[]>([{
path: router.getCurrentPath(), path: router.getCurrentPath(),
key: router.getCurrentKey(), key: router.getCurrentKey(),

View File

@ -32,7 +32,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ComputedRef, isRef, markRaw, onActivated, onDeactivated, Ref, ref, watch } from 'vue'; import { computed, ComputedRef, isRef, markRaw, onActivated, onDeactivated, Ref, ref, shallowRef, watch } from 'vue';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import * as os from '@/os'; import * as os from '@/os';
import { onScrollTop, isTopVisible, getScrollPosition, getScrollContainer } from '@/scripts/scroll'; import { onScrollTop, isTopVisible, getScrollPosition, getScrollContainer } from '@/scripts/scroll';
@ -65,7 +65,7 @@ const props = withDefaults(defineProps<{
disableAutoLoad?: boolean; disableAutoLoad?: boolean;
displayLimit?: number; displayLimit?: number;
}>(), { }>(), {
displayLimit: 30, displayLimit: 20,
}); });
const emit = defineEmits<{ const emit = defineEmits<{
@ -74,7 +74,7 @@ const emit = defineEmits<{
type Item = { id: string; [another: string]: unknown; }; type Item = { id: string; [another: string]: unknown; };
const rootEl = ref<HTMLElement>(); const rootEl = shallowRef<HTMLElement>();
const items = ref<Item[]>([]); const items = ref<Item[]>([]);
const queue = ref<Item[]>([]); const queue = ref<Item[]>([]);
const offset = ref(0); const offset = ref(0);

View File

@ -22,7 +22,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
let modal = $ref<InstanceType<typeof MkModal>>(); let modal = $shallowRef<InstanceType<typeof MkModal>>();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -128,10 +128,10 @@ const emit = defineEmits<{
(ev: 'esc'): void; (ev: 'esc'): void;
}>(); }>();
const textareaEl = $ref<HTMLTextAreaElement | null>(null); const textareaEl = $shallowRef<HTMLTextAreaElement | null>(null);
const cwInputEl = $ref<HTMLInputElement | null>(null); const cwInputEl = $shallowRef<HTMLInputElement | null>(null);
const hashtagsInputEl = $ref<HTMLInputElement | null>(null); const hashtagsInputEl = $shallowRef<HTMLInputElement | null>(null);
const visibilityButton = $ref<HTMLElement | null>(null); const visibilityButton = $shallowRef<HTMLElement | null>(null);
let posting = $ref(false); let posting = $ref(false);
let posted = $ref(false); let posted = $ref(false);

View File

@ -31,8 +31,8 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
let modal = $ref<InstanceType<typeof MkModal>>(); let modal = $shallowRef<InstanceType<typeof MkModal>>();
let form = $ref<InstanceType<typeof MkPostForm>>(); let form = $shallowRef<InstanceType<typeof MkPostForm>>();
function onPosted() { function onPosted() {
modal.close({ modal.close({

View File

@ -12,7 +12,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onMounted, ref, shallowRef, watch } from 'vue';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import XDetails from '@/components/MkReactionsViewer.details.vue'; import XDetails from '@/components/MkReactionsViewer.details.vue';
import XReactionIcon from '@/components/MkReactionIcon.vue'; import XReactionIcon from '@/components/MkReactionIcon.vue';
@ -28,7 +28,7 @@ const props = defineProps<{
note: misskey.entities.Note; note: misskey.entities.Note;
}>(); }>();
const buttonRef = ref<HTMLElement>(); const buttonRef = shallowRef<HTMLElement>();
const canToggle = computed(() => !props.reaction.match(/@\w/) && $i); const canToggle = computed(() => !props.reaction.match(/@\w/) && $i);

View File

@ -14,7 +14,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue'; import { computed, ref, shallowRef } from 'vue';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import XDetails from '@/components/MkUsersTooltip.vue'; import XDetails from '@/components/MkUsersTooltip.vue';
import { pleaseLogin } from '@/scripts/please-login'; import { pleaseLogin } from '@/scripts/please-login';
@ -28,7 +28,7 @@ const props = defineProps<{
count: number; count: number;
}>(); }>();
const buttonRef = ref<HTMLElement>(); const buttonRef = shallowRef<HTMLElement>();
const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id);

View File

@ -12,19 +12,18 @@ import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick }
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import { enUS } from 'date-fns/locale'; import { enUS } from 'date-fns/locale';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { MatrixController, MatrixElement } from 'chartjs-chart-matrix';
import * as os from '@/os'; import * as os from '@/os';
import 'chartjs-adapter-date-fns';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip'; import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { MatrixController, MatrixElement } from 'chartjs-chart-matrix';
import { chartVLine } from '@/scripts/chart-vline'; import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color'; import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart'; import { initChart } from '@/scripts/init-chart';
initChart(); initChart();
const rootEl = $ref<HTMLDivElement>(null); const rootEl = $shallowRef<HTMLDivElement>(null);
const chartEl = $ref<HTMLCanvasElement>(null); const chartEl = $shallowRef<HTMLCanvasElement>(null);
const now = new Date(); const now = new Date();
let chartInstance: Chart = null; let chartInstance: Chart = null;
let fetching = $ref(true); let fetching = $ref(true);

View File

@ -32,7 +32,7 @@ const emit = defineEmits<{
(ev: 'cancelled'): void; (ev: 'cancelled'): void;
}>(); }>();
const dialog = $ref<InstanceType<typeof XModalWindow>>(); const dialog = $shallowRef<InstanceType<typeof XModalWindow>>();
function onClose() { function onClose() {
emit('cancelled'); emit('cancelled');

View File

@ -33,7 +33,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const dialog = $ref<InstanceType<typeof XModalWindow>>(); const dialog = $shallowRef<InstanceType<typeof XModalWindow>>();
function onSignup(res) { function onSignup(res) {
emit('done', res); emit('done', res);

View File

@ -64,10 +64,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted, ref, shallowRef } from 'vue';
const particles = ref([]); const particles = ref([]);
const el = ref<HTMLElement>(); const el = shallowRef<HTMLElement>();
const width = ref(0); const width = ref(0);
const height = ref(0); const height = ref(0);
const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202']; const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];

View File

@ -19,9 +19,9 @@ const computedStyle = getComputedStyle(document.documentElement);
const idForCanvas = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const idForCanvas = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
const idForTags = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const idForTags = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
let available = $ref(false); let available = $ref(false);
let rootEl = $ref<HTMLElement | null>(null); let rootEl = $shallowRef<HTMLElement | null>(null);
let canvasEl = $ref<HTMLCanvasElement | null>(null); let canvasEl = $shallowRef<HTMLCanvasElement | null>(null);
let tagsEl = $ref<HTMLElement | null>(null); let tagsEl = $shallowRef<HTMLElement | null>(null);
let width = $ref(300); let width = $ref(300);
watch($$(available), () => { watch($$(available), () => {

View File

@ -54,7 +54,7 @@ const emit = defineEmits<{
(ev: 'done', result: { name: string | null, permissions: string[] }): void; (ev: 'done', result: { name: string | null, permissions: string[] }): void;
}>(); }>();
const dialog = $ref<InstanceType<typeof XModalWindow>>(); const dialog = $shallowRef<InstanceType<typeof XModalWindow>>();
let name = $ref(props.initialName); let name = $ref(props.initialName);
let permissions = $ref({}); let permissions = $ref({});

View File

@ -10,7 +10,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, ref } from 'vue'; import { nextTick, onMounted, onUnmounted, ref, shallowRef } from 'vue';
import * as os from '@/os'; import * as os from '@/os';
import { calcPopupPosition } from '@/scripts/popup-position'; import { calcPopupPosition } from '@/scripts/popup-position';
@ -34,7 +34,7 @@ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const el = ref<HTMLElement>(); const el = shallowRef<HTMLElement>();
const zIndex = os.claimZIndex('high'); const zIndex = os.claimZIndex('high');
function setPosition() { function setPosition() {

View File

@ -10,14 +10,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { shallowRef } from 'vue';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkSparkle from '@/components/MkSparkle.vue'; import MkSparkle from '@/components/MkSparkle.vue';
import { version } from '@/config'; import { version } from '@/config';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
const modal = ref<InstanceType<typeof MkModal>>(); const modal = shallowRef<InstanceType<typeof MkModal>>();
const whatIsNew = () => { const whatIsNew = () => {
modal.value.close(); modal.value.close();

View File

@ -1,5 +1,5 @@
<template> <template>
<MkPagination ref="pagingComponent" :pagination="pagination"> <MkPagination :pagination="pagination">
<template #empty> <template #empty>
<div class="_fullinfo"> <div class="_fullinfo">
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
@ -16,7 +16,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { shallowRef } from 'vue';
import MkUserInfo from '@/components/MkUserInfo.vue'; import MkUserInfo from '@/components/MkUserInfo.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue';
import { userPage } from '@/filters/user'; import { userPage } from '@/filters/user';
@ -26,8 +26,6 @@ const props = defineProps<{
pagination: Paging; pagination: Paging;
noGap?: boolean; noGap?: boolean;
}>(); }>();
const pagingComponent = ref<InstanceType<typeof MkPagination>>();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -22,7 +22,7 @@ const props = defineProps<{
}, },
}>(); }>();
const specified = $ref<HTMLElement>(); const specified = $shallowRef<HTMLElement>();
if (props.note.visibility === 'specified') { if (props.note.visibility === 'specified') {
useTooltip($$(specified), async (showing) => { useTooltip($$(specified), async (showing) => {

View File

@ -1,42 +1,42 @@
<template> <template>
<MkModal ref="modal" :z-priority="'high'" :src="src" @click="modal.close()" @closed="emit('closed')"> <MkModal ref="modal" :z-priority="'high'" :src="src" @click="modal.close()" @closed="emit('closed')">
<div class="gqyayizv _popup"> <div class="gqyayizv _popup">
<button key="public" class="_button" :class="{ active: v === 'public' }" data-index="1" @click="choose('public')"> <button key="public" class="_button item" :class="{ active: v === 'public' }" data-index="1" @click="choose('public')">
<div><i class="ti ti-world"></i></div> <div class="icon"><i class="ti ti-world"></i></div>
<div> <div class="body">
<span>{{ i18n.ts._visibility.public }}</span> <span>{{ i18n.ts._visibility.public }}</span>
<span>{{ i18n.ts._visibility.publicDescription }}</span> <span>{{ i18n.ts._visibility.publicDescription }}</span>
</div> </div>
</button> </button>
<button key="home" class="_button" :class="{ active: v === 'home' }" data-index="2" @click="choose('home')"> <button key="home" class="_button item" :class="{ active: v === 'home' }" data-index="2" @click="choose('home')">
<div><i class="ti ti-home"></i></div> <div class="icon"><i class="ti ti-home"></i></div>
<div> <div class="body">
<span>{{ i18n.ts._visibility.home }}</span> <span>{{ i18n.ts._visibility.home }}</span>
<span>{{ i18n.ts._visibility.homeDescription }}</span> <span>{{ i18n.ts._visibility.homeDescription }}</span>
</div> </div>
</button> </button>
<button key="followers" class="_button" :class="{ active: v === 'followers' }" data-index="3" @click="choose('followers')"> <button key="followers" class="_button item" :class="{ active: v === 'followers' }" data-index="3" @click="choose('followers')">
<div><i class="ti ti-lock-open"></i></div> <div class="icon"><i class="ti ti-lock-open"></i></div>
<div> <div class="body">
<span>{{ i18n.ts._visibility.followers }}</span> <span>{{ i18n.ts._visibility.followers }}</span>
<span>{{ i18n.ts._visibility.followersDescription }}</span> <span>{{ i18n.ts._visibility.followersDescription }}</span>
</div> </div>
</button> </button>
<button key="specified" :disabled="localOnly" class="_button" :class="{ active: v === 'specified' }" data-index="4" @click="choose('specified')"> <button key="specified" :disabled="localOnly" class="_button item" :class="{ active: v === 'specified' }" data-index="4" @click="choose('specified')">
<div><i class="ti ti-mail"></i></div> <div class="icon"><i class="ti ti-mail"></i></div>
<div> <div class="body">
<span>{{ i18n.ts._visibility.specified }}</span> <span>{{ i18n.ts._visibility.specified }}</span>
<span>{{ i18n.ts._visibility.specifiedDescription }}</span> <span>{{ i18n.ts._visibility.specifiedDescription }}</span>
</div> </div>
</button> </button>
<div class="divider"></div> <div class="divider"></div>
<button key="localOnly" class="_button localOnly" :class="{ active: localOnly }" data-index="5" @click="localOnly = !localOnly"> <button key="localOnly" class="_button item localOnly" :class="{ active: localOnly }" data-index="5" @click="localOnly = !localOnly">
<div><i class="ti ti-world-off"></i></div> <div class="icon"><i class="ti ti-world-off"></i></div>
<div> <div class="body">
<span>{{ i18n.ts._visibility.localOnly }}</span> <span>{{ i18n.ts._visibility.localOnly }}</span>
<span>{{ i18n.ts._visibility.localOnlyDescription }}</span> <span>{{ i18n.ts._visibility.localOnlyDescription }}</span>
</div> </div>
<div><i :class="localOnly ? 'ti ti-toggle-right' : 'ti ti-toggle-left'"></i></div> <div class="toggle"><i :class="localOnly ? 'ti ti-toggle-right' : 'ti ti-toggle-left'"></i></div>
</button> </button>
</div> </div>
</MkModal> </MkModal>
@ -48,7 +48,7 @@ import * as misskey from 'misskey-js';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
const modal = $ref<InstanceType<typeof MkModal>>(); const modal = $shallowRef<InstanceType<typeof MkModal>>();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
currentVisibility: typeof misskey.noteVisibilities[number]; currentVisibility: typeof misskey.noteVisibilities[number];
@ -89,7 +89,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void {
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
} }
> button { > .item {
display: flex; display: flex;
padding: 8px 14px; padding: 8px 14px;
font-size: 12px; font-size: 12px;
@ -115,7 +115,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void {
background: inherit; background: inherit;
} }
> *:nth-child(1) { > .icon {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -127,7 +127,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void {
margin-bottom: auto; margin-bottom: auto;
} }
> *:nth-child(2) { > .body {
flex: 1 1 auto; flex: 1 1 auto;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@ -143,7 +143,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void {
} }
} }
> *:nth-child(3) { > .toggle {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;

View File

@ -9,10 +9,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { watch, ref } from 'vue'; import { watch, shallowRef } from 'vue';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
const modal = ref<InstanceType<typeof MkModal>>(); const modal = shallowRef<InstanceType<typeof MkModal>>();
const props = defineProps<{ const props = defineProps<{
success: boolean; success: boolean;

View File

@ -88,7 +88,7 @@ const emit = defineEmits<{
provide('inWindow', true); provide('inWindow', true);
let rootEl = $ref<HTMLElement | null>(); let rootEl = $shallowRef<HTMLElement | null>();
let showing = $ref(true); let showing = $ref(true);
let beforeClickedAt = 0; let beforeClickedAt = 0;
let maximized = $ref(false); let maximized = $ref(false);

View File

@ -35,7 +35,7 @@ const emit = defineEmits<{
(ev: 'update:modelValue', v: boolean): void; (ev: 'update:modelValue', v: boolean): void;
}>(); }>();
let button = $ref<HTMLElement>(); let button = $shallowRef<HTMLElement>();
const checked = toRefs(props).modelValue; const checked = toRefs(props).modelValue;
const toggle = () => { const toggle = () => {
if (props.disabled) return; if (props.disabled) return;

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="dwzlatin" :class="{ opened }" ref="root"> <div class="dwzlatin" :class="{ opened }">
<div class="header _button" @click="toggle"> <div class="header _button" @click="toggle">
<span class="icon"><slot name="icon"></slot></span> <span class="icon"><slot name="icon"></slot></span>
<span class="text"><slot name="label"></slot></span> <span class="text"><slot name="label"></slot></span>
@ -19,7 +19,7 @@
> >
<KeepAlive> <KeepAlive>
<div v-show="opened"> <div v-show="opened">
<MkSpacer :margin-min="14" :margin-max="22" :container="root"> <MkSpacer :margin-min="14" :margin-max="22">
<slot></slot> <slot></slot>
</MkSpacer> </MkSpacer>
</div> </div>
@ -40,7 +40,6 @@ const props = withDefaults(defineProps<{
let opened = $ref(props.defaultOpen); let opened = $ref(props.defaultOpen);
let openedAtLeastOnce = $ref(props.defaultOpen); let openedAtLeastOnce = $ref(props.defaultOpen);
let root = $ref<HTMLElement>();
function enter(el) { function enter(el) {
const elementHeight = el.getBoundingClientRect().height; const elementHeight = el.getBoundingClientRect().height;
@ -142,6 +141,7 @@ function toggle() {
> .body { > .body {
background: var(--panel); background: var(--panel);
border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px;
container-type: inline-size;
} }
&.opened { &.opened {

View File

@ -34,7 +34,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; import { onMounted, onUnmounted, nextTick, ref, shallowRef, watch, computed, toRefs } from 'vue';
import { debounce } from 'throttle-debounce'; import { debounce } from 'throttle-debounce';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { useInterval } from '@/scripts/use-interval'; import { useInterval } from '@/scripts/use-interval';
@ -74,9 +74,9 @@ const focused = ref(false);
const changed = ref(false); const changed = ref(false);
const invalid = ref(false); const invalid = ref(false);
const filled = computed(() => v.value !== '' && v.value != null); const filled = computed(() => v.value !== '' && v.value != null);
const inputEl = ref<HTMLElement>(); const inputEl = shallowRef<HTMLElement>();
const prefixEl = ref<HTMLElement>(); const prefixEl = shallowRef<HTMLElement>();
const suffixEl = ref<HTMLElement>(); const suffixEl = shallowRef<HTMLElement>();
const height = const height =
props.small ? 35 : props.small ? 35 :
props.large ? 39 : props.large ? 39 :

View File

@ -34,7 +34,7 @@ const emit = defineEmits<{
(ev: 'update:modelValue', v: boolean): void; (ev: 'update:modelValue', v: boolean): void;
}>(); }>();
let button = $ref<HTMLElement>(); let button = $shallowRef<HTMLElement>();
const checked = toRefs(props).modelValue; const checked = toRefs(props).modelValue;
const toggle = () => { const toggle = () => {
if (props.disabled) return; if (props.disabled) return;

View File

@ -77,9 +77,9 @@ const metadata = injectPageMetadata();
const hideTitle = inject('shouldOmitHeaderTitle', false); const hideTitle = inject('shouldOmitHeaderTitle', false);
const thin_ = props.thin || inject('shouldHeaderThin', false); const thin_ = props.thin || inject('shouldHeaderThin', false);
const el = $ref<HTMLElement | undefined>(undefined); const el = $shallowRef<HTMLElement | undefined>(undefined);
const tabRefs: Record<string, HTMLElement | null> = {}; const tabRefs: Record<string, HTMLElement | null> = {};
const tabHighlightEl = $ref<HTMLElement | null>(null); const tabHighlightEl = $shallowRef<HTMLElement | null>(null);
const bg = ref<string | undefined>(undefined); const bg = ref<string | undefined>(undefined);
let narrow = $ref(false); let narrow = $ref(false);
const hasTabs = $computed(() => props.tabs.length > 0); const hasTabs = $computed(() => props.tabs.length > 0);

View File

@ -1,6 +1,6 @@
<template> <template>
<div ref="root" :class="$style.root" :style="{ padding: margin + 'px' }"> <div :class="[$style.root, { [$style.rootMin]: forceSpacerMin }]">
<div ref="content" :class="$style.content"> <div :class="$style.content">
<slot></slot> <slot></slot>
</div> </div>
</div> </div>
@ -14,85 +14,13 @@ const props = withDefaults(defineProps<{
contentMax?: number | null; contentMax?: number | null;
marginMin?: number; marginMin?: number;
marginMax?: number; marginMax?: number;
// MkFolderheight
container?: HTMLElement,
}>(), { }>(), {
contentMax: null, contentMax: null,
marginMin: 12, marginMin: 12,
marginMax: 24, marginMax: 24,
}); });
let ro: ResizeObserver; const forceSpacerMin = inject('forceSpacerMin', false) || deviceKind === 'smartphone';
let root = $ref<HTMLElement>();
let content = $ref<HTMLElement>();
let margin = $ref(props.marginMin);
const widthHistory = [null, null] as [number | null, number | null];
const heightHistory = [null, null] as [number | null, number | null];
const shouldSpacerMin = inject('shouldSpacerMin', false);
const adjust = (rect: { width: number; height: number; }) => {
if (shouldSpacerMin || deviceKind === 'smartphone') {
margin = props.marginMin;
return;
}
if (rect.width > (props.contentMax ?? 0) || (rect.width > 360 && window.innerWidth > 400)) {
margin = props.marginMax;
} else {
margin = props.marginMin;
}
};
if (props.container) {
const width = props.container.offsetWidth;
const height = props.container.offsetHeight;
adjust({
width,
height,
});
}
onMounted(() => {
ro = new ResizeObserver((entries) => {
/* iOS
adjust({
width: entries[0].borderBoxSize[0].inlineSize,
height: entries[0].borderBoxSize[0].blockSize,
});
*/
const width = props.container ? props.container.offsetWidth : root!.offsetWidth;
const height = props.container ? props.container.offsetHeight : root!.offsetHeight;
//#region Prevent infinite resizing
// https://github.com/misskey-dev/misskey/issues/9076
const pastWidth = widthHistory.pop();
widthHistory.unshift(width);
const pastHeight = heightHistory.pop();
heightHistory.unshift(height);
if (pastWidth === width && pastHeight === height) {
return;
}
//#endregion
adjust({
width,
height,
});
});
ro.observe(root!);
if (props.contentMax) {
content!.style.maxWidth = `${props.contentMax}px`;
}
});
onUnmounted(() => {
ro.disconnect();
});
</script> </script>
<style lang="scss" module> <style lang="scss" module>
@ -100,9 +28,25 @@ onUnmounted(() => {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
} }
.rootMin {
padding: v-bind('props.marginMin + "px"') !important;
}
.content { .content {
margin: 0 auto; margin: 0 auto;
max-width: v-bind('props.contentMax + "px"');
container-type: inline-size; container-type: inline-size;
} }
@container (max-width: 360px) {
.root {
padding: v-bind('props.marginMin + "px"');
}
}
@container (min-width: 361px) {
.root {
padding: v-bind('props.marginMax + "px"');
}
}
</style> </style>

View File

@ -18,9 +18,9 @@ const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue'; import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue';
const rootEl = $ref<HTMLElement>(); const rootEl = $shallowRef<HTMLElement>();
const headerEl = $ref<HTMLElement>(); const headerEl = $shallowRef<HTMLElement>();
const bodyEl = $ref<HTMLElement>(); const bodyEl = $shallowRef<HTMLElement>();
let headerHeight = $ref<string | undefined>(); let headerHeight = $ref<string | undefined>();
let childStickyTop = $ref(0); let childStickyTop = $ref(0);

View File

@ -6,7 +6,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, nextTick, onUnmounted, PropType } from 'vue'; import { defineComponent, onMounted, nextTick, onUnmounted, PropType } from 'vue';
import { parse } from '@syuilo/aiscript';
import XBlock from './page.block.vue'; import XBlock from './page.block.vue';
import { Hpml } from '@/scripts/hpml/evaluator'; import { Hpml } from '@/scripts/hpml/evaluator';
import { url } from '@/config'; import { url } from '@/config';
@ -28,38 +27,11 @@ export default defineComponent({
randomSeed: Math.random(), randomSeed: Math.random(),
visitor: $i, visitor: $i,
url: url, url: url,
enableAiScript: !defaultStore.state.disablePagesScript,
}); });
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
if (props.page.script && hpml.aiscript) { hpml.eval();
let ast;
try {
ast = parse(props.page.script);
} catch (err) {
console.error(err);
/*os.alert({
type: 'error',
text: 'Syntax error :('
});*/
return;
}
hpml.aiscript.exec(ast).then(() => {
hpml.eval();
}).catch(err => {
console.error(err);
/*os.alert({
type: 'error',
text: err
});*/
});
} else {
hpml.eval();
}
});
onUnmounted(() => {
if (hpml.aiscript) hpml.aiscript.abort();
}); });
}); });

View File

@ -156,7 +156,7 @@ const patrons = [
let easterEggReady = false; let easterEggReady = false;
let easterEggEmojis = $ref([]); let easterEggEmojis = $ref([]);
let easterEggEngine = $ref(null); let easterEggEngine = $ref(null);
const containerEl = $ref<HTMLElement>(); const containerEl = $shallowRef<HTMLElement>();
function iconLoaded() { function iconLoaded() {
const emojis = defaultStore.state.reactions; const emojis = defaultStore.state.reactions;

View File

@ -30,15 +30,13 @@
<option value="-followers">{{ i18n.ts.followers }} ({{ i18n.ts.ascendingOrder }})</option> <option value="-followers">{{ i18n.ts.followers }} ({{ i18n.ts.ascendingOrder }})</option>
<option value="+caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.descendingOrder }})</option> <option value="+caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.descendingOrder }})</option>
<option value="-caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.ascendingOrder }})</option> <option value="-caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.ascendingOrder }})</option>
<option value="+lastCommunicatedAt">{{ i18n.ts.lastCommunication }} ({{ i18n.ts.descendingOrder }})</option>
<option value="-lastCommunicatedAt">{{ i18n.ts.lastCommunication }} ({{ i18n.ts.ascendingOrder }})</option>
</MkSelect> </MkSelect>
</FormSplit> </FormSplit>
</div> </div>
<MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination"> <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination">
<div class="dqokceoi"> <div class="dqokceoi">
<MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Last communicated: ${dateString(instance.lastCommunicatedAt)}\nStatus: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`"> <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`">
<MkInstanceCardMini :instance="instance"/> <MkInstanceCardMini :instance="instance"/>
</MkA> </MkA>
</div> </div>

View File

@ -28,7 +28,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, inject, watch, nextTick } from 'vue'; import { computed, onMounted, onUnmounted, ref, shallowRef, inject, watch, nextTick } from 'vue';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { popupMenu } from '@/os'; import { popupMenu } from '@/os';
import { url } from '@/config'; import { url } from '@/config';
@ -64,9 +64,9 @@ const emit = defineEmits<{
const metadata = injectPageMetadata(); const metadata = injectPageMetadata();
const el = ref<HTMLElement>(null); const el = shallowRef<HTMLElement>(null);
const tabRefs = {}; const tabRefs = {};
const tabHighlightEl = $ref<HTMLElement | null>(null); const tabHighlightEl = $shallowRef<HTMLElement | null>(null);
const bg = ref(null); const bg = ref(null);
const height = ref(0); const height = ref(0);
const hasTabs = computed(() => { const hasTabs = computed(() => {

View File

@ -58,7 +58,7 @@ import * as os from '@/os';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
let reports = $ref<InstanceType<typeof MkPagination>>(); let reports = $shallowRef<InstanceType<typeof MkPagination>>();
let state = $ref('unresolved'); let state = $ref('unresolved');
let reporterOrigin = $ref('combined'); let reporterOrigin = $ref('combined');

View File

@ -68,7 +68,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, defineAsyncComponent, defineComponent, ref, toRef } from 'vue'; import { computed, defineAsyncComponent, defineComponent, ref, shallowRef } from 'vue';
import XHeader from './_header_.vue'; import XHeader from './_header_.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/form/input.vue'; import MkInput from '@/components/form/input.vue';
@ -81,7 +81,7 @@ import * as os from '@/os';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
const emojisPaginationComponent = ref<InstanceType<typeof MkPagination>>(); const emojisPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
const tab = ref('local'); const tab = ref('local');
const query = ref(null); const query = ref(null);

View File

@ -16,7 +16,7 @@
</div> </div>
</MkSpacer> </MkSpacer>
</div> </div>
<div v-if="!(narrow && currentPage?.route.name == null)" class="main" style="container-type: inline-size;"> <div v-if="!(narrow && currentPage?.route.name == null)" class="main">
<RouterView/> <RouterView/>
</div> </div>
</div> </div>

View File

@ -1,439 +0,0 @@
<template>
<div class="_debobigegoItem">
<div class="_debobigegoLabel"><i class="fas fa-microchip"></i> {{ $ts.cpuAndMemory }}</div>
<div class="_debobigegoPanel xhexznfu">
<div>
<canvas :ref="cpumem"></canvas>
</div>
<div v-if="serverInfo">
<div class="_table">
<div class="_row">
<div class="_cell"><div class="_label">MEM total</div>{{ bytes(serverInfo.mem.total) }}</div>
<div class="_cell"><div class="_label">MEM used</div>{{ bytes(memUsage) }} ({{ (memUsage / serverInfo.mem.total * 100).toFixed(0) }}%)</div>
<div class="_cell"><div class="_label">MEM free</div>{{ bytes(serverInfo.mem.total - memUsage) }} ({{ ((serverInfo.mem.total - memUsage) / serverInfo.mem.total * 100).toFixed(0) }}%)</div>
</div>
</div>
</div>
</div>
</div>
<div class="_debobigegoItem">
<div class="_debobigegoLabel"><i class="fas fa-hdd"></i> {{ $ts.disk }}</div>
<div class="_debobigegoPanel xhexznfu">
<div>
<canvas :ref="disk"></canvas>
</div>
<div v-if="serverInfo">
<div class="_table">
<div class="_row">
<div class="_cell"><div class="_label">Disk total</div>{{ bytes(serverInfo.fs.total) }}</div>
<div class="_cell"><div class="_label">Disk used</div>{{ bytes(serverInfo.fs.used) }} ({{ (serverInfo.fs.used / serverInfo.fs.total * 100).toFixed(0) }}%)</div>
<div class="_cell"><div class="_label">Disk free</div>{{ bytes(serverInfo.fs.total - serverInfo.fs.used) }} ({{ ((serverInfo.fs.total - serverInfo.fs.used) / serverInfo.fs.total * 100).toFixed(0) }}%)</div>
</div>
</div>
</div>
</div>
</div>
<div class="_debobigegoItem">
<div class="_debobigegoLabel"><i class="fas fa-exchange-alt"></i> {{ $ts.network }}</div>
<div class="_debobigegoPanel xhexznfu">
<div>
<canvas :ref="net"></canvas>
</div>
<div v-if="serverInfo">
<div class="_table">
<div class="_row">
<div class="_cell"><div class="_label">Interface</div>{{ serverInfo.net.interface }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, markRaw } from 'vue';
import { Chart } from 'chart.js';
import MkwFederation from '../../widgets/federation.vue';
import MkButton from '@/components/MkButton.vue';
import MkSelect from '@/components/form/select.vue';
import MkInput from '@/components/form/input.vue';
import MkContainer from '@/components/MkContainer.vue';
import MkFolder from '@/components/MkFolder.vue';
import { version, url } from '@/config';
import bytes from '@/filters/bytes';
import number from '@/filters/number';
import * as os from '@/os';
import { stream } from '@/stream';
import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart';
initChart();
export default defineComponent({
components: {
MkButton,
MkSelect,
MkInput,
MkContainer,
MkFolder,
MkwFederation,
},
data() {
return {
version,
url,
stats: null,
serverInfo: null,
connection: null,
queueConnection: markRaw(stream.useChannel('queueStats')),
memUsage: 0,
chartCpuMem: null,
chartNet: null,
jobs: [],
logs: [],
logLevel: 'all',
logDomain: '',
modLogs: [],
dbInfo: null,
overviewHeight: '1fr',
queueHeight: '1fr',
paused: false,
};
},
computed: {
gridColor() {
// TODO: var(--panel)
return this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
},
},
mounted() {
this.fetchJobs();
Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
os.api('admin/server-info', {}).then(res => {
this.serverInfo = res;
this.connection = markRaw(stream.useChannel('serverStats'));
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 150,
});
this.$nextTick(() => {
this.queueConnection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 200,
});
});
});
},
beforeUnmount() {
if (this.connection) {
this.connection.off('stats', this.onStats);
this.connection.off('statsLog', this.onStatsLog);
this.connection.dispose();
}
this.queueConnection.dispose();
},
methods: {
cpumem(el) {
if (this.chartCpuMem != null) return;
this.chartCpuMem = markRaw(new Chart(el, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'CPU',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#86b300',
backgroundColor: alpha('#86b300', 0.1),
data: [],
}, {
label: 'MEM (active)',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#935dbf',
backgroundColor: alpha('#935dbf', 0.02),
data: [],
}, {
label: 'MEM (used)',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#935dbf',
borderDash: [5, 5],
fill: false,
data: [],
}],
},
options: {
aspectRatio: 3,
layout: {
padding: {
left: 16,
right: 16,
top: 16,
bottom: 0,
},
},
legend: {
position: 'bottom',
labels: {
boxWidth: 16,
},
},
scales: {
x: {
gridLines: {
display: false,
color: this.gridColor,
zeroLineColor: this.gridColor,
},
ticks: {
display: false,
},
},
y: {
position: 'right',
gridLines: {
display: true,
color: this.gridColor,
zeroLineColor: this.gridColor,
},
ticks: {
display: false,
max: 100,
},
},
},
tooltips: {
intersect: false,
mode: 'index',
},
},
}));
},
net(el) {
if (this.chartNet != null) return;
this.chartNet = markRaw(new Chart(el, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'In',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#94a029',
backgroundColor: alpha('#94a029', 0.1),
data: [],
}, {
label: 'Out',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#ff9156',
backgroundColor: alpha('#ff9156', 0.1),
data: [],
}],
},
options: {
aspectRatio: 3,
layout: {
padding: {
left: 16,
right: 16,
top: 16,
bottom: 0,
},
},
legend: {
position: 'bottom',
labels: {
boxWidth: 16,
},
},
scales: {
x: {
gridLines: {
display: false,
color: this.gridColor,
zeroLineColor: this.gridColor,
},
ticks: {
display: false,
},
},
y: {
position: 'right',
gridLines: {
display: true,
color: this.gridColor,
zeroLineColor: this.gridColor,
},
ticks: {
display: false,
},
},
},
tooltips: {
intersect: false,
mode: 'index',
},
},
}));
},
disk(el) {
if (this.chartDisk != null) return;
this.chartDisk = markRaw(new Chart(el, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Read',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#94a029',
backgroundColor: alpha('#94a029', 0.1),
data: [],
}, {
label: 'Write',
pointRadius: 0,
tension: 0,
borderWidth: 2,
borderColor: '#ff9156',
backgroundColor: alpha('#ff9156', 0.1),
data: [],
}],
},
options: {
aspectRatio: 3,
layout: {
padding: {
left: 16,
right: 16,
top: 16,
bottom: 0,
},
},
legend: {
position: 'bottom',
labels: {
boxWidth: 16,
},
},
scales: {
x: {
gridLines: {
display: false,
color: this.gridColor,
zeroLineColor: this.gridColor,
},
ticks: {
display: false,
},
},
y: {
position: 'right',
gridLines: {
display: true,
color: this.gridColor,
zeroLineColor: this.gridColor,
},
ticks: {
display: false,
},
},
},
tooltips: {
intersect: false,
mode: 'index',
},
},
}));
},
fetchJobs() {
os.api('admin/queue/deliver-delayed', {}).then(jobs => {
this.jobs = jobs;
});
},
onStats(stats) {
if (this.paused) return;
const cpu = (stats.cpu * 100).toFixed(0);
const memActive = (stats.mem.active / this.serverInfo.mem.total * 100).toFixed(0);
const memUsed = (stats.mem.used / this.serverInfo.mem.total * 100).toFixed(0);
this.memUsage = stats.mem.active;
this.chartCpuMem.data.labels.push('');
this.chartCpuMem.data.datasets[0].data.push(cpu);
this.chartCpuMem.data.datasets[1].data.push(memActive);
this.chartCpuMem.data.datasets[2].data.push(memUsed);
this.chartNet.data.labels.push('');
this.chartNet.data.datasets[0].data.push(stats.net.rx);
this.chartNet.data.datasets[1].data.push(stats.net.tx);
this.chartDisk.data.labels.push('');
this.chartDisk.data.datasets[0].data.push(stats.fs.r);
this.chartDisk.data.datasets[1].data.push(stats.fs.w);
if (this.chartCpuMem.data.datasets[0].data.length > 150) {
this.chartCpuMem.data.labels.shift();
this.chartCpuMem.data.datasets[0].data.shift();
this.chartCpuMem.data.datasets[1].data.shift();
this.chartCpuMem.data.datasets[2].data.shift();
this.chartNet.data.labels.shift();
this.chartNet.data.datasets[0].data.shift();
this.chartNet.data.datasets[1].data.shift();
this.chartDisk.data.labels.shift();
this.chartDisk.data.datasets[0].data.shift();
this.chartDisk.data.datasets[1].data.shift();
}
this.chartCpuMem.update();
this.chartNet.update();
this.chartDisk.update();
},
onStatsLog(statsLog) {
for (const stats of [...statsLog].reverse()) {
this.onStats(stats);
}
},
bytes,
number,
pause() {
this.paused = true;
},
resume() {
this.paused = false;
},
},
});
</script>
<style lang="scss" scoped>
.xhexznfu {
> div:nth-child(2) {
padding: 16px;
border-top: solid 0.5px var(--divider);
}
}
</style>

View File

@ -12,18 +12,17 @@ import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick }
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import { enUS } from 'date-fns/locale'; import { enUS } from 'date-fns/locale';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import gradient from 'chartjs-plugin-gradient';
import * as os from '@/os'; import * as os from '@/os';
import 'chartjs-adapter-date-fns';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip'; import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import gradient from 'chartjs-plugin-gradient';
import { chartVLine } from '@/scripts/chart-vline'; import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color'; import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart'; import { initChart } from '@/scripts/init-chart';
initChart(); initChart();
const chartEl = $ref<HTMLCanvasElement>(null); const chartEl = $shallowRef<HTMLCanvasElement>(null);
const now = new Date(); const now = new Date();
let chartInstance: Chart = null; let chartInstance: Chart = null;
const chartLimit = 7; const chartLimit = 7;

View File

@ -34,8 +34,8 @@ import { initChart } from '@/scripts/init-chart';
initChart(); initChart();
const chartLimit = 50; const chartLimit = 50;
const chartEl = $ref<HTMLCanvasElement>(); const chartEl = $shallowRef<HTMLCanvasElement>();
const chartEl2 = $ref<HTMLCanvasElement>(); const chartEl2 = $shallowRef<HTMLCanvasElement>();
let fetching = $ref(true); let fetching = $ref(true);
const { handler: externalTooltipHandler } = useChartTooltip(); const { handler: externalTooltipHandler } = useChartTooltip();

View File

@ -22,7 +22,7 @@ const fetching = ref(true);
const fetch = async () => { const fetch = async () => {
const fetchedInstances = await os.api('federation/instances', { const fetchedInstances = await os.api('federation/instances', {
sort: '+lastCommunicatedAt', sort: '+latestRequestReceivedAt',
limit: 6, limit: 6,
}); });
instances.value = fetchedInstances; instances.value = fetchedInstances;

View File

@ -3,7 +3,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted, ref, shallowRef } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import number from '@/filters/number'; import number from '@/filters/number';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
@ -16,7 +16,7 @@ const props = defineProps<{
data: { name: string; value: number; color: string; onClick?: () => void }[]; data: { name: string; value: number; color: string; onClick?: () => void }[];
}>(); }>();
const chartEl = ref<HTMLCanvasElement>(null); const chartEl = shallowRef<HTMLCanvasElement>(null);
const { handler: externalTooltipHandler } = useChartTooltip({ const { handler: externalTooltipHandler } = useChartTooltip({
position: 'middle', position: 'middle',

View File

@ -3,7 +3,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { watch, onMounted, onUnmounted, ref } from 'vue'; import { watch, onMounted, onUnmounted, ref, shallowRef } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import number from '@/filters/number'; import number from '@/filters/number';
import * as os from '@/os'; import * as os from '@/os';
@ -19,7 +19,7 @@ const props = defineProps<{
type: string; type: string;
}>(); }>();
const chartEl = ref<HTMLCanvasElement>(null); const chartEl = shallowRef<HTMLCanvasElement>(null);
const { handler: externalTooltipHandler } = useChartTooltip(); const { handler: externalTooltipHandler } = useChartTooltip();

View File

@ -43,10 +43,10 @@ const activeSincePrevTick = ref(0);
const active = ref(0); const active = ref(0);
const delayed = ref(0); const delayed = ref(0);
const waiting = ref(0); const waiting = ref(0);
let chartProcess = $ref<InstanceType<typeof XChart>>(); let chartProcess = $shallowRef<InstanceType<typeof XChart>>();
let chartActive = $ref<InstanceType<typeof XChart>>(); let chartActive = $shallowRef<InstanceType<typeof XChart>>();
let chartDelayed = $ref<InstanceType<typeof XChart>>(); let chartDelayed = $shallowRef<InstanceType<typeof XChart>>();
let chartWaiting = $ref<InstanceType<typeof XChart>>(); let chartWaiting = $shallowRef<InstanceType<typeof XChart>>();
const props = defineProps<{ const props = defineProps<{
domain: string; domain: string;

View File

@ -77,12 +77,11 @@ import * as os from '@/os';
import { stream } from '@/stream'; import { stream } from '@/stream';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import 'chartjs-adapter-date-fns';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue'; import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
import MkFolder from '@/components/MkFolder.vue'; import MkFolder from '@/components/MkFolder.vue';
const rootEl = $ref<HTMLElement>(); const rootEl = $shallowRef<HTMLElement>();
let serverInfo: any = $ref(null); let serverInfo: any = $ref(null);
let topSubInstancesForPie: any = $ref(null); let topSubInstancesForPie: any = $ref(null);
let topPubInstancesForPie: any = $ref(null); let topPubInstancesForPie: any = $ref(null);
@ -153,7 +152,7 @@ onMounted(async () => {
}); });
os.api('federation/instances', { os.api('federation/instances', {
sort: '+lastCommunicatedAt', sort: '+latestRequestReceivedAt',
limit: 25, limit: 25,
}).then(res => { }).then(res => {
activeInstances = res; activeInstances = res;

View File

@ -3,7 +3,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { watch, onMounted, onUnmounted, ref } from 'vue'; import { watch, onMounted, onUnmounted, ref, shallowRef } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import number from '@/filters/number'; import number from '@/filters/number';
import * as os from '@/os'; import * as os from '@/os';
@ -19,7 +19,7 @@ const props = defineProps<{
type: string; type: string;
}>(); }>();
const chartEl = ref<HTMLCanvasElement>(null); const chartEl = shallowRef<HTMLCanvasElement>(null);
const { handler: externalTooltipHandler } = useChartTooltip(); const { handler: externalTooltipHandler } = useChartTooltip();

View File

@ -53,10 +53,10 @@ const active = ref(0);
const delayed = ref(0); const delayed = ref(0);
const waiting = ref(0); const waiting = ref(0);
const jobs = ref([]); const jobs = ref([]);
let chartProcess = $ref<InstanceType<typeof XChart>>(); let chartProcess = $shallowRef<InstanceType<typeof XChart>>();
let chartActive = $ref<InstanceType<typeof XChart>>(); let chartActive = $shallowRef<InstanceType<typeof XChart>>();
let chartDelayed = $ref<InstanceType<typeof XChart>>(); let chartDelayed = $shallowRef<InstanceType<typeof XChart>>();
let chartWaiting = $ref<InstanceType<typeof XChart>>(); let chartWaiting = $shallowRef<InstanceType<typeof XChart>>();
const props = defineProps<{ const props = defineProps<{
domain: string; domain: string;

View File

@ -65,7 +65,7 @@ import { definePageMetadata } from '@/scripts/page-metadata';
import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkUserCardMini from '@/components/MkUserCardMini.vue';
import { dateString } from '@/filters/date'; import { dateString } from '@/filters/date';
let paginationComponent = $ref<InstanceType<typeof MkPagination>>(); let paginationComponent = $shallowRef<InstanceType<typeof MkPagination>>();
let sort = $ref('+createdAt'); let sort = $ref('+createdAt');
let state = $ref('all'); let state = $ref('all');

View File

@ -34,8 +34,8 @@ const props = defineProps<{
let antenna = $ref(null); let antenna = $ref(null);
let queue = $ref(0); let queue = $ref(0);
let rootEl = $ref<HTMLElement>(); let rootEl = $shallowRef<HTMLElement>();
let tlEl = $ref<InstanceType<typeof XTimeline>>(); let tlEl = $shallowRef<InstanceType<typeof XTimeline>>();
const keymap = $computed(() => ({ const keymap = $computed(() => ({
't': focus, 't': focus,
})); }));

View File

@ -72,7 +72,7 @@ const props = defineProps<{
}>(); }>();
let origin = $ref('local'); let origin = $ref('local');
let tagsEl = $ref<InstanceType<typeof MkFolder>>(); let tagsEl = $shallowRef<InstanceType<typeof MkFolder>>();
let tagsLocal = $ref([]); let tagsLocal = $ref([]);
let tagsRemote = $ref([]); let tagsRemote = $ref([]);

View File

@ -51,7 +51,7 @@ const props = withDefaults(defineProps<{
}); });
let tab = $ref(props.initialTab); let tab = $ref(props.initialTab);
let tagsEl = $ref<InstanceType<typeof MkFolder>>(); let tagsEl = $shallowRef<InstanceType<typeof MkFolder>>();
let searchQuery = $ref(null); let searchQuery = $ref(null);
let searchOrigin = $ref('combined'); let searchOrigin = $ref('combined');

Some files were not shown because too many files have changed in this diff Show More