mirror of
https://github.com/MisskeyIO/misskey
synced 2024-11-23 14:46:40 +09:00
Merge remote-tracking branch 'misskey-dev/develop' into io
This commit is contained in:
commit
2be209b0a5
@ -1,7 +1,7 @@
|
||||
## Unreleased
|
||||
|
||||
### General
|
||||
-
|
||||
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
|
||||
|
||||
### Client
|
||||
- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
|
||||
@ -13,6 +13,8 @@
|
||||
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
|
||||
- Fix: 周年の実績が閏年を考慮しない問題を修正
|
||||
- Fix: ローカルURLのプレビューポップアップが左上に表示される
|
||||
- Fix: WebGL2をサポートしないブラウザで「季節に応じた画面の演出」が有効になっているとき、Misskeyが起動できなくなる問題を修正
|
||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
|
||||
|
||||
### Server
|
||||
- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
|
||||
|
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
@ -8823,6 +8823,10 @@ export interface Locale extends ILocale {
|
||||
* 説明
|
||||
*/
|
||||
"summary": string;
|
||||
/**
|
||||
* 非公開に設定するとプロフィールに表示されなくなりますが、URLを知っている人は引き続きアクセスできます。
|
||||
*/
|
||||
"visibilityDescription": string;
|
||||
};
|
||||
"_pages": {
|
||||
/**
|
||||
|
@ -2330,6 +2330,7 @@ _play:
|
||||
title: "タイトル"
|
||||
script: "スクリプト"
|
||||
summary: "説明"
|
||||
visibilityDescription: "非公開に設定するとプロフィールに表示されなくなりますが、URLを知っている人は引き続きアクセスできます。"
|
||||
|
||||
_pages:
|
||||
newPage: "ページの作成"
|
||||
|
@ -459,13 +459,15 @@ export default abstract class Chart<T extends Schema> {
|
||||
}
|
||||
}
|
||||
|
||||
// bake unique count
|
||||
// bake cardinality
|
||||
for (const [k, v] of Object.entries(finalDiffs)) {
|
||||
if (this.schema[k].uniqueIncrement) {
|
||||
const name = COLUMN_PREFIX + k.replaceAll('.', COLUMN_DELIMITER) as keyof Columns<T>;
|
||||
const tempColumnName = UNIQUE_TEMP_COLUMN_PREFIX + k.replaceAll('.', COLUMN_DELIMITER) as keyof TempColumnsForUnique<T>;
|
||||
queryForHour[name] = new Set([...(v as string[]), ...(logHour[tempColumnName] as unknown as string[])]).size;
|
||||
queryForDay[name] = new Set([...(v as string[]), ...(logDay[tempColumnName] as unknown as string[])]).size;
|
||||
const cardinalityOfHour = new Set([...(v as string[]), ...(logHour[tempColumnName] as unknown as string[])]).size;
|
||||
const cardinalityOfDay = new Set([...(v as string[]), ...(logDay[tempColumnName] as unknown as string[])]).size;
|
||||
queryForHour[name] = cardinalityOfHour;
|
||||
queryForDay[name] = cardinalityOfDay;
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,7 +639,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
// 要求された範囲にログがひとつもなかったら
|
||||
if (logs.length === 0) {
|
||||
// もっとも新しいログを持ってくる
|
||||
// (すくなくともひとつログが無いと隙間埋めできないため)
|
||||
// (すくなくともひとつログが無いと補間できないため)
|
||||
const recentLog = await repository.findOne({
|
||||
where: group ? {
|
||||
group: group,
|
||||
@ -654,7 +656,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
// 要求された範囲の最も古い箇所に位置するログが存在しなかったら
|
||||
} else if (!isTimeSame(new Date(logs[logs.length - 1].date * 1000), gt)) {
|
||||
// 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する
|
||||
// (隙間埋めできないため)
|
||||
// (補間できないため)
|
||||
const outdatedLog = await repository.findOne({
|
||||
where: {
|
||||
date: LessThan(Chart.dateToTimestamp(gt)),
|
||||
@ -683,7 +685,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
if (log) {
|
||||
chart.unshift(this.convertRawRecord(log));
|
||||
} else {
|
||||
// 隙間埋め
|
||||
// 補間
|
||||
const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current));
|
||||
const data = latest ? this.convertRawRecord(latest) : null;
|
||||
chart.unshift(this.getNewLog(data));
|
||||
|
@ -45,7 +45,7 @@ export const paramDef = {
|
||||
permissions: { type: 'array', items: {
|
||||
type: 'string',
|
||||
} },
|
||||
visibility: { type: 'string', enum: ['public', 'private'] },
|
||||
visibility: { type: 'string', enum: ['public', 'private'], default: 'public' },
|
||||
},
|
||||
required: ['title', 'summary', 'script', 'permissions'],
|
||||
} as const;
|
||||
|
@ -76,26 +76,31 @@ export async function mainBoot() {
|
||||
},
|
||||
};
|
||||
|
||||
if (defaultStore.state.enableSeasonalScreenEffect) {
|
||||
const month = new Date().getMonth() + 1;
|
||||
if (defaultStore.state.hemisphere === 'S') {
|
||||
// ▼南半球
|
||||
if (month === 7 || month === 8) {
|
||||
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||
new SnowfallEffect({}).render();
|
||||
try {
|
||||
if (defaultStore.state.enableSeasonalScreenEffect) {
|
||||
const month = new Date().getMonth() + 1;
|
||||
if (defaultStore.state.hemisphere === 'S') {
|
||||
// ▼南半球
|
||||
if (month === 7 || month === 8) {
|
||||
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||
new SnowfallEffect({}).render();
|
||||
}
|
||||
} else {
|
||||
// ▼北半球
|
||||
if (month === 12 || month === 1) {
|
||||
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||
new SnowfallEffect({}).render();
|
||||
} else if (month === 3 || month === 4) {
|
||||
const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||
new SakuraEffect({
|
||||
sakura: true,
|
||||
}).render();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ▼北半球
|
||||
if (month === 12 || month === 1) {
|
||||
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||
new SnowfallEffect({}).render();
|
||||
} else if (month === 3 || month === 4) {
|
||||
const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||
new SakuraEffect({
|
||||
sakura: true,
|
||||
}).render();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error(error);
|
||||
console.error('Failed to initialise the seasonal screen effect canvas context:', error);
|
||||
}
|
||||
|
||||
if ($i) {
|
||||
|
@ -18,16 +18,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkCodeEditor v-model="script" lang="is">
|
||||
<template #label>{{ i18n.ts._play.script }}</template>
|
||||
</MkCodeEditor>
|
||||
<MkSelect v-model="visibility">
|
||||
<template #label>{{ i18n.ts.visibility }}</template>
|
||||
<template #caption>{{ i18n.ts._play.visibilityDescription }}</template>
|
||||
<option :key="'public'" :value="'public'">{{ i18n.ts.public }}</option>
|
||||
<option :key="'private'" :value="'private'">{{ i18n.ts.private }}</option>
|
||||
</MkSelect>
|
||||
<div class="_buttons">
|
||||
<MkButton primary @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
<MkButton @click="show"><i class="ti ti-eye"></i> {{ i18n.ts.show }}</MkButton>
|
||||
<MkButton v-if="flash" danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
||||
</div>
|
||||
<MkSelect v-model="visibility">
|
||||
<template #label>{{ i18n.ts.visibility }}</template>
|
||||
<option :key="'public'" :value="'public'">{{ i18n.ts.public }}</option>
|
||||
<option :key="'private'" :value="'private'">{{ i18n.ts.private }}</option>
|
||||
</MkSelect>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
|
@ -156,6 +156,9 @@ export class SnowfallEffect {
|
||||
easing: 0.0005,
|
||||
};
|
||||
|
||||
/**
|
||||
* @throws {Error} - Thrown when it fails to get WebGL context for the canvas
|
||||
*/
|
||||
constructor(options: {
|
||||
sakura?: boolean;
|
||||
}) {
|
||||
|
@ -8,7 +8,12 @@ import { markRaw } from 'vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { wsOrigin } from '@/config.js';
|
||||
|
||||
// heart beat interval in ms
|
||||
const HEART_BEAT_INTERVAL = 1000 * 60;
|
||||
|
||||
let stream: Misskey.Stream | null = null;
|
||||
let timeoutHeartBeat: ReturnType<typeof setTimeout> | null = null;
|
||||
let lastHeartbeatCall = 0;
|
||||
|
||||
export function useStream(): Misskey.Stream {
|
||||
if (stream) return stream;
|
||||
@ -17,7 +22,18 @@ export function useStream(): Misskey.Stream {
|
||||
token: $i.token,
|
||||
} : null));
|
||||
|
||||
window.setTimeout(heartbeat, 1000 * 60);
|
||||
if (timeoutHeartBeat) window.clearTimeout(timeoutHeartBeat);
|
||||
timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL);
|
||||
|
||||
// send heartbeat right now when last send time is over HEART_BEAT_INTERVAL
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (
|
||||
!stream
|
||||
|| document.visibilityState !== 'visible'
|
||||
|| Date.now() - lastHeartbeatCall < HEART_BEAT_INTERVAL
|
||||
) return;
|
||||
heartbeat();
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
@ -26,5 +42,7 @@ function heartbeat(): void {
|
||||
if (stream != null && document.visibilityState === 'visible') {
|
||||
stream.heartbeat();
|
||||
}
|
||||
window.setTimeout(heartbeat, 1000 * 60);
|
||||
lastHeartbeatCall = Date.now();
|
||||
if (timeoutHeartBeat) window.clearTimeout(timeoutHeartBeat);
|
||||
timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL);
|
||||
}
|
||||
|
@ -23749,7 +23749,10 @@ export type operations = {
|
||||
summary: string;
|
||||
script: string;
|
||||
permissions: string[];
|
||||
/** @enum {string} */
|
||||
/**
|
||||
* @default public
|
||||
* @enum {string}
|
||||
*/
|
||||
visibility?: 'public' | 'private';
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user