Zgwfdl_M$Toghr7@@g@e7FXe44Ak+x$bs+!>{Sg!Be7b_Db`fwBX&T
z@l~l^P_!i)YkIMOoHtL!PyLm;JeW$yG7>DTq`>U0ACYd|2l=G9U8HVxl1!bdeBDI5
zsbY^TDb^7u3D2CltH)mUO
zwQY?3mgQvcH-X{VDR
zTNJ8WtF6`3(HuUb-?%7@CFlGN0XuXzd-o>%2J%tqoI2$tMmhpl)F5Nb1HRsIb+a9<
ziYdlL)iu^!$$j9f>eGF{&L-!pt9YDkna4dAY{e+)53DY&VH}c&Tt_CI@>HK}P`9Xo
z&jA$nzRnkm@-fp)0H$t-ehA^*+Z!vP5^A6e@O4;Kt}+2~xTBWXE0;%sG~QNGY7<6!
zE@S&ea@M=+-rV>)(`K)Ig_rYm9`Yx6qHZH@s-u^NgKB<4fp~?E+9Xa0K1e22BJXeV
zZk7r1vn)ekvy3c1L;%VVMMt^z38
zpF0izwLY)RjHHc(9krEpmLlOwA_4rFg{Ks_=E&+?eNW1W|CF`a>-BkuS>kkD#US(s
zw1Hy8$ZSKtuP^4%wp$tZDrNKk4
z1*Vjpc-LT5_hbe9I!EIzgAT`=ppBEUliRI7|g
zFr#5kA@nRDoz-#e{1!nX6mzcY{9f_L;sk>w8IhuGc2_-SRH#%FH2%8#LB_N)J;3oD
zQ(v8ZV|7=$iRppfqF1hBb-Lo1R?ec2ZnT1ATV-mB>f36g8oUj@?R-oD)?8zW1_S}|
zNIB&D$A*`oY=+l+JWL{nG~2Bo_C7RAf6^;|Ol0Bi2QE>3g{&dU+^ee>y38nUOpc8@
z$bKklmz8Z}%%iwvHkmUt#Htxn@wcxTQ)k6I-yu%`~eZnc;_$Iqn@nxAWl&?!;32DRj=CBmvolE@5UY58K&CwSWa{ubA!hS5EH#~i1HUIhfOgHf?c_jPF&{&>!#
zs16lNQ;}sHa0^>bPrDqYGr4Yb=Z)A_eki?s!T8$w(!%A^-}JVIcyOemITX0KV42c69Je=W5MR24c^
zMEVGSNs~Ti#AO16=^B!z(&@UDVh?lWfP-sRPe*I6T4{%~w|VEjCxx+-$SeEkVoGta
zsUk#2FKBvji1?bqw`f`ES@o`oSD$|{Y{WZU2#nGadDIkbF_e&KzP$4<3NG6i{m>Ep
za~8$d@eEy~{InWxiCP~yt((*(i?JWQl=t*il3pwjvPjG{a7{iBla=ApV37sO>`Y@6
z7JWQ_TB^y!rS?nXhgB8oK)=+ETP~;5;p&5((w|j6nhux=$l}+RuAcel?d5;gT1XdQ%`%sinj*Zh#%xMpP&WSe}v~|yA(M)aO`}>dM%Fw|pBfiggyHjzQ
z34Y=lz+Q#Ea{(-D;
z)Wuw3m+@uOfeBB{r|bF(kGczszm#fJVNSXKu-5+sfnVIM*Usy;)W#O-U%3ZPP={p1LCbBiYF`Al(>uc+n9dMp
zLJJS(Gq91xOpnmLard|;WrBod#JPz&I4~Dqd!c#cs(MYjYWZE;INkn(PQIO6
zN+{bVnvy3^La7nwEgPd4AF2I&aCq%POVjnKwsg{gsG?+6m2x8C(++J?V-eaHDcmU<
zmw4cFcJ*4^nhsohW}|Ppbx62<{a`okZ9HZ-caFL-gsnZ3khpe+@^dN$io2KOYG&zJ
zn4`9h{1ifA({)|>MMG`2EYbC_PDRheHP_zbGNGlTmdmPRNq!C&T^%wV=yyo>wU%qF
zi^l*4hzCa4wJn3yYN__d=7O6lDVYhF!ifQfyH}#Y4#d7HAGVlg
z&|SzGp@HvcpJZjsj6oyzZcHyM1zjypYfQ#Dxnio<-M&BNz&t8hK7oaU+=c%lM*>ZxV)xp|Xz}-aeDCtB=Bw{vv!Xd4J&TQjU`7c9la?|4CS#^9
z#J(S|*jeR^pJ{PL0qEtpKSo~!7`DnpH1sTKAPQ8aPy+12d$b2m)WYi90*+XuF&tLh
zKijyRdi|MmIJF*KS9EusSZaFzs!AJA;#2+fn4Pv{99aTo-X-*DLhHoE#X{%^smHZp
zm5~^AQ_)HDSe7)U5y6i+5*k=H`10{QAM#qoF9eb<8?=M`UB7(p+`f7CtUkwZ#W4dW
z=>JRHe7{E^>YH%VA8{6Fb3?GVKWdgo&K*trv1(;fqWU~RP`z}`1@Giopmt~5NF%*K
zVNm*IfA<9HW4u%W>_yO-g#C*wU1r>sL4Mh
z=i;jo(G@}~BGFj@On?Rbyk|%-MPx%jWHcUW#qW6RC|8g9!cA_g+!a$C0_1OzNhCMx
zQi{J-_GZ`p(C6P~&!D_>wFhC^NqR>V_bd7A4ujr!`JujICl_SFMbKMvt&i^^#g%T&
zjg%ZAHz#;To=h!JoF@3YB>BVVl%L59&g@a@h4QennPL)V2|t0s-ggxnx(zvA$OK^p
z-RSV6Bp`b>&7EKgdLVmD5j%r%NV*08ER9}5i)gb#gzA-}n%P^5g9Gg?i)*t+Ixb0G
zbNlh-GCV~urO}fgkSM3L8aneM6$dW9<57DQXXbBszHszI72CplFHJ3Ih}B0;!p
zq|28+F1~ZRU-V*5g?{26Up4v`KfU|ifsU5uC671}@i`jWpS6HjmC4chcVf@Qda1hs
z07QL9XJ;>Xgbt2gHc&VRY!RbUKLOsh4?h(10ssU&UH_r~qX4h|uQK>Qn*TQm0d5oK
z;RdmXHyV4`|K$_$KR*Ap2KW0P0{-RVzx@2G`L7!IU*T^~X9@Lihl`Y!4(=ZRG{G$Z
z&*0~J{)riQ>j<@lz}rBM(Esjxg){(Q60Fnz*OTlvPzSevYyjMyJ)QoQpSTvh43&pC
zK^-igbby79woX=X0oUE}Z=+92aH50$T~7&hvwUiQqNgrldb&A){+5BZ?jGh2aM{}3
z!~L&h{9O;wgP%xx3iOGdp81;)0Ju-WQ>bv_v2=$%br^sc92`soS3`nxLNL)&6#~%e
z3GiQ2Faka<3Y-Dqc>sXiJ^mV_zf|Bi5&!_{Nrt-s2E#ceJPeDc3OGHveFEt}+yma`
z2bcdPcs&sA9(WA*#s=qOaP-0v3r9K}d2qlFSpi{ic*6l70^n;n;NAU8HimOkI1J!`
zz+nxC9USnv38aKOd72M|?j9D-|2TY#1?~qx?r!Y@eJZ#)JHTzhPjSH?czlH4Dc#Mj
zUEuuRmj4;OxhK>E?ge1zX!#d^QltK#S%%LHH;9YNlg0l{?6!YTCHhhi=ch2J;K#zA
Vj64|zC_}ug_yjq)IN=xP{{mAaTcH2|
literal 0
HcmV?d00001
diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts
index 2eec80d76346..40d187f5a882 100644
--- a/packages/backend/test/unit/FileInfoService.ts
+++ b/packages/backend/test/unit/FileInfoService.ts
@@ -15,6 +15,7 @@ import { GlobalModule } from '@/GlobalModule.js';
import { FileInfoService } from '@/core/FileInfoService.js';
//import { DI } from '@/di-symbols.js';
import { AiService } from '@/core/AiService.js';
+import { LoggerService } from '@/core/LoggerService.js';
import type { TestingModule } from '@nestjs/testing';
import type { MockFunctionMetadata } from 'jest-mock';
@@ -35,6 +36,7 @@ describe('FileInfoService', () => {
],
providers: [
AiService,
+ LoggerService,
FileInfoService,
],
})
@@ -323,8 +325,26 @@ describe('FileInfoService', () => {
});
});
- /*
- * video/webmとして検出されてしまう
+ test('MPEG-4 AUDIO (M4A)', async () => {
+ const path = `${resources}/kick_gaba7.m4a`;
+ const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
+ delete info.warnings;
+ delete info.blurhash;
+ delete info.sensitive;
+ delete info.porn;
+ delete info.width;
+ delete info.height;
+ delete info.orientation;
+ assert.deepStrictEqual(info, {
+ size: 9817,
+ md5: '74c9279a4abe98789565f1dc1a541a42',
+ type: {
+ mime: 'audio/mp4',
+ ext: 'm4a',
+ },
+ });
+ });
+
test('WEBM AUDIO', async () => {
const path = `${resources}/kick_gaba7.webm`;
const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
@@ -337,13 +357,12 @@ describe('FileInfoService', () => {
delete info.orientation;
assert.deepStrictEqual(info, {
size: 8879,
- md5: '3350083dec312419cfdc06c16413aca7',
+ md5: '53bc1adcb6acbbda67ff9bd484896438',
type: {
mime: 'audio/webm',
ext: 'webm',
},
});
});
- */
});
});
From 61978cb4ca481f099828ef1b0b95258029937008 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 31 Mar 2024 14:16:42 +0900
Subject: [PATCH 004/133] =?UTF-8?q?fix(frontend):=20=E3=83=9A=E3=83=BC?=
=?UTF-8?q?=E3=82=B8=E3=83=87=E3=82=B6=E3=82=A4=E3=83=B3=E3=81=AE=E4=BF=AE?=
=?UTF-8?q?=E6=AD=A3=20(#13642)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
locales/index.d.ts | 8 ++++
locales/ja-JP.yml | 3 +-
.../src/components/page/page.block.vue | 15 +++++++
.../src/components/page/page.dynamic.vue | 43 +++++++++++++++++++
.../src/components/page/page.text.vue | 2 +-
5 files changed, 69 insertions(+), 2 deletions(-)
create mode 100644 packages/frontend/src/components/page/page.dynamic.vue
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 3dbe46c7b2f6..01bec41d9e9f 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -8830,6 +8830,14 @@ export interface Locale extends ILocale {
* ボタン
*/
"button": string;
+ /**
+ * 動的ブロック
+ */
+ "dynamic": string;
+ /**
+ * このブロックは廃止されています。今後は{play}を利用してください。
+ */
+ "dynamicDescription": ParameterizedString<"play">;
/**
* ノート埋め込み
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index aa765d13108f..4ba9ea0221b1 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2331,6 +2331,8 @@ _pages:
section: "セクション"
image: "画像"
button: "ボタン"
+ dynamic: "動的ブロック"
+ dynamicDescription: "このブロックは廃止されています。今後は{play}を利用してください。"
note: "ノート埋め込み"
_note:
@@ -2625,4 +2627,3 @@ _mediaControls:
pip: "ピクチャインピクチャ"
playbackRate: "再生速度"
loop: "ループ再生"
-
\ No newline at end of file
diff --git a/packages/frontend/src/components/page/page.block.vue b/packages/frontend/src/components/page/page.block.vue
index 164720ac6bd0..c7f72dce8cf4 100644
--- a/packages/frontend/src/components/page/page.block.vue
+++ b/packages/frontend/src/components/page/page.block.vue
@@ -14,6 +14,7 @@ import XText from './page.text.vue';
import XSection from './page.section.vue';
import XImage from './page.image.vue';
import XNote from './page.note.vue';
+import XDynamic from './page.dynamic.vue';
function getComponent(type: string) {
switch (type) {
@@ -21,6 +22,20 @@ function getComponent(type: string) {
case 'section': return XSection;
case 'image': return XImage;
case 'note': return XNote;
+
+ // 動的ページの代替用ブロック
+ case 'button':
+ case 'if':
+ case 'textarea':
+ case 'post':
+ case 'canvas':
+ case 'numberInput':
+ case 'textInput':
+ case 'switch':
+ case 'radioButton':
+ case 'counter':
+ return XDynamic;
+
default: return null;
}
}
diff --git a/packages/frontend/src/components/page/page.dynamic.vue b/packages/frontend/src/components/page/page.dynamic.vue
new file mode 100644
index 000000000000..8c511a690da4
--- /dev/null
+++ b/packages/frontend/src/components/page/page.dynamic.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
{{ i18n.ts._pages.blocks.dynamic }}
+
+
+ Play
+
+
+
+
+
+
+
+
diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue
index 4e501bd6999e..e0c7956f6e34 100644
--- a/packages/frontend/src/components/page/page.text.vue
+++ b/packages/frontend/src/components/page/page.text.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
From b4b47d85cf50486980cc3fa3575cf48c7fb0a2e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 1 Apr 2024 20:44:24 +0900
Subject: [PATCH 005/133] refactor(frontend): use `scrollX` or `scrollY`
(#13645)
---
.../frontend/src/components/MkContextMenu.vue | 8 ++--
packages/frontend/src/components/MkModal.vue | 24 ++++++------
.../src/components/MkUrlPreviewPopup.vue | 4 +-
.../frontend/src/components/MkUserPopup.vue | 4 +-
.../frontend/src/scripts/popup-position.ts | 38 +++++++++----------
.../frontend/src/scripts/use-chart-tooltip.ts | 6 +--
6 files changed, 42 insertions(+), 42 deletions(-)
diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue
index 5ca3c77fb23f..a807742bb9ba 100644
--- a/packages/frontend/src/components/MkContextMenu.vue
+++ b/packages/frontend/src/components/MkContextMenu.vue
@@ -47,12 +47,12 @@ onMounted(() => {
const width = rootEl.value!.offsetWidth;
const height = rootEl.value!.offsetHeight;
- if (left + width - window.pageXOffset >= (window.innerWidth - SCROLLBAR_THICKNESS)) {
- left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.pageXOffset;
+ if (left + width - window.scrollX >= (window.innerWidth - SCROLLBAR_THICKNESS)) {
+ left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.scrollX;
}
- if (top + height - window.pageYOffset >= (window.innerHeight - SCROLLBAR_THICKNESS)) {
- top = (window.innerHeight - SCROLLBAR_THICKNESS) - height + window.pageYOffset;
+ if (top + height - window.scrollY >= (window.innerHeight - SCROLLBAR_THICKNESS)) {
+ top = (window.innerHeight - SCROLLBAR_THICKNESS) - height + window.scrollY;
}
if (top < 0) {
diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue
index 40e67fb4e088..eb240da75978 100644
--- a/packages/frontend/src/components/MkModal.vue
+++ b/packages/frontend/src/components/MkModal.vue
@@ -175,8 +175,8 @@ const align = () => {
let left;
let top;
- const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
- const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
+ const x = srcRect.left + (fixed.value ? 0 : window.scrollX);
+ const y = srcRect.top + (fixed.value ? 0 : window.scrollY);
if (props.anchor.x === 'center') {
left = x + (props.src.offsetWidth / 2) - (width / 2);
@@ -220,24 +220,24 @@ const align = () => {
}
} else {
// 画面から横にはみ出る場合
- if (left + width - window.pageXOffset > (window.innerWidth - SCROLLBAR_THICKNESS)) {
- left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.pageXOffset - 1;
+ if (left + width - window.scrollX > (window.innerWidth - SCROLLBAR_THICKNESS)) {
+ left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.scrollX - 1;
}
- const underSpace = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - (top - window.pageYOffset);
+ const underSpace = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - (top - window.scrollY);
const upperSpace = (srcRect.top - MARGIN);
// 画面から縦にはみ出る場合
- if (top + height - window.pageYOffset > ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN)) {
+ if (top + height - window.scrollY > ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN)) {
if (props.noOverlap && props.anchor.x === 'center') {
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
- top = window.pageYOffset + ((upperSpace + MARGIN) - height);
+ top = window.scrollY + ((upperSpace + MARGIN) - height);
}
} else {
- top = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - height + window.pageYOffset - 1;
+ top = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - height + window.scrollY - 1;
}
} else {
maxHeight.value = underSpace;
@@ -255,15 +255,15 @@ const align = () => {
let transformOriginX = 'center';
let transformOriginY = 'center';
- if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.pageYOffset)) {
+ if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.scrollY)) {
transformOriginY = 'top';
- } else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.pageYOffset)) {
+ } else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.scrollY)) {
transformOriginY = 'bottom';
}
- if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.pageXOffset)) {
+ if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.scrollX)) {
transformOriginX = 'left';
- } else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.pageXOffset)) {
+ } else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.scrollX)) {
transformOriginX = 'right';
}
diff --git a/packages/frontend/src/components/MkUrlPreviewPopup.vue b/packages/frontend/src/components/MkUrlPreviewPopup.vue
index cf75064be795..e972973dbaf6 100644
--- a/packages/frontend/src/components/MkUrlPreviewPopup.vue
+++ b/packages/frontend/src/components/MkUrlPreviewPopup.vue
@@ -33,8 +33,8 @@ const left = ref(0);
onMounted(() => {
const rect = props.source.getBoundingClientRect();
- const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.pageXOffset;
- const y = rect.top + props.source.offsetHeight + window.pageYOffset;
+ const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.scrollX;
+ const y = rect.top + props.source.offsetHeight + window.scrollY;
top.value = y;
left.value = x;
diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue
index fb1a8f4fdc97..41b27a1afb1d 100644
--- a/packages/frontend/src/components/MkUserPopup.vue
+++ b/packages/frontend/src/components/MkUserPopup.vue
@@ -106,8 +106,8 @@ onMounted(() => {
}
const rect = props.source.getBoundingClientRect();
- const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.pageXOffset;
- const y = rect.top + props.source.offsetHeight + window.pageYOffset;
+ const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.scrollX;
+ const y = rect.top + props.source.offsetHeight + window.scrollY;
top.value = y;
left.value = x;
diff --git a/packages/frontend/src/scripts/popup-position.ts b/packages/frontend/src/scripts/popup-position.ts
index 8c9e3c02c36d..3dad41a8b31f 100644
--- a/packages/frontend/src/scripts/popup-position.ts
+++ b/packages/frontend/src/scripts/popup-position.ts
@@ -26,8 +26,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
let top: number;
if (props.anchorElement) {
- left = rect.left + window.pageXOffset + (props.anchorElement.offsetWidth / 2);
- top = (rect.top + window.pageYOffset - contentHeight) - props.innerMargin;
+ left = rect.left + window.scrollX + (props.anchorElement.offsetWidth / 2);
+ top = (rect.top + window.scrollY - contentHeight) - props.innerMargin;
} else {
left = props.x;
top = (props.y - contentHeight) - props.innerMargin;
@@ -35,8 +35,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
left -= (el.offsetWidth / 2);
- if (left + contentWidth - window.pageXOffset > window.innerWidth) {
- left = window.innerWidth - contentWidth + window.pageXOffset - 1;
+ if (left + contentWidth - window.scrollX > window.innerWidth) {
+ left = window.innerWidth - contentWidth + window.scrollX - 1;
}
return [left, top];
@@ -47,8 +47,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
let top: number;
if (props.anchorElement) {
- left = rect.left + window.pageXOffset + (props.anchorElement.offsetWidth / 2);
- top = (rect.top + window.pageYOffset + props.anchorElement.offsetHeight) + props.innerMargin;
+ left = rect.left + window.scrollX + (props.anchorElement.offsetWidth / 2);
+ top = (rect.top + window.scrollY + props.anchorElement.offsetHeight) + props.innerMargin;
} else {
left = props.x;
top = (props.y) + props.innerMargin;
@@ -56,8 +56,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
left -= (el.offsetWidth / 2);
- if (left + contentWidth - window.pageXOffset > window.innerWidth) {
- left = window.innerWidth - contentWidth + window.pageXOffset - 1;
+ if (left + contentWidth - window.scrollX > window.innerWidth) {
+ left = window.innerWidth - contentWidth + window.scrollX - 1;
}
return [left, top];
@@ -68,8 +68,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
let top: number;
if (props.anchorElement) {
- left = (rect.left + window.pageXOffset - contentWidth) - props.innerMargin;
- top = rect.top + window.pageYOffset + (props.anchorElement.offsetHeight / 2);
+ left = (rect.left + window.scrollX - contentWidth) - props.innerMargin;
+ top = rect.top + window.scrollY + (props.anchorElement.offsetHeight / 2);
} else {
left = (props.x - contentWidth) - props.innerMargin;
top = props.y;
@@ -77,8 +77,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
top -= (el.offsetHeight / 2);
- if (top + contentHeight - window.pageYOffset > window.innerHeight) {
- top = window.innerHeight - contentHeight + window.pageYOffset - 1;
+ if (top + contentHeight - window.scrollY > window.innerHeight) {
+ top = window.innerHeight - contentHeight + window.scrollY - 1;
}
return [left, top];
@@ -89,15 +89,15 @@ export function calcPopupPosition(el: HTMLElement, props: {
let top: number;
if (props.anchorElement) {
- left = (rect.left + props.anchorElement.offsetWidth + window.pageXOffset) + props.innerMargin;
+ left = (rect.left + props.anchorElement.offsetWidth + window.scrollX) + props.innerMargin;
if (props.align === 'top') {
- top = rect.top + window.pageYOffset;
+ top = rect.top + window.scrollY;
if (props.alignOffset != null) top += props.alignOffset;
} else if (props.align === 'bottom') {
// TODO
} else { // center
- top = rect.top + window.pageYOffset + (props.anchorElement.offsetHeight / 2);
+ top = rect.top + window.scrollY + (props.anchorElement.offsetHeight / 2);
top -= (el.offsetHeight / 2);
}
} else {
@@ -106,8 +106,8 @@ export function calcPopupPosition(el: HTMLElement, props: {
top -= (el.offsetHeight / 2);
}
- if (top + contentHeight - window.pageYOffset > window.innerHeight) {
- top = window.innerHeight - contentHeight + window.pageYOffset - 1;
+ if (top + contentHeight - window.scrollY > window.innerHeight) {
+ top = window.innerHeight - contentHeight + window.scrollY - 1;
}
return [left, top];
@@ -123,7 +123,7 @@ export function calcPopupPosition(el: HTMLElement, props: {
const [left, top] = calcPosWhenTop();
// ツールチップを上に向かって表示するスペースがなければ下に向かって出す
- if (top - window.pageYOffset < 0) {
+ if (top - window.scrollY < 0) {
const [left, top] = calcPosWhenBottom();
return { left, top, transformOrigin: 'center top' };
}
@@ -141,7 +141,7 @@ export function calcPopupPosition(el: HTMLElement, props: {
const [left, top] = calcPosWhenLeft();
// ツールチップを左に向かって表示するスペースがなければ右に向かって出す
- if (left - window.pageXOffset < 0) {
+ if (left - window.scrollX < 0) {
const [left, top] = calcPosWhenRight();
return { left, top, transformOrigin: 'left center' };
}
diff --git a/packages/frontend/src/scripts/use-chart-tooltip.ts b/packages/frontend/src/scripts/use-chart-tooltip.ts
index 7e4bf5c9c665..bed221a62255 100644
--- a/packages/frontend/src/scripts/use-chart-tooltip.ts
+++ b/packages/frontend/src/scripts/use-chart-tooltip.ts
@@ -53,11 +53,11 @@ export function useChartTooltip(opts: { position: 'top' | 'middle' } = { positio
const rect = context.chart.canvas.getBoundingClientRect();
tooltipShowing.value = true;
- tooltipX.value = rect.left + window.pageXOffset + context.tooltip.caretX;
+ tooltipX.value = rect.left + window.scrollX + context.tooltip.caretX;
if (opts.position === 'top') {
- tooltipY.value = rect.top + window.pageYOffset;
+ tooltipY.value = rect.top + window.scrollY;
} else if (opts.position === 'middle') {
- tooltipY.value = rect.top + window.pageYOffset + context.tooltip.caretY;
+ tooltipY.value = rect.top + window.scrollY + context.tooltip.caretY;
}
}
From c4fc582469a2596a4802496367699b9e04aed9f7 Mon Sep 17 00:00:00 2001
From: Jorge <46056498+jorgectf@users.noreply.github.com>
Date: Wed, 3 Apr 2024 06:02:36 +0200
Subject: [PATCH 006/133] Merge pull request from GHSA-fpvp-74wx-35p3
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
.github/workflows/storybook.yml | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index 87481b12cf19..ca82f4bcf3de 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -87,12 +87,13 @@ jobs:
if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
- BRANCH="${{ github.event.pull_request.head.user.login }}:${{ github.event.pull_request.head.ref }}"
- if [ "$BRANCH" = "misskey-dev:${{ github.event.pull_request.head.ref }}" ]; then
- BRANCH="${{ github.event.pull_request.head.ref }}"
+ BRANCH="${{ github.event.pull_request.head.user.login }}:$HEAD_REF"
+ if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then
+ BRANCH="$HEAD_REF"
fi
pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name $BRANCH $(echo "$CHROMATIC_PARAMETER")
env:
+ HEAD_REF: ${{ github.event.pull_request.head.ref }}
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- name: Notify that Chromatic detects changes
uses: actions/github-script@v7.0.1
From efa42a1624b0727232263f4ec196e4908ef1e712 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
<46447427+samunohito@users.noreply.github.com>
Date: Thu, 4 Apr 2024 22:25:28 +0900
Subject: [PATCH 007/133] =?UTF-8?q?fix(backend):=20=E3=83=90=E3=83=83?=
=?UTF-8?q?=E3=82=AF=E3=82=A8=E3=83=B3=E3=83=89=E3=81=AEpnpm=20dev?=
=?UTF-8?q?=E3=81=AB=E3=82=88=E3=82=8B=E3=83=93=E3=83=AB=E3=83=89=E5=BE=8C?=
=?UTF-8?q?=E3=81=ABbuild-assets=E3=82=92=E8=A1=8C=E3=81=86=E3=82=88?=
=?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#13659)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* moveto scripts
* add scripts/dev.mjs
---
packages/backend/package.json | 8 +--
.../backend/{ => scripts}/check_connect.js | 2 +-
packages/backend/scripts/dev.mjs | 61 +++++++++++++++++++
.../{ => scripts}/generate_api_json.js | 4 +-
packages/backend/{ => scripts}/watch.mjs | 0
pnpm-lock.yaml | 6 +-
6 files changed, 71 insertions(+), 10 deletions(-)
rename packages/backend/{ => scripts}/check_connect.js (85%)
create mode 100644 packages/backend/scripts/dev.mjs
rename packages/backend/{ => scripts}/generate_api_json.js (70%)
rename packages/backend/{ => scripts}/watch.mjs (100%)
diff --git a/packages/backend/package.json b/packages/backend/package.json
index d64fcc3d2a05..7f70ae0c975a 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -11,14 +11,14 @@
"start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js",
"migrate": "pnpm typeorm migration:run -d ormconfig.js",
"revert": "pnpm typeorm migration:revert -d ormconfig.js",
- "check:connect": "node ./check_connect.js",
+ "check:connect": "node ./scripts/check_connect.js",
"build": "swc src -d built -D",
"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc",
"watch:swc": "swc src -d built -D -w",
"build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
- "watch": "node watch.mjs",
+ "watch": "node ./scripts/watch.mjs",
"restart": "pnpm build && pnpm start",
- "dev": "nodemon -w src -e ts,js,mjs,cjs,json --exec \"cross-env NODE_ENV=development pnpm run restart\"",
+ "dev": "node ./scripts/dev.mjs",
"typecheck": "tsc --noEmit && tsc -p test --noEmit",
"eslint": "eslint --quiet \"src/**/*.ts\"",
"lint": "pnpm typecheck && pnpm eslint",
@@ -31,7 +31,7 @@
"test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e",
"test-and-coverage": "pnpm jest-and-coverage",
"test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e",
- "generate-api-json": "pnpm build && node ./generate_api_json.js"
+ "generate-api-json": "pnpm build && node ./scripts/generate_api_json.js"
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
diff --git a/packages/backend/check_connect.js b/packages/backend/scripts/check_connect.js
similarity index 85%
rename from packages/backend/check_connect.js
rename to packages/backend/scripts/check_connect.js
index d88e649c099d..ba25fd416c78 100644
--- a/packages/backend/check_connect.js
+++ b/packages/backend/scripts/check_connect.js
@@ -4,7 +4,7 @@
*/
import Redis from 'ioredis';
-import { loadConfig } from './built/config.js';
+import { loadConfig } from '../built/config.js';
const config = loadConfig();
const redis = new Redis(config.redis);
diff --git a/packages/backend/scripts/dev.mjs b/packages/backend/scripts/dev.mjs
new file mode 100644
index 000000000000..2d0de0f91666
--- /dev/null
+++ b/packages/backend/scripts/dev.mjs
@@ -0,0 +1,61 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { execa, execaNode } from 'execa';
+
+/** @type {import('execa').ExecaChildProcess | undefined} */
+let backendProcess;
+
+async function execBuildAssets() {
+ await execa('pnpm', ['run', 'build-assets'], {
+ cwd: '../../',
+ stdout: process.stdout,
+ stderr: process.stderr,
+ })
+}
+
+function execStart() {
+ // pnpm run start を呼び出したいが、windowsだとプロセスグループ単位でのkillが出来ずゾンビプロセス化するので
+ // 上記と同等の動きをするコマンドで子・孫プロセスを作らないようにしたい
+ backendProcess = execaNode('./built/boot/entry.js', [], {
+ stdout: process.stdout,
+ stderr: process.stderr,
+ env: {
+ 'NODE_ENV': 'development',
+ },
+ });
+}
+
+async function killProc() {
+ if (backendProcess) {
+ backendProcess.kill();
+ await new Promise(resolve => backendProcess.on('exit', resolve));
+ backendProcess = undefined;
+ }
+}
+
+(async () => {
+ execaNode(
+ './node_modules/nodemon/bin/nodemon.js',
+ [
+ '-w', 'src',
+ '-e', 'ts,js,mjs,cjs,json',
+ '--exec', 'pnpm', 'run', 'build',
+ ],
+ {
+ stdio: [process.stdin, process.stdout, process.stderr, 'ipc'],
+ })
+ .on('message', async (message) => {
+ if (message.type === 'exit') {
+ // かならずbuild->build-assetsの順番で呼び出したいので、
+ // 少々トリッキーだがnodemonからのexitイベントを利用してbuild-assets->startを行う。
+ // pnpm restartをbuildが終わる前にbuild-assetsが動いてしまうので、バラバラに呼び出す必要がある
+
+ await killProc();
+ await execBuildAssets();
+ execStart();
+ }
+ })
+})();
diff --git a/packages/backend/generate_api_json.js b/packages/backend/scripts/generate_api_json.js
similarity index 70%
rename from packages/backend/generate_api_json.js
rename to packages/backend/scripts/generate_api_json.js
index 602ced1d7553..b4769ef8012e 100644
--- a/packages/backend/generate_api_json.js
+++ b/packages/backend/scripts/generate_api_json.js
@@ -3,8 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { loadConfig } from './built/config.js'
-import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
+import { loadConfig } from '../built/config.js'
+import { genOpenapiSpec } from '../built/server/api/openapi/gen-spec.js'
import { writeFileSync } from "node:fs";
const config = loadConfig();
diff --git a/packages/backend/watch.mjs b/packages/backend/scripts/watch.mjs
similarity index 100%
rename from packages/backend/watch.mjs
rename to packages/backend/scripts/watch.mjs
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 46512784c3ab..91c2a704e294 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6678,7 +6678,7 @@ packages:
ts-dedent: 2.2.0
type-fest: 2.19.0
vue: 3.4.21(typescript@5.3.3)
- vue-component-type-helpers: 2.0.6
+ vue-component-type-helpers: 2.0.7
transitivePeerDependencies:
- encoding
- supports-color
@@ -19348,8 +19348,8 @@ packages:
resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
dev: true
- /vue-component-type-helpers@2.0.6:
- resolution: {integrity: sha512-qdGXCtoBrwqk1BT6r2+1Wcvl583ZVkuSZ3or7Y1O2w5AvWtlvvxwjGhmz5DdPJS9xqRdDlgTJ/38ehWnEi0tFA==}
+ /vue-component-type-helpers@2.0.7:
+ resolution: {integrity: sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==}
dev: true
/vue-demi@0.14.7(vue@3.4.21):
From 2f8fb105a5b1d2f6e5cd70ff3246ead07e63144d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Fri, 5 Apr 2024 15:59:43 +0900
Subject: [PATCH 008/133] =?UTF-8?q?fix(deps):=20aiscript-vscode=E3=81=AE?=
=?UTF-8?q?=E3=82=A4=E3=83=B3=E3=82=B9=E3=83=88=E3=83=BC=E3=83=AB=E4=B8=AD?=
=?UTF-8?q?=E3=81=ABWARN=E3=81=8C=E5=87=BA=E3=82=8B=E3=81=AE=E3=82=92?=
=?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#13661)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/frontend/package.json | 2 +-
pnpm-lock.yaml | 39 +++++++++++++++++-----------------
2 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index db7f7b76f649..cbf4e595920f 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -29,7 +29,7 @@
"@twemoji/parser": "15.0.0",
"@vitejs/plugin-vue": "5.0.4",
"@vue/compiler-sfc": "3.4.21",
- "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.2",
+ "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.4",
"astring": "1.8.6",
"broadcast-channel": "7.0.0",
"buraha": "0.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 91c2a704e294..1dbb172b5dd7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -722,8 +722,8 @@ importers:
specifier: 3.4.21
version: 3.4.21
aiscript-vscode:
- specifier: github:aiscript-dev/aiscript-vscode#v0.1.2
- version: github.com/aiscript-dev/aiscript-vscode/793211d40243c8775f6b85f015c221c82cbffb07
+ specifier: github:aiscript-dev/aiscript-vscode#v0.1.4
+ version: github.com/aiscript-dev/aiscript-vscode/3f79d6f0550369267220aa67702287948d885424
astring:
specifier: 1.8.6
version: 1.8.6
@@ -5009,7 +5009,7 @@ packages:
resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
dependencies:
- semver: 7.5.4
+ semver: 7.6.0
dev: false
/@nsfw-filter/gif-frames@1.0.2:
@@ -6678,7 +6678,7 @@ packages:
ts-dedent: 2.2.0
type-fest: 2.19.0
vue: 3.4.21(typescript@5.3.3)
- vue-component-type-helpers: 2.0.7
+ vue-component-type-helpers: 2.0.10
transitivePeerDependencies:
- encoding
- supports-color
@@ -10595,7 +10595,7 @@ packages:
'@one-ini/wasm': 0.1.1
commander: 10.0.1
minimatch: 9.0.1
- semver: 7.5.4
+ semver: 7.6.0
dev: true
/ee-first@1.1.1:
@@ -13125,7 +13125,7 @@ packages:
'@babel/parser': 7.23.9
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
- semver: 7.5.4
+ semver: 7.6.0
transitivePeerDependencies:
- supports-color
dev: true
@@ -14121,7 +14121,7 @@ packages:
resolution: {integrity: sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==}
engines: {node: 14 || >=16.14}
dependencies:
- semver: 7.5.4
+ semver: 7.6.0
/lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
@@ -14192,7 +14192,7 @@ packages:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
dependencies:
- semver: 7.5.4
+ semver: 7.6.0
dev: true
/make-fetch-happen@13.0.0:
@@ -15303,7 +15303,7 @@ packages:
dependencies:
hosted-git-info: 4.1.0
is-core-module: 2.13.1
- semver: 7.5.4
+ semver: 7.6.0
validate-npm-package-license: 3.0.4
dev: true
@@ -17446,7 +17446,6 @@ packages:
hasBin: true
dependencies:
lru-cache: 6.0.0
- dev: true
/send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
@@ -19299,7 +19298,7 @@ packages:
engines: {vscode: ^1.82.0}
dependencies:
minimatch: 5.1.2
- semver: 7.5.4
+ semver: 7.6.0
vscode-languageserver-protocol: 3.17.5
dev: false
@@ -19348,8 +19347,8 @@ packages:
resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
dev: true
- /vue-component-type-helpers@2.0.7:
- resolution: {integrity: sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==}
+ /vue-component-type-helpers@2.0.10:
+ resolution: {integrity: sha512-FC5fKJjDks3Ue/KRSYBdsiCaZa0kUPQfs8yQpb8W9mlO6BenV8G1z58xobeRMzevnmEcDa09LLwuXDwb4f6NMQ==}
dev: true
/vue-demi@0.14.7(vue@3.4.21):
@@ -19871,10 +19870,10 @@ packages:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: true
- '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz':
- resolution: {tarball: https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz}
+ '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz':
+ resolution: {tarball: https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz}
name: '@aiscript-dev/aiscript-languageserver'
- version: 0.1.5
+ version: 0.1.6
hasBin: true
dependencies:
seedrandom: 3.0.5
@@ -19884,13 +19883,13 @@ packages:
vscode-languageserver-textdocument: 1.0.11
dev: false
- github.com/aiscript-dev/aiscript-vscode/793211d40243c8775f6b85f015c221c82cbffb07:
- resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/793211d40243c8775f6b85f015c221c82cbffb07}
+ github.com/aiscript-dev/aiscript-vscode/3f79d6f0550369267220aa67702287948d885424:
+ resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/3f79d6f0550369267220aa67702287948d885424}
name: aiscript-vscode
- version: 0.1.2
+ version: 0.1.4
engines: {vscode: ^1.83.0}
dependencies:
- '@aiscript-dev/aiscript-languageserver': '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz'
+ '@aiscript-dev/aiscript-languageserver': '@github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz'
vscode-languageclient: 9.0.1
dev: false
From 959cc8ff37de620bf0082f48f59963c00d045fe9 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 7 Apr 2024 21:14:13 +0900
Subject: [PATCH 009/133] refactor(general): use `Date.now()` instead of
creating a new `Date` instance (#13671)
---
packages/backend/src/core/AccountMoveService.ts | 4 ++--
packages/backend/src/core/PushNotificationService.ts | 2 +-
.../backend/src/server/api/endpoints/i/import-blocking.ts | 2 +-
.../backend/src/server/api/endpoints/i/import-following.ts | 2 +-
.../backend/src/server/api/endpoints/i/import-muting.ts | 2 +-
.../backend/src/server/api/endpoints/i/import-user-lists.ts | 2 +-
packages/frontend/src/components/global/MkTime.vue | 4 ++--
packages/frontend/src/widgets/WidgetUnixClock.vue | 6 +++---
packages/sw/src/sw.ts | 2 +-
9 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts
index 5bd885df406b..b6b591d24036 100644
--- a/packages/backend/src/core/AccountMoveService.ts
+++ b/packages/backend/src/core/AccountMoveService.ts
@@ -305,7 +305,7 @@ export class AccountMoveService {
let resultUser: MiLocalUser | MiRemoteUser | null = null;
if (this.userEntityService.isRemoteUser(dst)) {
- if ((new Date()).getTime() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
+ if (Date.now() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
await this.apPersonService.updatePerson(dst.uri);
}
dst = await this.apPersonService.fetchPerson(dst.uri) ?? dst;
@@ -321,7 +321,7 @@ export class AccountMoveService {
if (!src) continue; // oldAccountを探してもこのサーバーに存在しない場合はフォロー関係もないということなのでスルー
if (this.userEntityService.isRemoteUser(dst)) {
- if ((new Date()).getTime() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
+ if (Date.now() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
await this.apPersonService.updatePerson(srcUri);
}
diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts
index 3b706d985433..6a845b951de6 100644
--- a/packages/backend/src/core/PushNotificationService.ts
+++ b/packages/backend/src/core/PushNotificationService.ts
@@ -101,7 +101,7 @@ export class PushNotificationService implements OnApplicationShutdown {
type,
body: (type === 'notification' || type === 'unreadAntennaNote') ? truncateBody(type, body) : body,
userId,
- dateTime: (new Date()).getTime(),
+ dateTime: Date.now(),
}), {
proxy: this.config.proxy,
}).catch((err: any) => {
diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
index 8ddbe5663e83..260610853930 100644
--- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
@@ -75,7 +75,7 @@ export default class extends Endpoint
{ // eslint-
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
- (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+ (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts
index 390dd9cd715f..d5e824df2740 100644
--- a/packages/backend/src/server/api/endpoints/i/import-following.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-following.ts
@@ -75,7 +75,7 @@ export default class extends Endpoint { // eslint-
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
- (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+ (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts
index 51a9cdf5a58a..0f5800404eaf 100644
--- a/packages/backend/src/server/api/endpoints/i/import-muting.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts
@@ -75,7 +75,7 @@ export default class extends Endpoint { // eslint-
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
- (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+ (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
index a3b67301a790..bacdd5c88f28 100644
--- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
@@ -74,7 +74,7 @@ export default class extends Endpoint { // eslint-
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
- (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
+ (old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > Date.now(),
true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue
index 67532268d3be..23fe99bd9c32 100644
--- a/packages/frontend/src/components/global/MkTime.vue
+++ b/packages/frontend/src/components/global/MkTime.vue
@@ -47,7 +47,7 @@ const invalid = Number.isNaN(_time);
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
// eslint-disable-next-line vue/no-setup-props-destructure
-const now = ref((props.origin ?? new Date()).getTime());
+const now = ref(props.origin?.getTime() ?? Date.now());
const ago = computed(() => (now.value - _time) / 1000/*ms*/);
const relative = computed(() => {
@@ -77,7 +77,7 @@ let tickId: number;
let currentInterval: number;
function tick() {
- now.value = (new Date()).getTime();
+ now.value = Date.now();
const nextInterval = ago.value < 60 ? 10000 : ago.value < 3600 ? 60000 : 180000;
if (currentInterval !== nextInterval) {
diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue
index 2ac7d1c7810d..832cd575cc00 100644
--- a/packages/frontend/src/widgets/WidgetUnixClock.vue
+++ b/packages/frontend/src/widgets/WidgetUnixClock.vue
@@ -68,9 +68,9 @@ watch(showColon, (v) => {
});
const tick = () => {
- const now = new Date();
- ss.value = Math.floor(now.getTime() / 1000).toString();
- ms.value = Math.floor(now.getTime() % 1000 / 10).toString().padStart(2, '0');
+ const now = Date.now();
+ ss.value = Math.floor(now / 1000).toString();
+ ms.value = Math.floor(now % 1000 / 10).toString().padStart(2, '0');
if (ss.value !== prevSec) showColon.value = true;
prevSec = ss.value;
};
diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts
index 46fe9fc90f86..cc79d887133c 100644
--- a/packages/sw/src/sw.ts
+++ b/packages/sw/src/sw.ts
@@ -76,7 +76,7 @@ globalThis.addEventListener('push', ev => {
case 'notification':
case 'unreadAntennaNote':
// 1日以上経過している場合は無視
- if ((new Date()).getTime() - data.dateTime > 1000 * 60 * 60 * 24) break;
+ if (Date.now() - data.dateTime > 1000 * 60 * 60 * 24) break;
return createNotification(data);
case 'readAllNotifications':
From 960c4df48e31483209ac0421a009686685acd82d Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 7 Apr 2024 21:16:37 +0900
Subject: [PATCH 010/133] enhance(frontend): better condition for posting and
displaying Notes (#13670)
* enhance(frontend): better condition for posting and displaying Notes
* Update CHANGELOG.md
---
CHANGELOG.md | 4 ++++
packages/frontend/src/components/MkNote.vue | 1 +
packages/frontend/src/components/MkNoteDetailed.vue | 4 +++-
packages/frontend/src/components/MkPostForm.vue | 8 +++++++-
4 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6b9cf093925..41cbdea0239d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,8 @@
- Enhance: 映像・音声の再生メニューに「再生速度」「ループ再生」「ピクチャインピクチャ」を追加
- Enhance: 映像・音声の再生にキーボードショートカットが使えるように
- Enhance: ノートについているリアクションの「もっと!」から、リアクションの一覧を表示できるように
+- Enhance: リプライにて引用がある場合テキストが空でもノートできるように
+ - 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
- Fix: 周年の実績が閏年を考慮しない問題を修正
- Fix: ローカルURLのプレビューポップアップが左上に表示される
@@ -33,6 +35,8 @@
- Fix: コードブロックのシンタックスハイライトで使用される定義ファイルをCDNから取得するように #13177
- CDNから取得せずMisskey本体にバンドルする場合は`pacakges/frontend/vite.config.ts`を修正してください。
- Fix: タイムゾーンによっては、「今日誕生日のフォロー中ユーザー」ウィジェットが正しく動作しない問題を修正
+- Fix: CWのみの引用リノートが詳細ページで純粋なリノートとして誤って扱われてしまう問題を修正
+- Fix: ノート詳細ページにおいてCW付き引用リノートのCWボタンのラベルに「引用」が含まれていない問題を修正
### Server
- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index f5536e79bfcb..22b1691a8664 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -242,6 +242,7 @@ if (noteViewInterruptors.length > 0) {
const isRenote = (
note.value.renote != null &&
+ note.value.reply == null &&
note.value.text == null &&
note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index eec1aad53c49..ed1c0a9e9693 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
({{ i18n.ts.private }})
@@ -266,7 +266,9 @@ if (noteViewInterruptors.length > 0) {
const isRenote = (
note.value.renote != null &&
+ note.value.reply == null &&
note.value.text == null &&
+ note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&
note.value.poll == null
);
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index e03faeaf555f..014b866fbdbe 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -253,7 +253,13 @@ const maxTextLength = computed((): number => {
const canPost = computed((): boolean => {
return !props.mock && !posting.value && !posted.value &&
- (1 <= textLength.value || 1 <= files.value.length || !!poll.value || !!props.renote) &&
+ (
+ 1 <= textLength.value ||
+ 1 <= files.value.length ||
+ poll.value != null ||
+ props.renote != null ||
+ (props.reply != null && quoteId.value != null)
+ ) &&
(textLength.value <= maxTextLength.value) &&
(!poll.value || poll.value.choices.length >= 2);
});
From b322f55c8791493da9788313fd3df9d52f1327ef Mon Sep 17 00:00:00 2001
From: Srgr0 <66754887+Srgr0@users.noreply.github.com>
Date: Mon, 8 Apr 2024 22:41:26 +0900
Subject: [PATCH 011/133] dev: fix misskey-tga (#13312)
* Update deploy-test-environment.yml
* Update deploy-test-environment.yml
* use github.repository
---------
Co-authored-by: anatawa12
---
.github/workflows/deploy-test-environment.yml | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/deploy-test-environment.yml b/.github/workflows/deploy-test-environment.yml
index 77cdcfaf881e..66b15beb91ea 100644
--- a/.github/workflows/deploy-test-environment.yml
+++ b/.github/workflows/deploy-test-environment.yml
@@ -50,12 +50,9 @@ jobs:
- name: Get PR ref
id: get-ref
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- PR_NUMBER=$(jq --raw-output .issue.number $GITHUB_EVENT_PATH)
- PR_REF=$(gh pr view $PR_NUMBER --json headRefName -q '.headRefName')
- echo "pr-ref=$PR_REF" > $GITHUB_OUTPUT
+ PR_REF="refs/pull/${{ github.event.issue.number }}/head"
+ echo "pr-ref=$PR_REF" >> $GITHUB_OUTPUT
- name: Extract wait time
id: get-wait-time
From 7586ef7ba86ae9516e4a9460c0845750dda22e77 Mon Sep 17 00:00:00 2001
From: 1Step621 <86859447+1STEP621@users.noreply.github.com>
Date: Tue, 9 Apr 2024 14:20:00 +0900
Subject: [PATCH 012/133] =?UTF-8?q?fix(frontend):=20MkDialog=E3=81=AEinput?=
=?UTF-8?q?=E3=81=A7=E5=AD=97=E6=95=B0=E5=88=B6=E9=99=90=E3=81=AB=E9=81=95?=
=?UTF-8?q?=E5=8F=8D=E3=81=97=E3=81=A6=E3=81=84=E3=81=A6=E3=82=82Enter?=
=?UTF-8?q?=E3=82=AD=E3=83=BC=E3=81=8C=E6=8A=BC=E3=81=9B=E3=81=A6=E3=81=97?=
=?UTF-8?q?=E3=81=BE=E3=81=86=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1367?=
=?UTF-8?q?7)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* MkDialogのinputで字数制限に違反していてもEnterキーが押せてしまうのを修正
* update CHANGELOG.md
---
CHANGELOG.md | 1 +
packages/frontend/src/components/MkDialog.vue | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41cbdea0239d..ab4ecb3ffe92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@
- Fix: タイムゾーンによっては、「今日誕生日のフォロー中ユーザー」ウィジェットが正しく動作しない問題を修正
- Fix: CWのみの引用リノートが詳細ページで純粋なリノートとして誤って扱われてしまう問題を修正
- Fix: ノート詳細ページにおいてCW付き引用リノートのCWボタンのラベルに「引用」が含まれていない問題を修正
+- Fix: ダイアログの入力で字数制限に違反していてもEnterキーが押せてしまう問題を修正
### Server
- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue
index 4577d37c0837..c52404a3190b 100644
--- a/packages/frontend/src/components/MkDialog.vue
+++ b/packages/frontend/src/components/MkDialog.vue
@@ -161,7 +161,7 @@ function onKeydown(evt: KeyboardEvent) {
}
function onInputKeydown(evt: KeyboardEvent) {
- if (evt.key === 'Enter') {
+ if (evt.key === 'Enter' && okButtonDisabledReason.value === null) {
evt.preventDefault();
evt.stopPropagation();
ok();
From eb1ef1484afbdb09407a603ff69414e7f88bb9ff Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 9 Apr 2024 20:52:29 +0900
Subject: [PATCH 013/133] enhance(frontend): add link of 2fa guide
---
locales/index.d.ts | 4 ++++
locales/ja-JP.yml | 1 +
packages/frontend/src/pages/settings/2fa.qrdialog.vue | 3 +++
packages/frontend/src/pages/settings/2fa.vue | 6 +++++-
4 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 01bec41d9e9f..54f028572683 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -7645,6 +7645,10 @@ export interface Locale extends ILocale {
* バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。
*/
"backupCodesExhaustedWarning": string;
+ /**
+ * 詳細なガイドはこちら
+ */
+ "moreDetailedGuideHere": string;
};
"_permissions": {
/**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4ba9ea0221b1..ac88420b9d72 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2009,6 +2009,7 @@ _2fa:
backupCodesDescription: "認証アプリが使用できなくなった場合、以下のバックアップコードを使ってアカウントにアクセスできます。これらのコードは必ず安全な場所に保管してください。各コードは一回だけ使用できます。"
backupCodeUsedWarning: "バックアップコードが使用されました。認証アプリが使えなくなっている場合、なるべく早く認証アプリを再設定してください。"
backupCodesExhaustedWarning: "バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。"
+ moreDetailedGuideHere: "詳細なガイドはこちら"
_permissions:
"read:account": "アカウントの情報を見る"
diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
index 73253b1ef43f..2244047b3165 100644
--- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue
+++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue
@@ -25,6 +25,8 @@ SPDX-License-Identifier: AGPL-3.0-only
+
{{ i18n.ts._2fa.moreDetailedGuideHere }}
+
Authy
@@ -113,6 +115,7 @@ import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import MkFolder from '@/components/MkFolder.vue';
import MkInfo from '@/components/MkInfo.vue';
+import MkLink from '@/components/MkLink.vue';
import { confetti } from '@/scripts/confetti.js';
import { signinRequired } from '@/account.js';
diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue
index 975f23cdd1de..b7d648c1a4d3 100644
--- a/packages/frontend/src/pages/settings/2fa.vue
+++ b/packages/frontend/src/pages/settings/2fa.vue
@@ -30,7 +30,10 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.unregister }}
- {{ i18n.ts._2fa.registerTOTP }}
+
+ {{ i18n.ts._2fa.registerTOTP }}
+ {{ i18n.ts.learnMore }}
+
@@ -79,6 +82,7 @@ import MkInfo from '@/components/MkInfo.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import FormSection from '@/components/form/section.vue';
import MkFolder from '@/components/MkFolder.vue';
+import MkLink from '@/components/MkLink.vue';
import * as os from '@/os.js';
import { signinRequired, updateAccount } from '@/account.js';
import { i18n } from '@/i18n.js';
From f5100cc81f6ffdcfe2b9bf6041f97098a4e82d02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 13 Apr 2024 12:51:37 +0900
Subject: [PATCH 014/133] =?UTF-8?q?feat(frontend):=20=E3=82=A2=E3=83=83?=
=?UTF-8?q?=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89=E3=81=99=E3=82=8B=E3=83=95?=
=?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E5=90=8D=E5=89=8D=E3=82=92?=
=?UTF-8?q?=E3=83=A9=E3=83=B3=E3=83=80=E3=83=A0=E6=96=87=E5=AD=97=E5=88=97?=
=?UTF-8?q?=E3=81=AB=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
=?UTF-8?q?=20(#13688)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat(frontend): アップロードするファイルの名前をランダム文字列にできるように
* Update Changelog
* refactor
* 設定項目を移動
* fix
* 「オリジナルのファイル名を保持」に変更
* 拡張子を付加するように
---
CHANGELOG.md | 1 +
locales/index.d.ts | 8 ++++++++
locales/ja-JP.yml | 2 ++
packages/frontend/src/pages/settings/drive.vue | 5 +++++
packages/frontend/src/scripts/upload.ts | 10 +++++++---
packages/frontend/src/store.ts | 4 ++++
6 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab4ecb3ffe92..1332da69f917 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
### Client
+- Feat: アップロードするファイルの名前をランダム文字列にできるように
- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
- Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
- Enhance: リアクション・いいねの総数を表示するように
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 54f028572683..d6875c086807 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4936,6 +4936,14 @@ export interface Locale extends ILocale {
* 動画・音声の再生にブラウザのUIを使用する
*/
"useNativeUIForVideoAudioPlayer": string;
+ /**
+ * オリジナルのファイル名を保持
+ */
+ "keepOriginalFilename": string;
+ /**
+ * この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。
+ */
+ "keepOriginalFilenameDescription": string;
"_bubbleGame": {
/**
* 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index ac88420b9d72..0b581a01e328 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1230,6 +1230,8 @@ useTotp: "ワンタイムパスワードを使う"
useBackupCode: "バックアップコードを使う"
launchApp: "アプリを起動"
useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
+keepOriginalFilename: "オリジナルのファイル名を保持"
+keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
_bubbleGame:
howToPlay: "遊び方"
diff --git a/packages/frontend/src/pages/settings/drive.vue b/packages/frontend/src/pages/settings/drive.vue
index 1919f808640f..81a8d474d29b 100644
--- a/packages/frontend/src/pages/settings/drive.vue
+++ b/packages/frontend/src/pages/settings/drive.vue
@@ -44,6 +44,10 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.keepOriginalUploading }}
{{ i18n.ts.keepOriginalUploadingDescription }}
+
+ {{ i18n.ts.keepOriginalFilename }}
+ {{ i18n.ts.keepOriginalFilenameDescription }}
+
{{ i18n.ts.alwaysMarkSensitive }}
@@ -96,6 +100,7 @@ const meterStyle = computed(() => {
});
const keepOriginalUploading = computed(defaultStore.makeGetterSetter('keepOriginalUploading'));
+const keepOriginalFilename = computed(defaultStore.makeGetterSetter('keepOriginalFilename'));
misskeyApi('drive').then(info => {
capacity.value = info.capacity;
diff --git a/packages/frontend/src/scripts/upload.ts b/packages/frontend/src/scripts/upload.ts
index 6c46b2bc1ba2..3e947183c9ea 100644
--- a/packages/frontend/src/scripts/upload.ts
+++ b/packages/frontend/src/scripts/upload.ts
@@ -5,6 +5,7 @@
import { reactive, ref } from 'vue';
import * as Misskey from 'misskey-js';
+import { v4 as uuid } from 'uuid';
import { readAndCompressImage } from '@misskey-dev/browser-image-resizer';
import { getCompressionConfig } from './upload/compress-config.js';
import { defaultStore } from '@/store.js';
@@ -39,13 +40,16 @@ export function uploadFile(
if (folder && typeof folder === 'object') folder = folder.id;
return new Promise((resolve, reject) => {
- const id = Math.random().toString();
+ const id = uuid();
const reader = new FileReader();
reader.onload = async (): Promise => {
+ const filename = name ?? file.name ?? 'untitled';
+ const extension = filename.split('.').length > 1 ? '.' + filename.split('.').pop() : '';
+
const ctx = reactive({
- id: id,
- name: name ?? file.name ?? 'untitled',
+ id,
+ name: defaultStore.state.keepOriginalFilename ? filename : id + extension,
progressMax: undefined,
progressValue: undefined,
img: window.URL.createObjectURL(file),
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index faefbd8ce430..9b5011739a06 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -446,6 +446,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: false,
},
+ keepOriginalFilename: {
+ where: 'device',
+ default: true,
+ },
sound_masterVolume: {
where: 'device',
From 5c7c44c9ebd12e9ae0dd6d7fab8f6dd78ba54eb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 13 Apr 2024 20:38:25 +0900
Subject: [PATCH 015/133] =?UTF-8?q?fix(backend):=20=E7=99=BB=E9=8C=B2?=
=?UTF-8?q?=E3=81=AB=E3=83=A1=E3=83=BC=E3=83=AB=E8=AA=8D=E8=A8=BC=E3=81=8C?=
=?UTF-8?q?=E5=BF=85=E9=A0=88=E3=81=AB=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=84?=
=?UTF-8?q?=E3=82=8B=E5=A0=B4=E5=90=88=E3=80=81=E7=99=BB=E9=8C=B2=E3=81=95?=
=?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=84=E3=82=8B=E3=83=A1=E3=83=BC=E3=83=AB?=
=?UTF-8?q?=E3=82=A2=E3=83=89=E3=83=AC=E3=82=B9=E3=82=92=E5=89=8A=E9=99=A4?=
=?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?=
=?UTF-8?q?=20(#13703)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix(backend): 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように (MisskeyIO#606)
(cherry picked from commit 6b7df2bd10dc28b84f525a621b66fc49bf59cac6)
* Update Changelog
---------
Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
CHANGELOG.md | 2 ++
.../backend/src/server/api/endpoints/i/update-email.ts | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1332da69f917..d184a0b3987a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,6 +48,8 @@
- Fix: エンドポイント`notes/translate`のエラーを改善
- Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
- Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正
+- Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように
+ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
## 2024.3.1
diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts
index 386827869020..eea657ebbd07 100644
--- a/packages/backend/src/server/api/endpoints/i/update-email.ts
+++ b/packages/backend/src/server/api/endpoints/i/update-email.ts
@@ -15,6 +15,7 @@ import { DI } from '@/di-symbols.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
import { UserAuthService } from '@/core/UserAuthService.js';
+import { MetaService } from '@/core/MetaService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -39,6 +40,12 @@ export const meta = {
code: 'UNAVAILABLE',
id: 'a2defefb-f220-8849-0af6-17f816099323',
},
+
+ emailRequired: {
+ message: 'Email address is required.',
+ code: 'EMAIL_REQUIRED',
+ id: '324c7a88-59f2-492f-903f-89134f93e47e',
+ },
},
res: {
@@ -66,6 +73,7 @@ export default class extends Endpoint { // eslint-
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
+ private metaService: MetaService,
private userEntityService: UserEntityService,
private emailService: EmailService,
private userAuthService: UserAuthService,
@@ -97,6 +105,8 @@ export default class extends Endpoint { // eslint-
if (!res.available) {
throw new ApiError(meta.errors.unavailable);
}
+ } else if ((await this.metaService.fetch()).emailRequiredForSignup) {
+ throw new ApiError(meta.errors.emailRequired);
}
await this.userProfilesRepository.update(me.id, {
From 48a7679b8a8b3df80d7f90ac6f4a852f47a8df22 Mon Sep 17 00:00:00 2001
From: anatawa12
Date: Sun, 14 Apr 2024 08:08:26 +0900
Subject: [PATCH 016/133] test: do not use indexedDB in cypress environment due
to chrome bug (#13709)
---
cypress/support/commands.ts | 4 ++++
packages/frontend/src/scripts/idb-proxy.ts | 10 ++++++++++
2 files changed, 14 insertions(+)
diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
index c2d92e1663e8..281f2e6ccdd8 100644
--- a/cypress/support/commands.ts
+++ b/cypress/support/commands.ts
@@ -30,9 +30,13 @@ Cypress.Commands.add('visitHome', () => {
})
Cypress.Commands.add('resetState', () => {
+ // iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。
+ // see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
+ /*
cy.window().then(win => {
win.indexedDB.deleteDatabase('keyval-store');
});
+ */
cy.request('POST', '/api/reset-db', {}).as('reset');
cy.get('@reset').its('status').should('equal', 204);
cy.reload(true);
diff --git a/packages/frontend/src/scripts/idb-proxy.ts b/packages/frontend/src/scripts/idb-proxy.ts
index 1ca0990ba9e2..6b511f2a5fc7 100644
--- a/packages/frontend/src/scripts/idb-proxy.ts
+++ b/packages/frontend/src/scripts/idb-proxy.ts
@@ -15,6 +15,16 @@ const fallbackName = (key: string) => `idbfallback::${key}`;
let idbAvailable = typeof window !== 'undefined' ? !!(window.indexedDB && window.indexedDB.open) : true;
+// iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。
+// バグが治って再度有効化するのであれば、cypressのコマンド内のコメントアウトを外すこと
+// see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
+if (window.Cypress) {
+ idbAvailable = false;
+ console.log('Cypress detected. It will use localStorage.');
+}
+
if (idbAvailable) {
await iset('idb-test', 'test')
.catch(err => {
From 7cf0c18f83f82416c9b1bb5bca5b669e77240527 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 14 Apr 2024 10:22:03 +0900
Subject: [PATCH 017/133] =?UTF-8?q?fix(backend):=20FileServerService?=
=?UTF-8?q?=E3=81=A7=E3=83=AC=E3=83=B3=E3=82=B8=E3=83=AA=E3=82=AF=E3=82=A8?=
=?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AB=E9=81=A9?=
=?UTF-8?q?=E5=88=87=E3=81=AA=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3=E3=82=B9?=
=?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=81=8C=E8=BF=94=E3=82=89=E3=81=AA?=
=?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1370?=
=?UTF-8?q?1)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* return 206 for every ranged response - fixes #494
(cherry picked from commit 92eec2178fd103e9ea2bcd646aacab1fb496a33b)
* detect size of remote files - fixes #494
without this, remote files are assumed to have size 0 (even if we just
downloaded them!) and the range-related code won't run
(cherry picked from commit 960f4fcff78a1f019c9a9377853fcd90dbfb7575)
---------
Co-authored-by: dakkar
---
packages/backend/src/server/FileServerService.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index f51d7aebca68..ce7702143ed9 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -194,6 +194,7 @@ export class FileServerService {
reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`);
reply.header('Accept-Ranges', 'bytes');
reply.header('Content-Length', chunksize);
+ reply.code(206);
} else {
image = {
data: fs.createReadStream(file.path),
@@ -263,7 +264,6 @@ export class FileServerService {
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1;
- console.log(end);
if (end > file.file.size) {
end = file.file.size - 1;
}
@@ -433,6 +433,7 @@ export class FileServerService {
reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`);
reply.header('Accept-Ranges', 'bytes');
reply.header('Content-Length', chunksize);
+ reply.code(206);
} else {
image = {
data: fs.createReadStream(file.path),
@@ -529,6 +530,9 @@ export class FileServerService {
if (!file.storedInternal) {
if (!(file.isLink && file.uri)) return '204';
const result = await this.downloadAndDetectTypeFromUrl(file.uri);
+ if (!file.size) {
+ file.size = (await fs.promises.stat(result.path)).size;
+ }
return {
...result,
url: file.uri,
From 8c5d9a6295ab506b935bbd5856894239997a8158 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 14 Apr 2024 10:23:48 +0900
Subject: [PATCH 018/133] fix(backend): incorrect logic for determining whether
Quote or not (#13700)
* fix(backend): incorrect logic for determining whether Quote or not
* Update CHANGELOG.md
---------
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
CHANGELOG.md | 1 +
.../src/core/FanoutTimelineEndpointService.ts | 6 +-
.../backend/src/core/NoteCreateService.ts | 23 ++-
.../backend/src/core/NoteDeleteService.ts | 4 +-
packages/backend/src/misc/is-pure-renote.ts | 15 --
packages/backend/src/misc/is-quote.ts | 12 --
packages/backend/src/misc/is-renote.ts | 36 +++++
.../src/server/ActivityPubServerService.ts | 4 +-
.../src/server/api/endpoints/notes/create.ts | 6 +-
.../backend/test/unit/NoteCreateService.ts | 144 ++++++++++++++++++
packages/backend/test/unit/misc/is-renote.ts | 88 +++++++++++
11 files changed, 296 insertions(+), 43 deletions(-)
delete mode 100644 packages/backend/src/misc/is-pure-renote.ts
delete mode 100644 packages/backend/src/misc/is-quote.ts
create mode 100644 packages/backend/src/misc/is-renote.ts
create mode 100644 packages/backend/test/unit/NoteCreateService.ts
create mode 100644 packages/backend/test/unit/misc/is-renote.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d184a0b3987a..47e8e0cf19aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,6 +48,7 @@
- Fix: エンドポイント`notes/translate`のエラーを改善
- Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
- Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正
+- Fix: リプライのみの引用リノートと、CWのみの引用リノートが純粋なリノートとして誤って扱われてしまう問題を修正
- Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606)
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts
index 9c239b4dfc40..006433df7a22 100644
--- a/packages/backend/src/core/FanoutTimelineEndpointService.ts
+++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts
@@ -13,7 +13,7 @@ import type { NotesRepository } from '@/models/_.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { FanoutTimelineName, FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { isUserRelated } from '@/misc/is-user-related.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
import { CacheService } from '@/core/CacheService.js';
import { isReply } from '@/misc/is-reply.js';
import { isInstanceMuted } from '@/misc/is-instance-muted.js';
@@ -95,7 +95,7 @@ export class FanoutTimelineEndpointService {
if (ps.excludePureRenotes) {
const parentFilter = filter;
- filter = (note) => !isPureRenote(note) && parentFilter(note);
+ filter = (note) => (!isRenote(note) || isQuote(note)) && parentFilter(note);
}
if (ps.me) {
@@ -116,7 +116,7 @@ export class FanoutTimelineEndpointService {
filter = (note) => {
if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromBlock)) return false;
if (isUserRelated(note, userIdsWhoMeMuting, ps.ignoreAuthorFromMute)) return false;
- if (isPureRenote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false;
+ if (isRenote(note) && !isQuote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false;
if (isInstanceMuted(note, userMutedInstances)) return false;
return parentFilter(note);
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 81ae2908d3dc..32104fea9072 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -306,7 +306,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
// Check blocking
- if (data.renote && !this.isQuote(data)) {
+ if (this.isRenote(data) && !this.isQuote(data)) {
if (data.renote.userHost === null) {
if (data.renote.userId !== user.id) {
const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id);
@@ -641,7 +641,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
// If it is renote
- if (data.renote) {
+ if (this.isRenote(data)) {
const type = this.isQuote(data) ? 'quote' : 'renote';
// Notify
@@ -725,9 +725,20 @@ export class NoteCreateService implements OnApplicationShutdown {
}
@bindThis
- private isQuote(note: Option): note is Option & { renote: MiNote } {
- // sync with misc/is-quote.ts
- return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll);
+ private isRenote(note: Option): note is Option & { renote: MiNote } {
+ return note.renote != null;
+ }
+
+ @bindThis
+ private isQuote(note: Option & { renote: MiNote }): note is Option & { renote: MiNote } & (
+ { text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] }
+ ) {
+ // NOTE: SYNC WITH misc/is-quote.ts
+ return note.text != null ||
+ note.reply != null ||
+ note.cw != null ||
+ note.poll != null ||
+ (note.files != null && note.files.length > 0);
}
@bindThis
@@ -795,7 +806,7 @@ export class NoteCreateService implements OnApplicationShutdown {
private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
if (data.localOnly) return null;
- const content = data.renote && !this.isQuote(data)
+ const content = this.isRenote(data) && !this.isQuote(data)
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
: this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts
index fdf843c3e82c..801ed02e00b3 100644
--- a/packages/backend/src/core/NoteDeleteService.ts
+++ b/packages/backend/src/core/NoteDeleteService.ts
@@ -24,7 +24,7 @@ import { bindThis } from '@/decorators.js';
import { MetaService } from '@/core/MetaService.js';
import { SearchService } from '@/core/SearchService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
@Injectable()
export class NoteDeleteService {
@@ -79,7 +79,7 @@ export class NoteDeleteService {
let renote: MiNote | null = null;
// if deleted note is renote
- if (isPureRenote(note)) {
+ if (isRenote(note) && !isQuote(note)) {
renote = await this.notesRepository.findOneBy({
id: note.renoteId,
});
diff --git a/packages/backend/src/misc/is-pure-renote.ts b/packages/backend/src/misc/is-pure-renote.ts
deleted file mode 100644
index f9c2243a06ff..000000000000
--- a/packages/backend/src/misc/is-pure-renote.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import type { MiNote } from '@/models/Note.js';
-
-export function isPureRenote(note: MiNote): note is MiNote & { renoteId: NonNullable } {
- if (!note.renoteId) return false;
-
- if (note.text) return false; // it's quoted with text
- if (note.fileIds.length !== 0) return false; // it's quoted with files
- if (note.hasPoll) return false; // it's quoted with poll
- return true;
-}
diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts
deleted file mode 100644
index 75b29f63f492..000000000000
--- a/packages/backend/src/misc/is-quote.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import type { MiNote } from '@/models/Note.js';
-
-// eslint-disable-next-line import/no-default-export
-export default function(note: MiNote): boolean {
- // sync with NoteCreateService.isQuote
- return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0));
-}
diff --git a/packages/backend/src/misc/is-renote.ts b/packages/backend/src/misc/is-renote.ts
new file mode 100644
index 000000000000..5d48aba36092
--- /dev/null
+++ b/packages/backend/src/misc/is-renote.ts
@@ -0,0 +1,36 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import type { MiNote } from '@/models/Note.js';
+
+type Renote =
+ MiNote & {
+ renoteId: NonNullable
+ };
+
+type Quote =
+ Renote & ({
+ text: NonNullable
+ } | {
+ cw: NonNullable
+ } | {
+ replyId: NonNullable
+ reply: NonNullable
+ } | {
+ hasPoll: true
+ });
+
+export function isRenote(note: MiNote): note is Renote {
+ return note.renoteId != null;
+}
+
+export function isQuote(note: Renote): note is Quote {
+ // NOTE: SYNC WITH NoteCreateService.isQuote
+ return note.text != null ||
+ note.cw != null ||
+ note.replyId != null ||
+ note.hasPoll ||
+ note.fileIds.length > 0;
+}
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index 60366dd5c231..3255d64621db 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -28,7 +28,7 @@ import { UtilityService } from '@/core/UtilityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import { IActivity } from '@/core/activitypub/type.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
import type { FindOptionsWhere } from 'typeorm';
@@ -91,7 +91,7 @@ export class ActivityPubServerService {
*/
@bindThis
private async packActivity(note: MiNote): Promise {
- if (isPureRenote(note)) {
+ if (isRenote(note) && !isQuote(note)) {
const renote = await this.notesRepository.findOneByOrFail({ id: note.renoteId });
return this.apRendererService.renderAnnounce(renote.uri ? renote.uri : `${this.config.url}/notes/${renote.id}`, note);
}
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index bfb92144393d..beb77ca7ab02 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -16,7 +16,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { NoteCreateService } from '@/core/NoteCreateService.js';
import { DI } from '@/di-symbols.js';
-import { isPureRenote } from '@/misc/is-pure-renote.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
@@ -275,7 +275,7 @@ export default class extends Endpoint { // eslint-
if (renote == null) {
throw new ApiError(meta.errors.noSuchRenoteTarget);
- } else if (isPureRenote(renote)) {
+ } else if (isRenote(renote) && !isQuote(renote)) {
throw new ApiError(meta.errors.cannotReRenote);
}
@@ -321,7 +321,7 @@ export default class extends Endpoint { // eslint-
if (reply == null) {
throw new ApiError(meta.errors.noSuchReplyTarget);
- } else if (isPureRenote(reply)) {
+ } else if (isRenote(reply) && !isQuote(reply)) {
throw new ApiError(meta.errors.cannotReplyToPureRenote);
} else if (!await this.noteEntityService.isVisibleForMe(reply, me.id)) {
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
diff --git a/packages/backend/test/unit/NoteCreateService.ts b/packages/backend/test/unit/NoteCreateService.ts
new file mode 100644
index 000000000000..f2d4c8ffbb77
--- /dev/null
+++ b/packages/backend/test/unit/NoteCreateService.ts
@@ -0,0 +1,144 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Test } from '@nestjs/testing';
+
+import { CoreModule } from '@/core/CoreModule.js';
+import { NoteCreateService } from '@/core/NoteCreateService.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { MiNote } from '@/models/Note.js';
+import { IPoll } from '@/models/Poll.js';
+import { MiDriveFile } from '@/models/DriveFile.js';
+
+describe('NoteCreateService', () => {
+ let noteCreateService: NoteCreateService;
+
+ beforeAll(async () => {
+ const app = await Test.createTestingModule({
+ imports: [GlobalModule, CoreModule],
+ }).compile();
+ noteCreateService = app.get(NoteCreateService);
+ });
+
+ describe('is-renote', () => {
+ const base: MiNote = {
+ id: 'some-note-id',
+ replyId: null,
+ reply: null,
+ renoteId: null,
+ renote: null,
+ threadId: null,
+ text: null,
+ name: null,
+ cw: null,
+ userId: 'some-user-id',
+ user: null,
+ localOnly: false,
+ reactionAcceptance: null,
+ renoteCount: 0,
+ repliesCount: 0,
+ clippedCount: 0,
+ reactions: {},
+ visibility: 'public',
+ uri: null,
+ url: null,
+ fileIds: [],
+ attachedFileTypes: [],
+ visibleUserIds: [],
+ mentions: [],
+ mentionedRemoteUsers: '',
+ reactionAndUserPairCache: [],
+ emojis: [],
+ tags: [],
+ hasPoll: false,
+ channelId: null,
+ channel: null,
+ userHost: null,
+ replyUserId: null,
+ replyUserHost: null,
+ renoteUserId: null,
+ renoteUserHost: null,
+ };
+
+ const poll: IPoll = {
+ choices: ['kinoko', 'takenoko'],
+ multiple: false,
+ expiresAt: null,
+ };
+
+ const file: MiDriveFile = {
+ id: 'some-file-id',
+ userId: null,
+ user: null,
+ userHost: null,
+ md5: '',
+ name: '',
+ type: '',
+ size: 0,
+ comment: null,
+ blurhash: null,
+ properties: {},
+ storedInternal: false,
+ url: '',
+ thumbnailUrl: null,
+ webpublicUrl: null,
+ webpublicType: null,
+ accessKey: null,
+ thumbnailAccessKey: null,
+ webpublicAccessKey: null,
+ uri: null,
+ src: null,
+ folderId: null,
+ folder: null,
+ isSensitive: false,
+ maybeSensitive: false,
+ maybePorn: false,
+ isLink: false,
+ requestHeaders: null,
+ requestIp: null,
+ };
+
+ test('note without renote should not be Renote', () => {
+ const note = { renote: null };
+ expect(noteCreateService['isRenote'](note)).toBe(false);
+ });
+
+ test('note with renote should be Renote and not be Quote', () => {
+ const note = { renote: base };
+ expect(noteCreateService['isRenote'](note)).toBe(true);
+ expect(noteCreateService['isQuote'](note)).toBe(false);
+ });
+
+ test('note with renote and text should be Quote', () => {
+ const note = { renote: base, text: 'some-text' };
+ expect(noteCreateService['isRenote'](note)).toBe(true);
+ expect(noteCreateService['isQuote'](note)).toBe(true);
+ });
+
+ test('note with renote and cw should be Quote', () => {
+ const note = { renote: base, cw: 'some-cw' };
+ expect(noteCreateService['isRenote'](note)).toBe(true);
+ expect(noteCreateService['isQuote'](note)).toBe(true);
+ });
+
+ test('note with renote and reply should be Quote', () => {
+ const note = { renote: base, reply: { ...base, id: 'another-note-id' } };
+ expect(noteCreateService['isRenote'](note)).toBe(true);
+ expect(noteCreateService['isQuote'](note)).toBe(true);
+ });
+
+ test('note with renote and poll should be Quote', () => {
+ const note = { renote: base, poll };
+ expect(noteCreateService['isRenote'](note)).toBe(true);
+ expect(noteCreateService['isQuote'](note)).toBe(true);
+ });
+
+ test('note with renote and non-empty files should be Quote', () => {
+ const note = { renote: base, files: [file] };
+ expect(noteCreateService['isRenote'](note)).toBe(true);
+ expect(noteCreateService['isQuote'](note)).toBe(true);
+ });
+ });
+});
diff --git a/packages/backend/test/unit/misc/is-renote.ts b/packages/backend/test/unit/misc/is-renote.ts
new file mode 100644
index 000000000000..0b713e8bf6b4
--- /dev/null
+++ b/packages/backend/test/unit/misc/is-renote.ts
@@ -0,0 +1,88 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { isQuote, isRenote } from '@/misc/is-renote.js';
+import { MiNote } from '@/models/Note.js';
+
+const base: MiNote = {
+ id: 'some-note-id',
+ replyId: null,
+ reply: null,
+ renoteId: null,
+ renote: null,
+ threadId: null,
+ text: null,
+ name: null,
+ cw: null,
+ userId: 'some-user-id',
+ user: null,
+ localOnly: false,
+ reactionAcceptance: null,
+ renoteCount: 0,
+ repliesCount: 0,
+ clippedCount: 0,
+ reactions: {},
+ visibility: 'public',
+ uri: null,
+ url: null,
+ fileIds: [],
+ attachedFileTypes: [],
+ visibleUserIds: [],
+ mentions: [],
+ mentionedRemoteUsers: '',
+ reactionAndUserPairCache: [],
+ emojis: [],
+ tags: [],
+ hasPoll: false,
+ channelId: null,
+ channel: null,
+ userHost: null,
+ replyUserId: null,
+ replyUserHost: null,
+ renoteUserId: null,
+ renoteUserHost: null,
+};
+
+describe('misc:is-renote', () => {
+ test('note without renoteId should not be Renote', () => {
+ expect(isRenote(base)).toBe(false);
+ });
+
+ test('note with renoteId should be Renote and not be Quote', () => {
+ const note: MiNote = { ...base, renoteId: 'some-renote-id' };
+ expect(isRenote(note)).toBe(true);
+ expect(isQuote(note as any)).toBe(false);
+ });
+
+ test('note with renoteId and text should be Quote', () => {
+ const note: MiNote = { ...base, renoteId: 'some-renote-id', text: 'some-text' };
+ expect(isRenote(note)).toBe(true);
+ expect(isQuote(note as any)).toBe(true);
+ });
+
+ test('note with renoteId and cw should be Quote', () => {
+ const note: MiNote = { ...base, renoteId: 'some-renote-id', cw: 'some-cw' };
+ expect(isRenote(note)).toBe(true);
+ expect(isQuote(note as any)).toBe(true);
+ });
+
+ test('note with renoteId and replyId should be Quote', () => {
+ const note: MiNote = { ...base, renoteId: 'some-renote-id', replyId: 'some-reply-id' };
+ expect(isRenote(note)).toBe(true);
+ expect(isQuote(note as any)).toBe(true);
+ });
+
+ test('note with renoteId and poll should be Quote', () => {
+ const note: MiNote = { ...base, renoteId: 'some-renote-id', hasPoll: true };
+ expect(isRenote(note)).toBe(true);
+ expect(isQuote(note as any)).toBe(true);
+ });
+
+ test('note with renoteId and non-empty fileIds should be Quote', () => {
+ const note: MiNote = { ...base, renoteId: 'some-renote-id', fileIds: ['some-file-id'] };
+ expect(isRenote(note)).toBe(true);
+ expect(isQuote(note as any)).toBe(true);
+ });
+});
From bba3097765317cbf95d09627961b5b5dce16a972 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 14 Apr 2024 21:30:24 +0900
Subject: [PATCH 019/133] =?UTF-8?q?enhance:=20=E3=82=AF=E3=83=AA=E3=83=83?=
=?UTF-8?q?=E3=83=97=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88=E6=95=B0=E3=82=92?=
=?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
=?UTF-8?q?=20(#13686)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* enhance: クリップのノート数を表示できるように
* Update Changelog
---
CHANGELOG.md | 1 +
locales/index.d.ts | 4 ++
locales/ja-JP.yml | 1 +
.../src/core/entities/ClipEntityService.ts | 6 ++-
.../backend/src/models/json-schema/clip.ts | 4 ++
.../frontend/src/components/MkClipPreview.vue | 52 +++++++++++++------
packages/frontend/src/pages/clip.vue | 13 +++--
.../frontend/src/pages/my-clips/index.vue | 10 ++--
packages/frontend/src/pages/note.vue | 4 +-
.../frontend/src/scripts/get-note-menu.ts | 36 +++++++++++--
packages/misskey-js/src/autogen/types.ts | 1 +
11 files changed, 99 insertions(+), 33 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47e8e0cf19aa..a238d99a062a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
- Enhance: URLプレビューの有効化・無効化を設定できるように #13569
- Enhance: アンテナでBotによるノートを除外できるように
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
+- Enhance: クリップのノート数を表示するように
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
### Client
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d6875c086807..cbea39f1cd18 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4944,6 +4944,10 @@ export interface Locale extends ILocale {
* この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。
*/
"keepOriginalFilenameDescription": string;
+ /**
+ * 説明文はありません
+ */
+ "noDescription": string;
"_bubbleGame": {
/**
* 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 0b581a01e328..4ab2f5adb02d 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1232,6 +1232,7 @@ launchApp: "アプリを起動"
useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
keepOriginalFilename: "オリジナルのファイル名を保持"
keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
+noDescription: "説明文はありません"
_bubbleGame:
howToPlay: "遊び方"
diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts
index 26fcd6714d16..ce49c3458c54 100644
--- a/packages/backend/src/core/entities/ClipEntityService.ts
+++ b/packages/backend/src/core/entities/ClipEntityService.ts
@@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import type { ClipFavoritesRepository, ClipsRepository, MiUser } from '@/models/_.js';
+import type { ClipNotesRepository, ClipFavoritesRepository, ClipsRepository, MiUser } from '@/models/_.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/Blocking.js';
@@ -20,6 +20,9 @@ export class ClipEntityService {
@Inject(DI.clipsRepository)
private clipsRepository: ClipsRepository,
+ @Inject(DI.clipNotesRepository)
+ private clipNotesRepository: ClipNotesRepository,
+
@Inject(DI.clipFavoritesRepository)
private clipFavoritesRepository: ClipFavoritesRepository,
@@ -47,6 +50,7 @@ export class ClipEntityService {
isPublic: clip.isPublic,
favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }),
isFavorited: meId ? await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: meId } }) : undefined,
+ notesCount: meId ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined,
});
}
diff --git a/packages/backend/src/models/json-schema/clip.ts b/packages/backend/src/models/json-schema/clip.ts
index ca4886c97837..c4e7055cd88a 100644
--- a/packages/backend/src/models/json-schema/clip.ts
+++ b/packages/backend/src/models/json-schema/clip.ts
@@ -52,5 +52,9 @@ export const packedClipSchema = {
type: 'boolean',
optional: true, nullable: false,
},
+ notesCount: {
+ type: 'integer',
+ optional: true, nullable: false,
+ },
},
} as const;
diff --git a/packages/frontend/src/components/MkClipPreview.vue b/packages/frontend/src/components/MkClipPreview.vue
index c51ad4356da0..6299a28e9f68 100644
--- a/packages/frontend/src/components/MkClipPreview.vue
+++ b/packages/frontend/src/components/MkClipPreview.vue
@@ -4,37 +4,59 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
-
-
{{ clip.name }}
-
{{ clip.description }}
-
{{ i18n.ts.updatedAt }}:
-
-
+
+
+
{{ clip.name }}
+
+
+
{{ i18n.ts.updatedAt }}:
+
{{ i18n.ts.notesCount }}: {{ number(clip.notesCount) }} / {{ $i?.policies.noteEachClipsLimit }} ({{ i18n.tsx.remainingN({ n: remaining }) }})
+
+
+
+
+
-
+
diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue
index bcd6eb7c0ff6..e50b208775c7 100644
--- a/packages/frontend/src/pages/announcements.vue
+++ b/packages/frontend/src/pages/announcements.vue
@@ -21,14 +21,19 @@ SPDX-License-Identifier: AGPL-3.0-only
-
{{ announcement.title }}
+
{{ announcement.title }}
-
-
-
+
+
+ {{ i18n.ts.createdAt }}:
+
+
+ {{ i18n.ts.updatedAt }}:
+
+
{{ i18n.ts.gotIt }}
@@ -73,24 +78,24 @@ const paginationEl = ref
>();
const tab = ref('current');
-async function read(announcement) {
- if (announcement.needConfirmationToRead) {
+async function read(target) {
+ if (target.needConfirmationToRead) {
const confirm = await os.confirm({
type: 'question',
title: i18n.ts._announcement.readConfirmTitle,
- text: i18n.tsx._announcement.readConfirmText({ title: announcement.title }),
+ text: i18n.tsx._announcement.readConfirmText({ title: target.title }),
});
if (confirm.canceled) return;
}
if (!paginationEl.value) return;
- paginationEl.value.updateItem(announcement.id, a => {
+ paginationEl.value.updateItem(target.id, a => {
a.isRead = true;
return a;
});
- misskeyApi('i/read-announcement', { announcementId: announcement.id });
+ misskeyApi('i/read-announcement', { announcementId: target.id });
updateAccount({
- unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== announcement.id),
+ unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== target.id),
});
}
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index c5b576f505c9..c12ae0fa572b 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -193,6 +193,9 @@ const routes: RouteDef[] = [{
}, {
path: '/announcements',
component: page(() => import('@/pages/announcements.vue')),
+}, {
+ path: '/announcements/:announcementId',
+ component: page(() => import('@/pages/announcement.vue')),
}, {
path: '/about',
component: page(() => import('@/pages/about.vue')),
diff --git a/packages/frontend/src/ui/_common_/announcements.vue b/packages/frontend/src/ui/_common_/announcements.vue
index 362c29e6c250..374bc20b5450 100644
--- a/packages/frontend/src/ui/_common_/announcements.vue
+++ b/packages/frontend/src/ui/_common_/announcements.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
v-for="announcement in $i.unreadAnnouncements.filter(x => x.display === 'banner')"
:key="announcement.id"
:class="$style.item"
- to="/announcements"
+ :to="`/announcements/${announcement.id}`"
>
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 9cdb61da8770..6ff711cabbb5 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -336,6 +336,12 @@ type AnnouncementsRequest = operations['announcements']['requestBody']['content'
// @public (undocumented)
type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
+// @public (undocumented)
+type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AnnouncementsShowResponse = operations['announcements___show']['responses']['200']['content']['application/json'];
+
// @public (undocumented)
type Antenna = components['schemas']['Antenna'];
@@ -1224,6 +1230,8 @@ declare namespace entities {
AdminRolesUsersResponse,
AnnouncementsRequest,
AnnouncementsResponse,
+ AnnouncementsShowRequest,
+ AnnouncementsShowResponse,
AntennasCreateRequest,
AntennasCreateResponse,
AntennasDeleteRequest,
diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
index 729107a78dbf..181f7274b7b6 100644
--- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts
+++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
@@ -851,6 +851,17 @@ declare module '../api.js' {
credential?: string | null,
): Promise>;
+ /**
+ * No description provided.
+ *
+ * **Credential required**: *No*
+ */
+ request(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise>;
+
/**
* No description provided.
*
diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts
index b0982e1e55d0..ab3baf16700d 100644
--- a/packages/misskey-js/src/autogen/endpoint.ts
+++ b/packages/misskey-js/src/autogen/endpoint.ts
@@ -101,6 +101,8 @@ import type {
AdminRolesUsersResponse,
AnnouncementsRequest,
AnnouncementsResponse,
+ AnnouncementsShowRequest,
+ AnnouncementsShowResponse,
AntennasCreateRequest,
AntennasCreateResponse,
AntennasDeleteRequest,
@@ -631,6 +633,7 @@ export type Endpoints = {
'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse };
'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse };
'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse };
+ 'announcements/show': { req: AnnouncementsShowRequest; res: AnnouncementsShowResponse };
'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse };
'antennas/delete': { req: AntennasDeleteRequest; res: EmptyResponse };
'antennas/list': { req: EmptyRequest; res: AntennasListResponse };
diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts
index 60bf6659c0d9..02ca932d8a38 100644
--- a/packages/misskey-js/src/autogen/entities.ts
+++ b/packages/misskey-js/src/autogen/entities.ts
@@ -104,6 +104,8 @@ export type AdminRolesUsersRequest = operations['admin___roles___users']['reques
export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json'];
export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
+export type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
+export type AnnouncementsShowResponse = operations['announcements___show']['responses']['200']['content']['application/json'];
export type AntennasCreateRequest = operations['antennas___create']['requestBody']['content']['application/json'];
export type AntennasCreateResponse = operations['antennas___create']['responses']['200']['content']['application/json'];
export type AntennasDeleteRequest = operations['antennas___delete']['requestBody']['content']['application/json'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 1e9c190ca56f..208f03dc3efc 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -706,6 +706,15 @@ export type paths = {
*/
post: operations['announcements'];
};
+ '/announcements/show': {
+ /**
+ * announcements/show
+ * @description No description provided.
+ *
+ * **Credential required**: *No*
+ */
+ post: operations['announcements___show'];
+ };
'/antennas/create': {
/**
* antennas/create
@@ -9662,6 +9671,60 @@ export type operations = {
};
};
};
+ /**
+ * announcements/show
+ * @description No description provided.
+ *
+ * **Credential required**: *No*
+ */
+ announcements___show: {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ announcementId: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['Announcement'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
/**
* antennas/create
* @description No description provided.
From 1df8ea824e5dace883f0d6855d7342984c8032d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:15:42 +0900
Subject: [PATCH 089/133] =?UTF-8?q?fix(backend):=20`/@`=20=E3=81=AB?=
=?UTF-8?q?=E3=82=A2=E3=82=AF=E3=82=BB=E3=82=B9=E3=81=99=E3=82=8B=E3=81=A8?=
=?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=82=A8=E3=83=A9=E3=83=BC?=
=?UTF-8?q?=E3=81=8C=E7=99=BA=E7=94=9F=E3=81=99=E3=82=8B=E5=95=8F=E9=A1=8C?=
=?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13884)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../backend/src/server/web/ClientServerService.ts | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index f35ec8ba31ca..ab03489c0d76 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -466,7 +466,9 @@ export class ClientServerService {
};
// Atom
- fastify.get<{ Params: { user: string; } }>('/@:user.atom', async (request, reply) => {
+ fastify.get<{ Params: { user?: string; } }>('/@:user.atom', async (request, reply) => {
+ if (request.params.user == null) return await renderBase(reply);
+
const feed = await getFeed(request.params.user);
if (feed) {
@@ -479,7 +481,9 @@ export class ClientServerService {
});
// RSS
- fastify.get<{ Params: { user: string; } }>('/@:user.rss', async (request, reply) => {
+ fastify.get<{ Params: { user?: string; } }>('/@:user.rss', async (request, reply) => {
+ if (request.params.user == null) return await renderBase(reply);
+
const feed = await getFeed(request.params.user);
if (feed) {
@@ -492,7 +496,9 @@ export class ClientServerService {
});
// JSON
- fastify.get<{ Params: { user: string; } }>('/@:user.json', async (request, reply) => {
+ fastify.get<{ Params: { user?: string; } }>('/@:user.json', async (request, reply) => {
+ if (request.params.user == null) return await renderBase(reply);
+
const feed = await getFeed(request.params.user);
if (feed) {
From 1b81ca45636db21166753e0aa00d91ab23e46ac5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:16:47 +0900
Subject: [PATCH 090/133] =?UTF-8?q?enhance(frontend):=20=E3=80=8C=E8=A6=8B?=
=?UTF-8?q?=E3=81=9F=E3=81=93=E3=81=A8=E3=81=AE=E3=81=82=E3=82=8B=E3=83=AA?=
=?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E3=82=92=E7=9C=81=E7=95=A5=E3=81=97?=
=?UTF-8?q?=E3=81=A6=E8=A1=A8=E7=A4=BA=E3=80=8D=E3=81=AE=E5=90=8D=E7=A7=B0?=
=?UTF-8?q?=E3=82=92=E5=A4=89=E6=9B=B4=20(#13883)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* enhance(frontend): 「見たことのあるリノートを省略して表示」の名称を変更
* ひとつだけcaptionが入ってるやつが真ん中にいると不格好だったので場所変更
---
locales/index.d.ts | 6 +++++-
locales/ja-JP.yml | 3 ++-
packages/frontend/src/pages/settings/general.vue | 5 ++++-
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 18d8eee18fa2..eb7e297aa325 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4113,9 +4113,13 @@ export interface Locale extends ILocale {
*/
"thisPostMayBeAnnoyingIgnore": string;
/**
- * 見たことのあるリノートを省略して表示
+ * リノートのスマート省略
*/
"collapseRenotes": string;
+ /**
+ * リアクションやリノートをしたことがあるノートをたたんで表示します。
+ */
+ "collapseRenotesDescription": string;
/**
* サーバー内部エラー
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 8b1738aebe19..ebaf16745c01 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1024,7 +1024,8 @@ thisPostMayBeAnnoying: "この投稿は迷惑になる可能性があります
thisPostMayBeAnnoyingHome: "ホームに投稿"
thisPostMayBeAnnoyingCancel: "やめる"
thisPostMayBeAnnoyingIgnore: "このまま投稿"
-collapseRenotes: "見たことのあるリノートを省略して表示"
+collapseRenotes: "リノートのスマート省略"
+collapseRenotesDescription: "リアクションやリノートをしたことがあるノートをたたんで表示します。"
internalServerError: "サーバー内部エラー"
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
copyErrorInfo: "エラー情報をコピー"
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 55d514ddf9d6..cfc63f2a08d9 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -50,9 +50,12 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+ {{ i18n.ts.collapseRenotes }}
+ {{ i18n.ts.collapseRenotesDescription }}
+
{{ i18n.ts.showNoteActionsOnlyHover }}
{{ i18n.ts.showClipButtonInNoteFooter }}
-
{{ i18n.ts.collapseRenotes }}
{{ i18n.ts.enableAdvancedMfm }}
{{ i18n.ts.enableAnimatedMfm }}
{{ i18n.ts.enableQuickAddMfmFunction }}
From 805a11aadbbc0f0a32531fd86443de514df74466 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:18:12 +0900
Subject: [PATCH 091/133] =?UTF-8?q?enhance(backend):=20=E3=83=97=E3=83=AD?=
=?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=BC=E3=83=AB=E3=81=AE=E3=83=AA=E3=83=B3?=
=?UTF-8?q?=E3=82=AF=E6=A4=9C=E8=A8=BC=E3=81=ABtry-catch=E3=82=92=E8=BF=BD?=
=?UTF-8?q?=E5=8A=A0=20(#13882)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* enhance(backend): プロフィールのリンク検証にtry-catchを追加
* :v:
---
.../src/server/api/endpoints/i/update.ts | 36 +++++++++++--------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 84a1931a3df5..a8e702f328e6 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -498,26 +498,32 @@ export default class extends Endpoint
{ // eslint-
private async verifyLink(url: string, user: MiLocalUser) {
if (!safeForSql(url)) return;
- const html = await this.httpRequestService.getHtml(url);
+ try {
+ const html = await this.httpRequestService.getHtml(url);
- const { window } = new JSDOM(html);
- const doc = window.document;
+ const { window } = new JSDOM(html);
+ const doc = window.document;
- const myLink = `${this.config.url}/@${user.username}`;
+ const myLink = `${this.config.url}/@${user.username}`;
- const aEls = Array.from(doc.getElementsByTagName('a'));
- const linkEls = Array.from(doc.getElementsByTagName('link'));
+ const aEls = Array.from(doc.getElementsByTagName('a'));
+ const linkEls = Array.from(doc.getElementsByTagName('link'));
- const includesMyLink = aEls.some(a => a.href === myLink);
- const includesRelMeLinks = [...aEls, ...linkEls].some(link => link.rel === 'me' && link.href === myLink);
+ const includesMyLink = aEls.some(a => a.href === myLink);
+ const includesRelMeLinks = [...aEls, ...linkEls].some(link => link.rel === 'me' && link.href === myLink);
- if (includesMyLink || includesRelMeLinks) {
- await this.userProfilesRepository.createQueryBuilder('profile').update()
- .where('userId = :userId', { userId: user.id })
- .set({
- verifiedLinks: () => `array_append("verifiedLinks", '${url}')`, // ここでSQLインジェクションされそうなのでとりあえず safeForSql で弾いている
- })
- .execute();
+ if (includesMyLink || includesRelMeLinks) {
+ await this.userProfilesRepository.createQueryBuilder('profile').update()
+ .where('userId = :userId', { userId: user.id })
+ .set({
+ verifiedLinks: () => `array_append("verifiedLinks", '${url}')`, // ここでSQLインジェクションされそうなのでとりあえず safeForSql で弾いている
+ })
+ .execute();
+ }
+
+ window.close();
+ } catch (err) {
+ // なにもしない
}
}
}
From d013e4516d7afb6ed4362467f69df2d79b9f0f9f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 17:19:09 +0900
Subject: [PATCH 092/133] =?UTF-8?q?enhance(frontend):=20=E3=81=8A=E6=B0=97?=
=?UTF-8?q?=E3=81=AB=E5=85=A5=E3=82=8A=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D?=
=?UTF-8?q?=E3=83=AB=E3=82=92=E3=82=AD=E3=83=A3=E3=83=83=E3=82=B7=E3=83=A5?=
=?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#13881)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/frontend/src/cache.ts | 1 +
packages/frontend/src/pages/channel.vue | 3 +++
packages/frontend/src/pages/timeline.vue | 6 ++----
packages/frontend/src/scripts/get-note-menu.ts | 6 ++----
packages/frontend/src/ui/deck/channel-column.vue | 13 ++++++-------
5 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/packages/frontend/src/cache.ts b/packages/frontend/src/cache.ts
index b286528de6c9..bfe8fbe0e40a 100644
--- a/packages/frontend/src/cache.ts
+++ b/packages/frontend/src/cache.ts
@@ -11,3 +11,4 @@ export const clipsCache = new Cache(1000 * 60 * 30, ()
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
export const userListsCache = new Cache(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
export const antennasCache = new Cache(1000 * 60 * 30, () => misskeyApi('antennas/list'));
+export const favoritedChannelsCache = new Cache(1000 * 60 * 30, () => misskeyApi('channels/my-favorites', { limit: 100 }));
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue
index 611ae6feca0f..a895df76e8e9 100644
--- a/packages/frontend/src/pages/channel.vue
+++ b/packages/frontend/src/pages/channel.vue
@@ -83,6 +83,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
import { deviceKind } from '@/scripts/device-kind.js';
import MkNotes from '@/components/MkNotes.vue';
import { url } from '@/config.js';
+import { favoritedChannelsCache } from '@/cache.js';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import { defaultStore } from '@/store.js';
@@ -153,6 +154,7 @@ function favorite() {
channelId: channel.value.id,
}).then(() => {
favorited.value = true;
+ favoritedChannelsCache.delete();
});
}
@@ -168,6 +170,7 @@ async function unfavorite() {
channelId: channel.value.id,
}).then(() => {
favorited.value = false;
+ favoritedChannelsCache.delete();
});
}
diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue
index 48dfc1fd44fd..98744c631855 100644
--- a/packages/frontend/src/pages/timeline.vue
+++ b/packages/frontend/src/pages/timeline.vue
@@ -48,7 +48,7 @@ import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import { $i } from '@/account.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
-import { antennasCache, userListsCache } from '@/cache.js';
+import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
import { deviceKind } from '@/scripts/device-kind.js';
import { deepMerge } from '@/scripts/merge.js';
import { MenuItem } from '@/types/menu.js';
@@ -173,9 +173,7 @@ async function chooseAntenna(ev: MouseEvent): Promise {
}
async function chooseChannel(ev: MouseEvent): Promise {
- const channels = await misskeyApi('channels/my-favorites', {
- limit: 100,
- });
+ const channels = await favoritedChannelsCache.fetch();
const items: MenuItem[] = [
...channels.map(channel => {
const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null;
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index e7c9a848e0f4..71ad299f507f 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -16,7 +16,7 @@ import { url } from '@/config.js';
import { defaultStore, noteActions } from '@/store.js';
import { miLocalStorage } from '@/local-storage.js';
import { getUserMenu } from '@/scripts/get-user-menu.js';
-import { clipsCache } from '@/cache.js';
+import { clipsCache, favoritedChannelsCache } from '@/cache.js';
import { MenuItem } from '@/types/menu.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { isSupportShare } from '@/scripts/navigator.js';
@@ -603,9 +603,7 @@ export function getRenoteMenu(props: {
icon: 'ti ti-repeat',
text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel,
children: async () => {
- const channels = await misskeyApi('channels/my-favorites', {
- limit: 30,
- });
+ const channels = await favoritedChannelsCache.fetch();
return channels.filter((channel) => {
if (!appearNote.channelId) return true;
return channel.id !== appearNote.channelId;
diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue
index bd3b059497b1..28c741bba238 100644
--- a/packages/frontend/src/ui/deck/channel-column.vue
+++ b/packages/frontend/src/ui/deck/channel-column.vue
@@ -26,6 +26,7 @@ import { updateColumn, Column } from './deck-store.js';
import MkTimeline from '@/components/MkTimeline.vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os.js';
+import { favoritedChannelsCache } from '@/cache.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
@@ -42,20 +43,18 @@ if (props.column.channelId == null) {
}
async function setChannel() {
- const channels = await misskeyApi('channels/my-favorites', {
- limit: 100,
- });
- const { canceled, result: channel } = await os.select({
+ const channels = await favoritedChannelsCache.fetch();
+ const { canceled, result: chosenChannel } = await os.select({
title: i18n.ts.selectChannel,
items: channels.map(x => ({
value: x, text: x.name,
})),
default: props.column.channelId,
});
- if (canceled) return;
+ if (canceled || chosenChannel == null) return;
updateColumn(props.column.id, {
- channelId: channel.id,
- name: channel.name,
+ channelId: chosenChannel.id,
+ name: chosenChannel.name,
});
}
From 6af9492ea5492c02a11302afe7c6a6e83c00de1b Mon Sep 17 00:00:00 2001
From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
Date: Mon, 27 May 2024 17:21:05 +0900
Subject: [PATCH 093/133] Quick action implement (#13878)
* enhance(frontend): quick action for file admin-lookup
* docs(changelog): update changelog
* enhance(frontend): quick action for general admin-lookup, remove unimplemented note, instance admin-lookup
* docs(changelog): update changelog
* chore: fix lint
---
CHANGELOG.md | 2 ++
packages/frontend/src/pages/admin/files.vue | 27 ++-----------------
packages/frontend/src/pages/admin/index.vue | 21 ++++++---------
packages/frontend/src/pages/admin/users.vue | 2 +-
.../{lookup-user.ts => admin-lookup.ts} | 23 ++++++++++++++++
5 files changed, 36 insertions(+), 39 deletions(-)
rename packages/frontend/src/scripts/{lookup-user.ts => admin-lookup.ts} (72%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e23fa8f7273..d23f512e3ded 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,6 +49,8 @@
- Enhance: AiScriptを0.18.0にバージョンアップ
- Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
- Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
+- Enhance: コントロールパネルのクイックアクションからファイルを照会できるように
+- Enhance: コントロールパネルのクイックアクションから通常の照会を行えるように
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
- Fix: 周年の実績が閏年を考慮しない問題を修正
- Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue
index 3fe021e77102..5132b85c64ed 100644
--- a/packages/frontend/src/pages/admin/files.vue
+++ b/packages/frontend/src/pages/admin/files.vue
@@ -42,7 +42,7 @@ import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
import * as os from '@/os.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
+import { lookupFile } from '@/scripts/admin-lookup.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
@@ -73,33 +73,10 @@ function clear() {
});
}
-function show(file) {
- os.pageWindow(`/admin/file/${file.id}`);
-}
-
-async function find() {
- const { canceled, result: q } = await os.inputText({
- title: i18n.ts.fileIdOrUrl,
- minLength: 1,
- });
- if (canceled) return;
-
- misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
- show(file);
- }).catch(err => {
- if (err.code === 'NO_SUCH_FILE') {
- os.alert({
- type: 'error',
- text: i18n.ts.notFound,
- });
- }
- });
-}
-
const headerActions = computed(() => [{
text: i18n.ts.lookup,
icon: 'ti ti-search',
- handler: find,
+ handler: lookupFile,
}, {
text: i18n.ts.clearCachedFiles,
icon: 'ti ti-trash',
diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue
index d4a41c66ccb6..eef1c8afa944 100644
--- a/packages/frontend/src/pages/admin/index.vue
+++ b/packages/frontend/src/pages/admin/index.vue
@@ -33,9 +33,10 @@ import { i18n } from '@/i18n.js';
import MkSuperMenu from '@/components/MkSuperMenu.vue';
import MkInfo from '@/components/MkInfo.vue';
import { instance } from '@/instance.js';
+import { lookup } from '@/scripts/lookup.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
-import { lookupUser, lookupUserByEmail } from '@/scripts/lookup-user.js';
+import { lookupUser, lookupUserByEmail, lookupFile } from '@/scripts/admin-lookup.js';
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
import { useRouter } from '@/router/supplier.js';
@@ -82,7 +83,7 @@ const menuDef = computed(() => [{
type: 'button',
icon: 'ti ti-search',
text: i18n.ts.lookup,
- action: lookup,
+ action: adminLookup,
}, ...(instance.disableRegistration ? [{
type: 'button',
icon: 'ti ti-user-plus',
@@ -282,7 +283,7 @@ function invite() {
});
}
-function lookup(ev: MouseEvent) {
+function adminLookup(ev: MouseEvent) {
os.popupMenu([{
text: i18n.ts.user,
icon: 'ti ti-user',
@@ -295,23 +296,17 @@ function lookup(ev: MouseEvent) {
action: () => {
lookupUserByEmail();
},
- }, {
- text: i18n.ts.note,
- icon: 'ti ti-pencil',
- action: () => {
- alert('TODO');
- },
}, {
text: i18n.ts.file,
icon: 'ti ti-cloud',
action: () => {
- alert('TODO');
+ lookupFile();
},
}, {
- text: i18n.ts.instance,
- icon: 'ti ti-planet',
+ text: i18n.ts.lookup,
+ icon: 'ti ti-world-search',
action: () => {
- alert('TODO');
+ lookup();
},
}], ev.currentTarget ?? ev.target);
}
diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue
index 06317760d2ac..7d87b97a3615 100644
--- a/packages/frontend/src/pages/admin/users.vue
+++ b/packages/frontend/src/pages/admin/users.vue
@@ -63,7 +63,7 @@ import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
import * as os from '@/os.js';
-import { lookupUser } from '@/scripts/lookup-user.js';
+import { lookupUser } from '@/scripts/admin-lookup.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
diff --git a/packages/frontend/src/scripts/lookup-user.ts b/packages/frontend/src/scripts/admin-lookup.ts
similarity index 72%
rename from packages/frontend/src/scripts/lookup-user.ts
rename to packages/frontend/src/scripts/admin-lookup.ts
index efc9132e757c..1b57b853c97b 100644
--- a/packages/frontend/src/scripts/lookup-user.ts
+++ b/packages/frontend/src/scripts/admin-lookup.ts
@@ -63,3 +63,26 @@ export async function lookupUserByEmail() {
}
}
}
+
+export async function lookupFile() {
+ const { canceled, result: q } = await os.inputText({
+ title: i18n.ts.fileIdOrUrl,
+ minLength: 1,
+ });
+ if (canceled) return;
+
+ const show = (file) => {
+ os.pageWindow(`/admin/file/${file.id}`);
+ };
+
+ misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
+ show(file);
+ }).catch(err => {
+ if (err.code === 'NO_SUCH_FILE') {
+ os.alert({
+ type: 'error',
+ text: i18n.ts.notFound,
+ });
+ }
+ });
+}
From 140df4b5e050f1c2b55e08f9c5b511588b0370d2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 27 May 2024 08:27:39 +0000
Subject: [PATCH 094/133] Bump version to 2024.5.0-beta.3
---
package.json | 2 +-
packages/misskey-js/package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index b9ac4fc2a16f..22e5217ea287 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "misskey",
- "version": "2024.5.0-beta.2",
+ "version": "2024.5.0-beta.3",
"codename": "nasubi",
"repository": {
"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 80ae84796aaa..d72004862c72 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
- "version": "2024.5.0-beta.2",
+ "version": "2024.5.0-beta.3",
"description": "Misskey SDK for JavaScript",
"main": "./built/index.js",
"types": "./built/index.d.ts",
From e50107792c870098ac78a64d8a92e69d5f11893a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 27 May 2024 08:37:07 +0000
Subject: [PATCH 095/133] Bump version to 2024.5.0-beta.4
---
package.json | 2 +-
packages/misskey-js/package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 22e5217ea287..ca3883b804b5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "misskey",
- "version": "2024.5.0-beta.3",
+ "version": "2024.5.0-beta.4",
"codename": "nasubi",
"repository": {
"type": "git",
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index d72004862c72..bad0142899b5 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
- "version": "2024.5.0-beta.3",
+ "version": "2024.5.0-beta.4",
"description": "Misskey SDK for JavaScript",
"main": "./built/index.js",
"types": "./built/index.d.ts",
From 28e0e20879d2b2834b5f3f47fdf8663afa8a07f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 27 May 2024 19:22:46 +0900
Subject: [PATCH 096/133] [ci skip] Delete .github/FUNDING.yml
use misskey-dev/.github repository
---
.github/FUNDING.yml | 4 ----
1 file changed, 4 deletions(-)
delete mode 100644 .github/FUNDING.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index d42b58abc09c..000000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-# These are supported funding model platforms
-
-github: [misskey-dev]
-patreon: syuilo
From cf2256cf4162f0f58fea3afbe08d9805451a9efc Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Mon, 27 May 2024 20:11:39 +0900
Subject: [PATCH 097/133] fix: CHANGELOG not reflecting correctly (#13888)
* fix: CHANGELOG not reflecting correctly
* Update .github/workflows/release-edit-with-push.yml
Co-authored-by: anatawa12
---------
Co-authored-by: anatawa12
---
.github/workflows/release-edit-with-push.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml
index 944b98eb7cc2..890cb047bd05 100644
--- a/.github/workflows/release-edit-with-push.yml
+++ b/.github/workflows/release-edit-with-push.yml
@@ -37,4 +37,7 @@ jobs:
# PRのnotesを更新
- name: Update PR
run: |
- gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}"
+ gh pr edit "$PR_NUMBER" --body "$CHANGELOG"
+ env:
+ CHANGELOG: ${{ steps.changelog.outputs.changelog }}
+ PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }}
From a7a8dc4dbbab075cdee140f468fd7e3559cde475 Mon Sep 17 00:00:00 2001
From: anatawa12
Date: Mon, 27 May 2024 20:12:25 +0900
Subject: [PATCH 098/133] =?UTF-8?q?=E3=82=82=E3=81=A8=E3=82=82=E3=81=A8?=
=?UTF-8?q?=E3=82=BB=E3=83=B3=E3=82=B7=E3=83=86=E3=82=A3=E3=83=96=E3=81=A7?=
=?UTF-8?q?=E3=81=AF=E3=81=AA=E3=81=84=E3=81=A8=E9=80=A3=E5=90=88=E3=81=95?=
=?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=84=E3=81=9F=E3=83=95=E3=82=A1=E3=82=A4?=
=?UTF-8?q?=E3=83=AB=E3=81=8C=E3=82=BB=E3=83=B3=E3=82=B7=E3=83=86=E3=82=A3?=
=?UTF-8?q?=E3=83=96=E3=81=A8=E3=81=97=E3=81=A6=E9=80=A3=E5=90=88=E3=81=95?=
=?UTF-8?q?=E3=82=8C=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AB=E3=82=BB=E3=83=B3?=
=?UTF-8?q?=E3=82=B7=E3=83=86=E3=82=A3=E3=83=96=E3=81=A8=E3=81=97=E3=81=A6?=
=?UTF-8?q?=E3=81=9D=E3=81=AE=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92?=
=?UTF-8?q?=E6=89=B1=E3=81=86=E3=82=88=E3=81=86=E3=81=AB=20(#13879)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat(backend): mark an file as sensitive if the file was newly federated as sensitive
* docs(changelog): もともとセンシティブではないと連合されていたファイルがセンシティブとして連合された場合にセンシティブとしてそのファイルを扱うように
* fix: change way to update federated image
* Update packages/backend/src/core/DriveService.ts
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
* update isSensitive of existing record object
---------
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
---
CHANGELOG.md | 2 ++
packages/backend/src/core/DriveService.ts | 6 ++++++
2 files changed, 8 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d23f512e3ded..f8463f8cbf60 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -96,6 +96,8 @@
- Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
- Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正
- Fix: `/tags` と `/user-tags` が検索エンジンにインデックスされないように
+- Fix: もともとセンシティブではないと連合されていたファイルがセンシティブとして連合された場合にセンシティブとしてそのファイルを扱うように
+ - センシティブとして連合したファイルは非センシティブとして連合されてもセンシティブとして扱われます
## 2024.3.1
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 1bc1df1dda4c..63fa26f69d5c 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -504,6 +504,12 @@ export class DriveService {
if (much) {
this.registerLogger.info(`file with same hash is found: ${much.id}`);
+ if (sensitive && !much.isSensitive) {
+ // The file is federated as sensitive for this time, but was federated as non-sensitive before.
+ // Therefore, update the file to sensitive.
+ await this.driveFilesRepository.update({ id: much.id }, { isSensitive: true });
+ much.isSensitive = true;
+ }
return much;
}
}
From d7982e471c11d0656fa1266b2e4747ca5179647d Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Mon, 27 May 2024 20:24:15 +0900
Subject: [PATCH 099/133] New Crowdin updates (#13860)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (Chinese Simplified)
* New translations ja-jp.yml (Spanish)
* New translations ja-jp.yml (Italian)
* New translations ja-jp.yml (Japanese, Kansai)
* New translations ja-jp.yml (Indonesian)
* New translations ja-jp.yml (French)
* New translations ja-jp.yml (Czech)
* New translations ja-jp.yml (German)
* New translations ja-jp.yml (Korean)
* New translations ja-jp.yml (Polish)
* New translations ja-jp.yml (Portuguese)
* New translations ja-jp.yml (Vietnamese)
* New translations ja-jp.yml (Romanian)
* New translations ja-jp.yml (Arabic)
* New translations ja-jp.yml (Catalan)
* New translations ja-jp.yml (Dutch)
* New translations ja-jp.yml (Norwegian)
* New translations ja-jp.yml (Russian)
* New translations ja-jp.yml (Slovak)
* New translations ja-jp.yml (Swedish)
* New translations ja-jp.yml (Turkish)
* New translations ja-jp.yml (Ukrainian)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (English)
* New translations ja-jp.yml (Bengali)
* New translations ja-jp.yml (Thai)
* New translations ja-jp.yml (Uzbek)
* New translations ja-jp.yml (Lao)
* New translations ja-jp.yml (Korean (Gyeongsang))
* New translations ja-jp.yml (Chinese Simplified)
* New translations ja-jp.yml (Spanish)
* New translations ja-jp.yml (Italian)
* New translations ja-jp.yml (Japanese, Kansai)
* New translations ja-jp.yml (Indonesian)
* New translations ja-jp.yml (Korean)
* New translations ja-jp.yml (Catalan)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (English)
* New translations ja-jp.yml (Thai)
* New translations ja-jp.yml (Chinese Simplified)
* New translations ja-jp.yml (Chinese Simplified)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (English)
* New translations ja-jp.yml (Chinese Traditional)
* New translations ja-jp.yml (Danish)
* New translations ja-jp.yml (Chinese Simplified)
---
locales/ar-SA.yml | 2 +
locales/bn-BD.yml | 4 ++
locales/ca-ES.yml | 5 +-
locales/cs-CZ.yml | 4 ++
locales/da-DK.yml | 2 +
locales/de-DE.yml | 4 ++
locales/en-US.yml | 14 +++++-
locales/es-ES.yml | 5 +-
locales/fr-FR.yml | 4 ++
locales/id-ID.yml | 14 +++++-
locales/it-IT.yml | 5 +-
locales/ja-KS.yml | 5 +-
locales/ko-GS.yml | 4 ++
locales/ko-KR.yml | 5 +-
locales/lo-LA.yml | 4 ++
locales/nl-NL.yml | 4 ++
locales/no-NO.yml | 2 +
locales/pl-PL.yml | 4 ++
locales/pt-PT.yml | 4 ++
locales/ro-RO.yml | 4 ++
locales/ru-RU.yml | 4 ++
locales/sk-SK.yml | 4 ++
locales/sv-SE.yml | 4 ++
locales/th-TH.yml | 5 +-
locales/tr-TR.yml | 4 ++
locales/uk-UA.yml | 4 ++
locales/uz-UZ.yml | 4 ++
locales/vi-VN.yml | 4 ++
locales/zh-CN.yml | 14 +++++-
locales/zh-TW.yml | 124 +++++++++++++++++++++++++---------------------
30 files changed, 205 insertions(+), 65 deletions(-)
diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index 88707fe1118e..955d672c1d05 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -1016,6 +1016,8 @@ sourceCode: "الشفرة المصدرية"
flip: "اقلب"
lastNDays: "آخر {n} أيام"
surrender: "ألغِ"
+_delivery:
+ stop: "مُعلّق"
_initialAccountSetting:
accountCreated: "نجح إنشاء حسابك!"
letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index dc5d315aed9f..abcf07da831e 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -857,6 +857,10 @@ replies: "জবাব"
renotes: "রিনোট"
sourceCode: "সোর্স কোড"
flip: "উল্টান"
+_delivery:
+ stop: "স্থগিত করা হয়েছে"
+ _type:
+ none: "প্রকাশ করা হচ্ছে"
_role:
priority: "অগ্রাধিকার"
_priority:
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index d035555c73af..0345ee0326e9 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -1224,6 +1224,10 @@ gameRetry: "Torna a provar"
notUsePleaseLeaveBlank: "Si no voleu usar-ho, deixeu-ho en blanc"
useTotp: "Usa una contrasenya d'un sol ús"
useBackupCode: "Usa un codi de recuperació"
+_delivery:
+ stop: "Suspés"
+ _type:
+ none: "S'està publicant"
_bubbleGame:
howToPlay: "Com es juga"
_howToPlay:
@@ -2001,7 +2005,6 @@ _permissions:
"read:admin:server-info": "Veure informació del servidor"
"read:admin:show-moderation-log": "Veure registre de moderació "
"read:admin:show-user": "Veure informació privada de l'usuari "
- "read:admin:show-users": "Veure informació privada de l'usuari "
"write:admin:suspend-user": "Suspendre usuari"
"write:admin:unset-user-avatar": "Esborrar avatar d'usuari "
"write:admin:unset-user-banner": "Esborrar bàner de l'usuari "
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index cff533976ec6..c8a0b0cb2804 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -1099,6 +1099,10 @@ sourceCode: "Zdrojový kód"
flip: "Otočit"
lastNDays: "Posledních {n} dnů"
surrender: "Zrušit"
+_delivery:
+ stop: "Suspendováno"
+ _type:
+ none: "Publikuji"
_initialAccountSetting:
accountCreated: "Váš účet byl úspěšně vytvořen!"
letsStartAccountSetup: "Pro začátek si nastavte svůj profil."
diff --git a/locales/da-DK.yml b/locales/da-DK.yml
index 08c15ed092fc..5eb7a5a5f417 100644
--- a/locales/da-DK.yml
+++ b/locales/da-DK.yml
@@ -1,2 +1,4 @@
---
_lang_: "Dansk"
+headlineMisskey: ""
+introMisskey: "ようこそ!Misskeyは、オープンソースの分散型マイクロブログサービスです。\n「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 3e1c40512e77..9e42e0125257 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -1185,6 +1185,10 @@ addMfmFunction: "MFM hinzufügen"
sfx: "Soundeffekte"
lastNDays: "Letzten {n} Tage"
surrender: "Abbrechen"
+_delivery:
+ stop: "Gesperrt"
+ _type:
+ none: "Wird veröffentlicht"
_announcement:
forExistingUsers: "Nur für existierende Nutzer"
forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 10e9fd778e70..c20a1ac7d8ef 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -108,11 +108,14 @@ enterEmoji: "Enter an emoji"
renote: "Renote"
unrenote: "Remove renote"
renoted: "Renoted."
+renotedToX: "Renote from {name} users。"
cantRenote: "This post can't be renoted."
cantReRenote: "A renote can't be renoted."
quote: "Quote"
inChannelRenote: "Channel-only Renote"
inChannelQuote: "Channel-only Quote"
+renoteToChannel: "Renote to channel"
+renoteToOtherChannel: "Renote to other channel"
pinnedNote: "Pinned note"
pinned: "Pin to profile"
you: "You"
@@ -468,6 +471,7 @@ retype: "Enter again"
noteOf: "Note by {user}"
quoteAttached: "Quote"
quoteQuestion: "Append as quote?"
+attachAsFileQuestion: "The text in clipboard is long. Would you want to attach it as text file?"
noMessagesYet: "No messages yet"
newMessageExists: "There are new messages"
onlyOneFileCanBeAttached: "You can only attach one file to a message"
@@ -1235,6 +1239,15 @@ keepOriginalFilenameDescription: "If you turn off this setting, files names will
noDescription: "There is not the explanation"
alwaysConfirmFollow: "Always confirm when following"
inquiry: "Contact"
+_delivery:
+ status: "Delivery status"
+ stop: "Suspended"
+ resume: "Delivery resume"
+ _type:
+ none: "Publishing"
+ manuallySuspended: "Manually suspended"
+ goneSuspended: "Server is suspended due to server deletion"
+ autoSuspendedForNotResponding: "Server is suspended due to no responding"
_bubbleGame:
howToPlay: "How to play"
hold: "Hold"
@@ -2032,7 +2045,6 @@ _permissions:
"read:admin:server-info": "View server info"
"read:admin:show-moderation-log": "View moderation log"
"read:admin:show-user": "View private user info"
- "read:admin:show-users": "View private user info"
"write:admin:suspend-user": "Suspend user"
"write:admin:unset-user-avatar": "Remove user avatar"
"write:admin:unset-user-banner": "Remove user banner"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index 2e05364c312f..5c8249ded50f 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -1233,6 +1233,10 @@ useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reprod
keepOriginalFilename: "Mantener el nombre original del archivo"
noDescription: "No hay descripción"
alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
+_delivery:
+ stop: "Suspendido"
+ _type:
+ none: "Publicando"
_bubbleGame:
howToPlay: "Cómo jugar"
hold: "Mantener"
@@ -2029,7 +2033,6 @@ _permissions:
"read:admin:server-info": "Ver información del servidor"
"read:admin:show-moderation-log": "Ver log de moderación"
"read:admin:show-user": "Ver información privada de usuario"
- "read:admin:show-users": "Ver información privada de usuario"
"write:admin:suspend-user": "Suspender cuentas de usuario"
"write:admin:unset-user-avatar": "Quitar avatares de usuario"
"write:admin:unset-user-banner": "Quitar banner de usuarios"
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 58a11a5cc4ea..8d66c3d37572 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -1224,6 +1224,10 @@ enableHorizontalSwipe: "Glisser pour changer d'onglet"
loading: "Chargement en cours"
surrender: "Annuler"
gameRetry: "Réessayer"
+_delivery:
+ stop: "Suspendu·e"
+ _type:
+ none: "Publié"
_bubbleGame:
howToPlay: "Comment jouer"
hold: "Réserver"
diff --git a/locales/id-ID.yml b/locales/id-ID.yml
index f8e645d63b57..7f509afa501a 100644
--- a/locales/id-ID.yml
+++ b/locales/id-ID.yml
@@ -108,11 +108,14 @@ enterEmoji: "Masukkan emoji"
renote: "Renote"
unrenote: "Hapus renote"
renoted: "Telah direnote"
+renotedToX: "{name} telah merenote"
cantRenote: "Postingan ini tidak dapat direnote"
cantReRenote: "Renote tidak dapat direnote"
quote: "Kutip"
inChannelRenote: "Hanya renote dalam kanal"
inChannelQuote: "Hanya kutip dalam kanal"
+renoteToChannel: "Renote ke kanal"
+renoteToOtherChannel: "Renote ke kanal lainnya"
pinnedNote: "Catatan yang disematkan"
pinned: "Sematkan ke profil"
you: "Kamu"
@@ -468,6 +471,7 @@ retype: "Masukkan ulang"
noteOf: "Catatan milik {user}"
quoteAttached: "Dikutip"
quoteQuestion: "Apakah kamu ingin menambahkan kutipan?"
+attachAsFileQuestion: "Teks dalam papan klip terlalu panjang. Apakah kamu ingin melampirkannya sebagai berkas teks?"
noMessagesYet: "Tidak ada pesan"
newMessageExists: "Kamu mendapatkan pesan baru"
onlyOneFileCanBeAttached: "Kamu hanya dapat melampirkan satu berkas ke dalam pesan"
@@ -1235,6 +1239,15 @@ keepOriginalFilenameDescription: "Apabila pengaturan ini dimatikan, nama berkas
noDescription: "Tidak ada deskripsi"
alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
inquiry: "Hubungi kami"
+_delivery:
+ status: "Status pengiriman"
+ stop: "Ditangguhkan"
+ resume: "Lanjutkan pengiriman"
+ _type:
+ none: "Sedang menyiarkan langsung"
+ manuallySuspended: "Ditangguhkan manual"
+ goneSuspended: "Sedang ditangguhkan untuk penghapusan peladen"
+ autoSuspendedForNotResponding: "Sedang ditangguhkan karena peladen tidak menjawab"
_bubbleGame:
howToPlay: "Cara bermain"
hold: "Tahan"
@@ -2032,7 +2045,6 @@ _permissions:
"read:admin:server-info": "Lihat informasi peladen"
"read:admin:show-moderation-log": "Lihat log moderasi"
"read:admin:show-user": "Lihat informasi pengguna privat"
- "read:admin:show-users": "Lihat informasi pengguna privat"
"write:admin:suspend-user": "Tangguhkan pengguna"
"write:admin:unset-user-avatar": "Hapus avatar pengguna"
"write:admin:unset-user-banner": "Hapus banner pengguna"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 0a250a2e289e..1d12a62ccadc 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -1233,6 +1233,10 @@ useNativeUIForVideoAudioPlayer: "Riprodurre audio/video usando le funzionalità
keepOriginalFilename: "Mantieni il nome file originale"
keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
noDescription: "Manca la descrizione"
+_delivery:
+ stop: "Sospensione"
+ _type:
+ none: "Pubblicazione"
_bubbleGame:
howToPlay: "Come giocare"
hold: "Tieni"
@@ -2025,7 +2029,6 @@ _permissions:
"read:admin:server-info": "Vedere le informazioni sul server"
"read:admin:show-moderation-log": "Vedere lo storico di moderazione"
"read:admin:show-user": "Vedere le informazioni private degli account utente"
- "read:admin:show-users": "Vedere le informazioni private degli account utente"
"write:admin:suspend-user": "Sospendere i profili"
"write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili"
"write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index e6a23a34d7e2..7a33968e9e37 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -1235,6 +1235,10 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ
noDescription: "説明文はあらへんで"
alwaysConfirmFollow: "フォローの際常に確認する"
inquiry: "問い合わせ"
+_delivery:
+ stop: "配信せぇへん"
+ _type:
+ none: "配信しとる"
_bubbleGame:
howToPlay: "遊び方"
hold: "ホールド"
@@ -2032,7 +2036,6 @@ _permissions:
"read:admin:server-info": "サーバーの情報見る"
"read:admin:show-moderation-log": "モデレーションログ見る"
"read:admin:show-user": "ユーザーのプライベートな情報見る"
- "read:admin:show-users": "ユーザーのプライベートな情報見る"
"write:admin:suspend-user": "ユーザーを凍結"
"write:admin:unset-user-avatar": "ユーザーのアバターを削除"
"write:admin:unset-user-banner": "ユーザーのバナーを削除"
diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml
index c80a4d399752..9466aff01f41 100644
--- a/locales/ko-GS.yml
+++ b/locales/ko-GS.yml
@@ -649,6 +649,10 @@ replies: "답하기"
renotes: "리노트"
attach: "옇기"
surrender: "아이예"
+_delivery:
+ stop: "고만 보내예"
+ _type:
+ none: "보내고 잇어예"
_initialAccountSetting:
startTutorial: "길라잡이 하기"
_initialTutorial:
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index fc3a64acab1d..294a5a1520cd 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -1230,6 +1230,10 @@ useTotp: "일회용 비밀번호 사용"
useBackupCode: "백업 코드 사용"
launchApp: "앱 실행"
useNativeUIForVideoAudioPlayer: "브라우저 UI에서 미디어 재생"
+_delivery:
+ stop: "정지됨"
+ _type:
+ none: "배포 중"
_bubbleGame:
howToPlay: "설명"
hold: "홀드"
@@ -2021,7 +2025,6 @@ _permissions:
"read:admin:server-info": "서버 정보 보기"
"read:admin:show-moderation-log": "조정 기록 보기"
"read:admin:show-user": "사용자 개인정보 보기"
- "read:admin:show-users": "사용자 개인정보 보기"
"write:admin:suspend-user": "사용자 정지하기"
"write:admin:unset-user-avatar": "사용자 아바타 삭제하기"
"write:admin:unset-user-banner": "사용자 배너 삭제하기"
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index fa4b3b6f9a95..087bac374524 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -395,6 +395,10 @@ searchByGoogle: "ຄົ້ນຫາ"
file: "ໄຟລ໌"
replies: "ຕອບໄປທີ"
renotes: "Renote"
+_delivery:
+ stop: "ໂຈະ"
+ _type:
+ none: "ການພິມເຜີຍແຜ່"
_role:
_priority:
middle: "ປານກາງ"
diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml
index e33b978bc857..eb48cf72da02 100644
--- a/locales/nl-NL.yml
+++ b/locales/nl-NL.yml
@@ -429,6 +429,10 @@ loggedInAsBot: "Momenteel als bot ingelogd"
icon: "Avatar"
replies: "Antwoord"
renotes: "Herdelen"
+_delivery:
+ stop: "Opgeschort"
+ _type:
+ none: "Publiceren"
_email:
_follow:
title: "volgde jou"
diff --git a/locales/no-NO.yml b/locales/no-NO.yml
index 475f93267be8..2b4c9b77761f 100644
--- a/locales/no-NO.yml
+++ b/locales/no-NO.yml
@@ -464,6 +464,8 @@ icon: "Avatar"
replies: "Svar"
renotes: "Renote"
surrender: "Avbryt"
+_delivery:
+ stop: "Suspendert"
_initialAccountSetting:
theseSettingsCanEditLater: "Du kan endre disse innstillingene senere."
_achievements:
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index 2183aa3022bc..9d75f7a9d76a 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -1023,6 +1023,10 @@ flip: "Odwróć"
lastNDays: "W ciągu ostatnich {n} dni"
surrender: "Odrzuć"
gameRetry: "Spróbuj ponownie"
+_delivery:
+ stop: "Zawieszono"
+ _type:
+ none: "Publikowanie"
_bubbleGame:
_score:
score: "Wynik"
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index e00f5750ddb5..cfc576b6e119 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -1012,6 +1012,10 @@ keepScreenOn: "Manter a tela do dispositivo sempre ligada"
flip: "Inversão"
lastNDays: "Últimos {n} dias"
surrender: "Cancelar"
+_delivery:
+ stop: "Suspenso"
+ _type:
+ none: "Publicando"
_initialAccountSetting:
followUsers: "Siga usuários que lhe interessam para criar a sua linha do tempo."
_serverSettings:
diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml
index 695eb2501fe6..328d34405e30 100644
--- a/locales/ro-RO.yml
+++ b/locales/ro-RO.yml
@@ -651,6 +651,10 @@ show: "Arată"
icon: "Avatar"
replies: "Răspunde"
renotes: "Re-notează"
+_delivery:
+ stop: "Suspendat"
+ _type:
+ none: "Publicare"
_role:
_priority:
middle: "Mediu"
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index 66e032f16f82..71f5cad601b5 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -1099,6 +1099,10 @@ flip: "Переворот"
code: "Код"
lastNDays: "Последние {n} сут"
surrender: "Этот пост не может быть отменен."
+_delivery:
+ stop: "Заморожено"
+ _type:
+ none: "Публикация"
_initialAccountSetting:
accountCreated: "Аккаунт успешно создан!"
letsStartAccountSetup: "Давайте настроим вашу учётную запись."
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 0978701e5557..52f6bf142cac 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -922,6 +922,10 @@ renotes: "Preposlať"
sourceCode: "Zdrojový kód"
flip: "Preklopiť"
lastNDays: "Posledných {n} dní"
+_delivery:
+ stop: "Zmrazené"
+ _type:
+ none: "Zverejňovanie"
_role:
priority: "Priorita"
_priority:
diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml
index 62bc71a13df2..089dc3949f8a 100644
--- a/locales/sv-SE.yml
+++ b/locales/sv-SE.yml
@@ -488,6 +488,10 @@ dataSaver: "Databesparing"
icon: "Profilbild"
replies: "Svara"
renotes: "Omnotera"
+_delivery:
+ stop: "Suspenderad"
+ _type:
+ none: "Publiceras"
_achievements:
_types:
_open3windows:
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index 020b95485475..ab09ac4d5a45 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -1235,6 +1235,10 @@ keepOriginalFilenameDescription: "หากปิดการตั้งค่
noDescription: "ไม่มีข้อความอธิบาย"
alwaysConfirmFollow: "แสดงข้อความยืนยันเมื่อกดติดตาม"
inquiry: "ติดต่อเรา"
+_delivery:
+ stop: "ถูกระงับ"
+ _type:
+ none: "กำลังเผยแพร่"
_bubbleGame:
howToPlay: "วิธีเล่น"
hold: "หยุดชั่วคราว"
@@ -2032,7 +2036,6 @@ _permissions:
"read:admin:server-info": "ดูข้อมูลเซิร์ฟเวอร์"
"read:admin:show-moderation-log": "ดูปูมการแก้ไข"
"read:admin:show-user": "ดูข้อมูลส่วนตัวของผู้ใช้"
- "read:admin:show-users": "ดูข้อมูลส่วนตัวของผู้ใช้"
"write:admin:suspend-user": "ระงับผู้ใช้"
"write:admin:unset-user-avatar": "ลบอวตารผู้ใช้"
"write:admin:unset-user-banner": "ลบแบนเนอร์ผู้ใช้"
diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml
index 0793592d3402..cf6729a81d8e 100644
--- a/locales/tr-TR.yml
+++ b/locales/tr-TR.yml
@@ -378,6 +378,10 @@ addMemo: "Kısa not ekle"
icon: "Avatar"
replies: "yanıt"
renotes: "vazgeçme"
+_delivery:
+ stop: "Askıya alınmış"
+ _type:
+ none: "Paylaşım"
_accountDelete:
started: "Silme işlemi başlatıldı"
_email:
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index 0ce5dc12028d..661ecf19d7d9 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -914,6 +914,10 @@ renotes: "Поширити"
sourceCode: "Вихідний код"
flip: "Перевернути"
lastNDays: "Останні {n} днів"
+_delivery:
+ stop: "Призупинено"
+ _type:
+ none: "Публікація"
_achievements:
earnedAt: "Відкрито"
_types:
diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml
index 809e78549295..4a930626f4f8 100644
--- a/locales/uz-UZ.yml
+++ b/locales/uz-UZ.yml
@@ -846,6 +846,10 @@ icon: "Avatar"
replies: "Javob berish"
renotes: "Qayta qayd etish"
flip: "Teskari"
+_delivery:
+ stop: "To'xtatilgan"
+ _type:
+ none: "Yuborilmoqda"
_achievements:
_types:
_viewInstanceChart:
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index d9c21d29ad4c..acc2e0c6a99e 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -1118,6 +1118,10 @@ pullDownToRefresh: "Kéo xuống để làm mới"
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
lastNDays: "{n} ngày trước"
surrender: "Từ chối"
+_delivery:
+ stop: "Đã vô hiệu hóa"
+ _type:
+ none: "Đang đăng"
_announcement:
forExistingUsers: "Chỉ những người dùng đã tồn tại"
forExistingUsersDescription: "Nếu được bật, thông báo này sẽ chỉ hiển thị với những người dùng đã tồn tại vào lúc thông báo được tạo. Nếu tắt đi, những tài khoản mới đăng ký sau khi thông báo được đăng lên cũng sẽ thấy nó."
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 17164dfe988c..3e500f8642b8 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -471,6 +471,7 @@ retype: "重新输入"
noteOf: "{user} 的帖子"
quoteAttached: "已引用"
quoteQuestion: "是否引用此链接内容?"
+attachAsFileQuestion: "剪贴板内的文字过长。要转换为文本文件并添加吗?"
noMessagesYet: "现在没有新的聊天"
newMessageExists: "新信息"
onlyOneFileCanBeAttached: "只能添加一个附件"
@@ -1024,6 +1025,7 @@ thisPostMayBeAnnoyingHome: "发到首页"
thisPostMayBeAnnoyingCancel: "取消"
thisPostMayBeAnnoyingIgnore: "就这样发布"
collapseRenotes: "省略显示已经看过的转发内容"
+collapseRenotesDescription: "将回应过或转贴过的贴子折叠表示。"
internalServerError: "内部服务器错误"
internalServerErrorDescription: "内部服务器发生了预期外的错误"
copyErrorInfo: "复制错误信息"
@@ -1238,6 +1240,15 @@ keepOriginalFilenameDescription: "若关闭此设置,上传文件时文件名
noDescription: "没有描述"
alwaysConfirmFollow: "总是确认关注"
inquiry: "联系我们"
+_delivery:
+ status: "投递状态"
+ stop: "停止投递"
+ resume: "继续投递"
+ _type:
+ none: "投递中"
+ manuallySuspended: "手动停止中"
+ goneSuspended: "因服务器被删除而停止"
+ autoSuspendedForNotResponding: "因服务器无应答而停止"
_bubbleGame:
howToPlay: "游戏说明"
hold: "抓住"
@@ -1696,8 +1707,10 @@ _role:
roleAssignedTo: "已分配给手动角色"
isLocal: "是本地用户"
isRemote: "是远程用户"
+ isCat: "猫猫用户"
isBot: "机器人用户"
isSuspended: "停用的用户"
+ isLocked: "锁推用户"
isExplorable: "启用“使账号可见”的用户"
createdLessThan: "账户创建时间少于"
createdMoreThan: "账户创建时间超过"
@@ -2032,7 +2045,6 @@ _permissions:
"read:admin:server-info": "查看服务器信息"
"read:admin:show-moderation-log": "查看管理日志"
"read:admin:show-user": "查看用户的非公开信息"
- "read:admin:show-users": "查看用户的非公开信息"
"write:admin:suspend-user": "冻结用户"
"write:admin:unset-user-avatar": "删除用户头像"
"write:admin:unset-user-banner": "删除用户横幅"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 8cde13052f35..fed7b642dcee 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -108,11 +108,14 @@ enterEmoji: "輸入表情符號"
renote: "轉發"
unrenote: "取消轉發"
renoted: "轉發成功。"
+renotedToX: "轉發給 {name} 了。"
cantRenote: "無法轉發此貼文。"
cantReRenote: "無法轉發之前已經轉發過的內容。"
quote: "引用"
inChannelRenote: "在頻道內轉發"
inChannelQuote: "在頻道內引用"
+renoteToChannel: "轉發至頻道"
+renoteToOtherChannel: "轉發至其他頻道"
pinnedNote: "已置頂的貼文"
pinned: "置頂"
you: "您"
@@ -169,7 +172,7 @@ cacheRemoteSensitiveFilesDescription: "若停用這個設定,則不會快取
flagAsBot: "此使用者是機器人"
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整 Misskey 內部系統將本帳戶識別為機器人。"
flagAsCat: "此帳戶是一隻貓,喵~~~!!!"
-flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示"
+flagAsCatDescription: "喵喵喵??"
flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
flagShowTimelineRepliesDescription: "啟用後,時間軸除了顯示使用者的貼文以外,還會顯示使用者對其他貼文的回覆。"
autoAcceptFollowed: "自動允許來自追隨中使用者的追隨請求"
@@ -366,7 +369,7 @@ enableRegistration: "開放新使用者註冊"
invite: "邀請"
driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
-inMb: "以Mbps為單位"
+inMb: "以 MB 為單位"
bannerUrl: "橫幅圖片URL"
backgroundImageUrl: "背景圖片的來源網址 "
basicInfo: "基本資訊"
@@ -378,12 +381,12 @@ pinnedClipId: "置頂的摘錄ID"
pinnedNotes: "已置頂的貼文"
hcaptcha: "hCaptcha"
enableHcaptcha: "啟用 hCaptcha"
-hcaptchaSiteKey: "網站金鑰"
-hcaptchaSecretKey: "金鑰"
+hcaptchaSiteKey: "hcaptchaSiteKey"
+hcaptchaSecretKey: "hcaptchaSecretKey"
mcaptcha: "mCaptcha"
enableMcaptcha: "啟用 mCaptcha"
mcaptchaSiteKey: "網站金鑰"
-mcaptchaSecretKey: "金鑰"
+mcaptchaSecretKey: "私密金鑰"
mcaptchaInstanceUrl: "mCaptcha 的實例網址"
recaptcha: "reCAPTCHA"
enableRecaptcha: "啟用 reCAPTCHA"
@@ -391,8 +394,8 @@ recaptchaSiteKey: "網站金鑰"
recaptchaSecretKey: "金鑰"
turnstile: "Turnstile"
enableTurnstile: "啟用 Turnstile"
-turnstileSiteKey: "網站金鑰"
-turnstileSecretKey: "金鑰"
+turnstileSiteKey: "turnstileSiteKey"
+turnstileSecretKey: "turnstileSecretKey"
avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要關閉其他驗證方式嗎?您可以按「取消」保留多種驗證方式。"
antennas: "天線"
manageAntennas: "管理天線"
@@ -464,10 +467,11 @@ title: "標題"
text: "文字"
enable: "啟用"
next: "下一步"
-retype: "再次輸入"
+retype: "重新輸入"
noteOf: "{user}的貼文"
quoteAttached: "引用"
quoteQuestion: "是否要引用?"
+attachAsFileQuestion: "剪貼簿的文字較長。請問是否要改成附加檔案呢?"
noMessagesYet: "沒有訊息"
newMessageExists: "有新的訊息"
onlyOneFileCanBeAttached: "只能加入一個附件"
@@ -602,7 +606,7 @@ addItem: "新增項目"
rearrange: "排序方式"
relays: "中繼器"
addRelay: "新增中繼器"
-inboxUrl: "收件夾URL"
+inboxUrl: "收件夾 URL"
addedRelays: "已加入的中繼器"
serviceworkerInfo: "如要使用推播通知,需要啟用此選項並設定金鑰。"
deletedNote: "已刪除的貼文"
@@ -791,7 +795,7 @@ newVersionOfClientAvailable: "新版本的客戶端可用。"
usageAmount: "使用量"
capacity: "容量"
inUse: "已使用"
-editCode: "編輯代碼"
+editCode: "編輯程式碼"
apply: "套用"
receiveAnnouncementFromInstance: "接收來自伺服器的通知"
emailNotification: "郵件通知"
@@ -1062,7 +1066,7 @@ enableChartsForFederatedInstances: "生成遠端伺服器的圖表"
showClipButtonInNoteFooter: "新增摘錄按鈕至貼文"
reactionsDisplaySize: "反應的顯示尺寸"
limitWidthOfReaction: "限制反應的最大寬度,並縮小顯示尺寸。"
-noteIdOrUrl: "貼文ID或URL"
+noteIdOrUrl: "貼文 ID 或 URL"
video: "影片"
videos: "影片"
audio: "音效"
@@ -1077,7 +1081,7 @@ addMemo: "新增備註"
editMemo: "編輯備註"
reactionsList: "反應列表"
renotesList: "轉發貼文列表"
-notificationDisplay: "通知的顯示"
+notificationDisplay: "通知"
leftTop: "左上"
rightTop: "右上"
leftBottom: "左下"
@@ -1179,15 +1183,15 @@ repositoryUrlOrTarballRequired: "如果儲存庫不是公開的,則必須提
feedback: "意見回饋"
feedbackUrl: "意見回饋 URL"
impressum: "營運者資訊"
-impressumUrl: "營運者資訊網址"
+impressumUrl: "營運者資訊 URL"
impressumDescription: "在德國與部份地區必須要明確顯示營運者資訊。"
privacyPolicy: "隱私政策"
-privacyPolicyUrl: "隱私政策網址"
+privacyPolicyUrl: "隱私政策 URL"
tosAndPrivacyPolicy: "服務條款和隱私政策"
avatarDecorations: "頭像裝飾"
attach: "裝上"
detach: "取下"
-detachAll: "移除所有裝飾"
+detachAll: "全部移除"
angle: "角度"
flip: "翻轉"
showAvatarDecorations: "顯示頭像裝飾"
@@ -1205,7 +1209,7 @@ remainingN: "剩餘:{n}"
overwriteContentConfirm: "確定要覆蓋目前的內容嗎?"
seasonalScreenEffect: "隨季節變換畫面的呈現"
decorate: "設置頭像裝飾"
-addMfmFunction: "插入MFM功能語法"
+addMfmFunction: "插入 MFM 功能語法"
enableQuickAddMfmFunction: "顯示高級 MFM 選擇器"
bubbleGame: "氣泡遊戲"
sfx: "音效"
@@ -1225,16 +1229,25 @@ enableHorizontalSwipe: "滑動切換時間軸"
loading: "載入中"
surrender: "退出"
gameRetry: "再試一次"
-notUsePleaseLeaveBlank: "如不使用,請留空"
+notUsePleaseLeaveBlank: "如果不使用的話請留白"
useTotp: "使用一次性密碼"
useBackupCode: "使用備用驗證碼"
-launchApp: "啟動 App"
+launchApp: "啟動 APP"
useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊"
keepOriginalFilename: "保留原始檔名"
keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。"
noDescription: "沒有說明文字"
alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
inquiry: "聯絡我們"
+_delivery:
+ status: "傳送狀態"
+ stop: "已凍結"
+ resume: "繼續傳送"
+ _type:
+ none: "直播中"
+ manuallySuspended: "手動暫停中"
+ goneSuspended: "因為伺服器刪除所以暫停中"
+ autoSuspendedForNotResponding: "因為伺服器沒有回應所以暫停中"
_bubbleGame:
howToPlay: "玩法說明"
hold: "保留"
@@ -1243,7 +1256,7 @@ _bubbleGame:
scoreYen: "賺取的金額"
highScore: "最高分"
maxChain: "最大結合數"
- yen: "{yen} 日圓"
+ yen: "{yen}円"
estimatedQty: "{qty}個"
scoreSweets: "飯糰 {onigiriQtyWithUnit}"
_howToPlay:
@@ -1271,7 +1284,7 @@ _initialAccountSetting:
privacySetting: "隱私設定"
theseSettingsCanEditLater: "這裡的設定可以在之後變更。"
youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。"
- followUsers: "為了構築時間軸,試著追蹤您感興趣的使用者吧。"
+ followUsers: "為了構築時間軸,試著追隨您感興趣的使用者吧。"
pushNotificationDescription: "啟用推送通知,就可以在設備上接收{name}的通知。"
initialAccountSettingCompleted: "初始設定完成了!"
haveFun: "盡情享受{name}吧!"
@@ -1326,7 +1339,7 @@ _initialTutorial:
title: "隱藏內容(CW)"
description: "將顯示「註釋」中寫入的內容而不是本文。按一下「顯示內容」以顯示本文。"
_exampleNote:
- cw: "美食恐怖主義注意"
+ cw: "注意消夜文"
note: "我吃了一個巧克力甜甜圈🍩😋"
useCases: "伺服器的服務條款可能會規範特定的貼文需要使用隱藏內容,除此之外也會用在隱藏劇情洩漏與敏感內容的貼文。"
_howToMakeAttachmentsSensitive:
@@ -1351,7 +1364,7 @@ _serverRules:
_serverSettings:
iconUrl: "圖示的 URL"
appIconDescription: "指定顯示 {host} 為應用程式時的圖示。"
- appIconUsageExample: "例如:漸進式網路應用程式(PWA)、於手機桌面新增書籤"
+ appIconUsageExample: "例如:PWA 或是在手機桌面作為書籤等"
appIconStyleRecommendation: "因為可能會裁剪成圓形或圓角,所以建議用單色填滿邊框及背景。"
appIconResolutionMustBe: "解析度必須為 {resolution}。"
manifestJsonOverride: "覆寫 manifest.json"
@@ -1559,7 +1572,7 @@ _achievements:
_postedAt0min0sec:
title: "報時"
description: "在零分零秒發佈貼文"
- flavor: "啵、啵、啵、嗶ーー"
+ flavor: "啵.啵.啵.嗶ー"
_selfQuote:
title: "自我引用"
description: "引用了自己的貼文"
@@ -1694,8 +1707,8 @@ _role:
roleAssignedTo: "手動指派角色完成"
isLocal: "本地使用者"
isRemote: "遠端使用者"
- isCat: "使用者是貓"
- isBot: "使用者是機器人"
+ isCat: "貓使用者"
+ isBot: "機器人使用者"
isSuspended: "被停權的使用者"
isLocked: "上鎖的使用者"
isExplorable: "開啟了「使您的帳戶更容易被找到」功能的使用者"
@@ -1857,7 +1870,7 @@ _theme:
invalid: "佈景主題格式錯誤"
make: "製作佈景主題"
base: "基於"
- addConstant: "添加常數"
+ addConstant: "新增常數"
constant: "常數"
defaultValue: "預設值"
color: "顏色"
@@ -1932,22 +1945,22 @@ _soundSettings:
_ago:
future: "未來"
justNow: "剛剛"
- secondsAgo: "{n} 秒前"
- minutesAgo: "{n} 分鐘前 "
- hoursAgo: "{n} 小時前"
- daysAgo: "{n} 天前"
- weeksAgo: "{n} 週前"
- monthsAgo: "{n} 個月前"
- yearsAgo: "{n} 年前"
+ secondsAgo: "{n}秒前"
+ minutesAgo: "{n}分鐘前"
+ hoursAgo: "{n}小時前"
+ daysAgo: "{n}天前"
+ weeksAgo: "{n}周前"
+ monthsAgo: "{n}個月前"
+ yearsAgo: "{n}年前"
invalid: "無"
_timeIn:
- seconds: "{n} 秒後"
- minutes: "{n} 分後"
- hours: "{n} 小時後"
- days: "{n} 日後"
- weeks: "{n} 週後"
- months: "{n} 個月後"
- years: "{n} 年後"
+ seconds: "{n}秒後"
+ minutes: "{n}分鐘後"
+ hours: "{n}小時後"
+ days: "{n}天後"
+ weeks: "{n}周後"
+ months: "{n}個月後"
+ years: "{n}年後"
_time:
second: "秒"
minute: "分鐘"
@@ -2032,7 +2045,6 @@ _permissions:
"read:admin:server-info": "查看伺服器的資訊"
"read:admin:show-moderation-log": "查看審查紀錄"
"read:admin:show-user": "查看使用者的私密資訊"
- "read:admin:show-users": "查看使用者的私密資訊"
"write:admin:suspend-user": "凍結使用者"
"write:admin:unset-user-avatar": "刪除使用者的頭像"
"write:admin:unset-user-banner": "刪除使用者的橫幅"
@@ -2085,13 +2097,13 @@ _antennaSources:
userList: "來自特定清單中的貼文"
userBlacklist: "除指定使用者外的所有貼文"
_weekday:
- sunday: "週日"
- monday: "週一"
- tuesday: "週二"
- wednesday: "週三"
- thursday: "週四"
- friday: "週五"
- saturday: "週六"
+ sunday: "星期天"
+ monday: "星期一"
+ tuesday: "星期二"
+ wednesday: "星期三"
+ thursday: "星期四"
+ friday: "星期五"
+ saturday: "星期六"
_widgets:
profile: "個人檔案"
instanceInfo: "伺服器資訊"
@@ -2140,7 +2152,7 @@ _poll:
deadlineDate: "截止日期"
deadlineTime: "小時"
duration: "時長"
- votesCount: "{n} 票"
+ votesCount: "{n}票"
totalVotes: "合計 {n} 票"
vote: "投票"
showResult: "顯示結果"
@@ -2173,7 +2185,7 @@ _postForm:
e: "寫些什麼吧……"
f: "靜待發文……"
_profile:
- name: "名稱"
+ name: "名字"
username: "使用者名稱"
description: "關於我"
youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag"
@@ -2231,10 +2243,10 @@ _timelines:
_play:
new: "新增 Play"
edit: "編輯 Play"
- created: "已新增Play "
- updated: "已更新Play "
+ created: "已新增 Play "
+ updated: "已更新 Play "
deleted: "已刪除 Play"
- pageSetting: "Play設定"
+ pageSetting: "Play 設定"
editThisPage: "編輯此 Play"
viewSource: "檢視原始碼"
my: "自己的 Play"
@@ -2247,7 +2259,7 @@ _play:
_pages:
newPage: "建立頁面"
editPage: "編輯頁面"
- readPage: "正檢視原始碼"
+ readPage: "正在檢視原始碼"
created: "頁面已建立"
updated: "頁面已更新"
deleted: "頁面已被刪除"
@@ -2274,7 +2286,7 @@ _pages:
hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
font: "字型"
fontSerif: "襯線體"
- fontSansSerif: "無襯線體"
+ fontSansSerif: "黑體"
eyeCatchingImageSet: "設定封面影像"
eyeCatchingImageRemove: "刪除封面影像"
chooseBlock: "新增方塊"
@@ -2384,7 +2396,7 @@ _drivecleaner:
orderByCreatedAtAsc: "按新增日期降序排列"
_webhookSettings:
createWebhook: "建立 Webhook"
- name: "名稱"
+ name: "名字"
secret: "密鑰"
events: "何時運行 Webhook"
active: "已啟用"
From 4579be0f5401001bcfc27c4d56133cc910f3f581 Mon Sep 17 00:00:00 2001
From: anatawa12
Date: Mon, 27 May 2024 20:54:53 +0900
Subject: [PATCH 100/133] =?UTF-8?q?=E6=96=B0=E7=9D=80=E3=83=8E=E3=83=BC?=
=?UTF-8?q?=E3=83=88=E3=82=92=E3=82=B5=E3=82=A6=E3=83=B3=E3=83=89=E3=81=A7?=
=?UTF-8?q?=E9=80=9A=E7=9F=A5=E3=81=99=E3=82=8B=E6=A9=9F=E8=83=BD=E3=82=92?=
=?UTF-8?q?deck=20UI=E3=81=AB=E8=BF=BD=E5=8A=A0=20(#13867)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat(deck-ui): implement note notification
* chore: remove notify in antenna
* docs(changelog): 新着ノートをサウンドで通知する機能をdeck UIに追加
* fix: type error in test
* lint: key order
* fix: remove notify column
* test: remove test for notify
* chore: make sound selectable
* fix: add license header
* fix: add license header again
* Unnecessary await
Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
* ファイルを選択してください -> ファイルが選択されていません
* fix: i18n忘れ
* fix: i18n忘れ
* pleaseSelectFile > fileNotSelected
---------
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
---
CHANGELOG.md | 1 +
locales/index.d.ts | 8 ++
locales/ja-JP.yml | 2 +
.../1716450883149-RemoveAntennaNotify.js | 16 +++
.../src/core/entities/AntennaEntityService.ts | 1 -
packages/backend/src/models/Antenna.ts | 3 -
.../backend/src/models/json-schema/antenna.ts | 4 -
.../ExportAntennasProcessorService.ts | 1 -
.../ImportAntennasProcessorService.ts | 4 +-
.../server/api/endpoints/antennas/create.ts | 4 +-
.../server/api/endpoints/antennas/update.ts | 2 -
packages/backend/test/e2e/antennas.ts | 4 -
packages/backend/test/e2e/move.ts | 2 -
.../src/components/MkFormDialog.file.vue | 71 ++++++++++++
.../frontend/src/components/MkFormDialog.vue | 12 +-
packages/frontend/src/os.ts | 2 +-
.../frontend/src/pages/my-antennas/editor.vue | 3 -
packages/frontend/src/scripts/form.ts | 30 +++--
.../frontend/src/ui/deck/antenna-column.vue | 24 +++-
.../frontend/src/ui/deck/channel-column.vue | 23 +++-
packages/frontend/src/ui/deck/deck-store.ts | 2 +
packages/frontend/src/ui/deck/list-column.vue | 22 +++-
.../src/ui/deck/role-timeline-column.vue | 23 +++-
packages/frontend/src/ui/deck/tl-column.vue | 20 +++-
.../src/ui/deck/tl-note-notification.ts | 107 ++++++++++++++++++
packages/misskey-js/src/autogen/types.ts | 3 -
26 files changed, 341 insertions(+), 53 deletions(-)
create mode 100644 packages/backend/migration/1716450883149-RemoveAntennaNotify.js
create mode 100644 packages/frontend/src/components/MkFormDialog.file.vue
create mode 100644 packages/frontend/src/ui/deck/tl-note-notification.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8463f8cbf60..0a70fc7a8a0f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,6 +49,7 @@
- Enhance: AiScriptを0.18.0にバージョンアップ
- Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
- Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
+- Enhance: 新着ノートをサウンドで通知する機能をdeck UIに追加しました
- Enhance: コントロールパネルのクイックアクションからファイルを照会できるように
- Enhance: コントロールパネルのクイックアクションから通常の照会を行えるように
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index eb7e297aa325..d4ded0bb5b8e 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1280,6 +1280,10 @@ export interface Locale extends ILocale {
* フォルダーを選択
*/
"selectFolders": string;
+ /**
+ * ファイルが選択されていません
+ */
+ "fileNotSelected": string;
/**
* ファイル名を変更
*/
@@ -9143,6 +9147,10 @@ export interface Locale extends ILocale {
* カラムを追加
*/
"addColumn": string;
+ /**
+ * 新着ノート通知の設定
+ */
+ "newNoteNotificationSettings": string;
/**
* カラムの設定
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index ebaf16745c01..d7ceb971afed 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -316,6 +316,7 @@ selectFile: "ファイルを選択"
selectFiles: "ファイルを選択"
selectFolder: "フォルダーを選択"
selectFolders: "フォルダーを選択"
+fileNotSelected: "ファイルが選択されていません"
renameFile: "ファイル名を変更"
folderName: "フォルダー名"
createFolder: "フォルダーを作成"
@@ -2420,6 +2421,7 @@ _deck:
alwaysShowMainColumn: "常にメインカラムを表示"
columnAlign: "カラムの寄せ"
addColumn: "カラムを追加"
+ newNoteNotificationSettings: "新着ノート通知の設定"
configureColumn: "カラムの設定"
swapLeft: "左に移動"
swapRight: "右に移動"
diff --git a/packages/backend/migration/1716450883149-RemoveAntennaNotify.js b/packages/backend/migration/1716450883149-RemoveAntennaNotify.js
new file mode 100644
index 000000000000..b5a2441855d2
--- /dev/null
+++ b/packages/backend/migration/1716450883149-RemoveAntennaNotify.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class RemoveAntennaNotify1716450883149 {
+ name = 'RemoveAntennaNotify1716450883149'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "notify"`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "antenna" ADD "notify" boolean NOT NULL`);
+ }
+}
diff --git a/packages/backend/src/core/entities/AntennaEntityService.ts b/packages/backend/src/core/entities/AntennaEntityService.ts
index 3ec8efa6bfd0..4a17a3d80fba 100644
--- a/packages/backend/src/core/entities/AntennaEntityService.ts
+++ b/packages/backend/src/core/entities/AntennaEntityService.ts
@@ -38,7 +38,6 @@ export class AntennaEntityService {
users: antenna.users,
caseSensitive: antenna.caseSensitive,
localOnly: antenna.localOnly,
- notify: antenna.notify,
excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies,
withFile: antenna.withFile,
diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts
index f5e819059e03..33e6f4818952 100644
--- a/packages/backend/src/models/Antenna.ts
+++ b/packages/backend/src/models/Antenna.ts
@@ -90,9 +90,6 @@ export class MiAntenna {
})
public expression: string | null;
- @Column('boolean')
- public notify: boolean;
-
@Index()
@Column('boolean', {
default: true,
diff --git a/packages/backend/src/models/json-schema/antenna.ts b/packages/backend/src/models/json-schema/antenna.ts
index 78cf6d3ba27f..c4ac358fa60a 100644
--- a/packages/backend/src/models/json-schema/antenna.ts
+++ b/packages/backend/src/models/json-schema/antenna.ts
@@ -72,10 +72,6 @@ export const packedAntennaSchema = {
optional: false, nullable: false,
default: false,
},
- notify: {
- type: 'boolean',
- optional: false, nullable: false,
- },
excludeBots: {
type: 'boolean',
optional: false, nullable: false,
diff --git a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
index 1d8e90f367f0..88c4ea29c0e6 100644
--- a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
@@ -84,7 +84,6 @@ export class ExportAntennasProcessorService {
excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies,
withFile: antenna.withFile,
- notify: antenna.notify,
}));
if (antennas.length - 1 !== index) {
write(', ');
diff --git a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
index ff1c04de06c5..e5b7c5ac5213 100644
--- a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts
@@ -47,9 +47,8 @@ const validate = new Ajv().compile({
excludeBots: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
- notify: { type: 'boolean' },
},
- required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
+ required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
});
@Injectable()
@@ -92,7 +91,6 @@ export class ImportAntennasProcessorService {
excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies,
withFile: antenna.withFile,
- notify: antenna.notify,
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
this.logger.succ('Antenna created: ' + result.id);
this.globalEventService.publishInternalEvent('antennaCreated', result);
diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts
index 57c8eb495850..6b7bacb05499 100644
--- a/packages/backend/src/server/api/endpoints/antennas/create.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/create.ts
@@ -67,9 +67,8 @@ export const paramDef = {
excludeBots: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
- notify: { type: 'boolean' },
},
- required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
+ required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
} as const;
@Injectable()
@@ -128,7 +127,6 @@ export default class extends Endpoint { // eslint-
excludeBots: ps.excludeBots,
withReplies: ps.withReplies,
withFile: ps.withFile,
- notify: ps.notify,
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
this.globalEventService.publishInternalEvent('antennaCreated', antenna);
diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts
index e6720aacf82e..0c30bca9e0bf 100644
--- a/packages/backend/src/server/api/endpoints/antennas/update.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/update.ts
@@ -66,7 +66,6 @@ export const paramDef = {
excludeBots: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
- notify: { type: 'boolean' },
},
required: ['antennaId'],
} as const;
@@ -124,7 +123,6 @@ export default class extends Endpoint { // eslint-
excludeBots: ps.excludeBots,
withReplies: ps.withReplies,
withFile: ps.withFile,
- notify: ps.notify,
isActive: true,
lastUsedAt: new Date(),
});
diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index cf5c7dd130ea..4f78cc999d43 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -38,7 +38,6 @@ describe('アンテナ', () => {
excludeKeywords: [['']],
keywords: [['keyword']],
name: 'test',
- notify: false,
src: 'all' as const,
userListId: null,
users: [''],
@@ -151,7 +150,6 @@ describe('アンテナ', () => {
isActive: true,
keywords: [['keyword']],
name: 'test',
- notify: false,
src: 'all',
userListId: null,
users: [''],
@@ -219,8 +217,6 @@ describe('アンテナ', () => {
{ parameters: () => ({ withReplies: true }) },
{ parameters: () => ({ withFile: false }) },
{ parameters: () => ({ withFile: true }) },
- { parameters: () => ({ notify: false }) },
- { parameters: () => ({ notify: true }) },
];
test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
const response = await successfulApiCall({
diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts
index 4e5306da97da..35050130dc1b 100644
--- a/packages/backend/test/e2e/move.ts
+++ b/packages/backend/test/e2e/move.ts
@@ -191,7 +191,6 @@ describe('Account Move', () => {
localOnly: false,
withReplies: false,
withFile: false,
- notify: false,
}, alice);
antennaId = antenna.body.id;
@@ -435,7 +434,6 @@ describe('Account Move', () => {
localOnly: false,
withReplies: false,
withFile: false,
- notify: false,
}, alice);
assert.strictEqual(res.status, 403);
diff --git a/packages/frontend/src/components/MkFormDialog.file.vue b/packages/frontend/src/components/MkFormDialog.file.vue
new file mode 100644
index 000000000000..936059423657
--- /dev/null
+++ b/packages/frontend/src/components/MkFormDialog.file.vue
@@ -0,0 +1,71 @@
+
+
+
+
+
{{ i18n.ts.selectFile }}
+
{{ friendlyFileName }}
+
+
+
+
+
+
diff --git a/packages/frontend/src/components/MkFormDialog.vue b/packages/frontend/src/components/MkFormDialog.vue
index deedc5badb1b..124f114111c2 100644
--- a/packages/frontend/src/components/MkFormDialog.vue
+++ b/packages/frontend/src/components/MkFormDialog.vue
@@ -21,8 +21,9 @@ SPDX-License-Identifier: AGPL-3.0-only
-
-
+
+
+
({{ i18n.ts.optional }})
{{ v.description }}
@@ -53,6 +54,12 @@ SPDX-License-Identifier: AGPL-3.0-only
+ values[k] = f"
+ />
@@ -72,6 +79,7 @@ import MkSelect from './MkSelect.vue';
import MkRange from './MkRange.vue';
import MkButton from './MkButton.vue';
import MkRadios from './MkRadios.vue';
+import XFile from './MkFormDialog.file.vue';
import type { Form } from '@/scripts/form.js';
import MkModalWindow from '@/components/MkModalWindow.vue';
import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index c561e84a23b5..f656a5237165 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -518,7 +518,7 @@ export function waiting(): Promise {
});
}
-export function form(title: string, f: F): Promise<{ canceled: true } | { result: GetFormResultType }> {
+export function form(title: string, f: F): Promise<{ canceled: true, result?: undefined } | { canceled?: false, result: GetFormResultType }> {
return new Promise(resolve => {
popup(defineAsyncComponent(() => import('@/components/MkFormDialog.vue')), { title, form: f }, {
done: result => {
diff --git a/packages/frontend/src/pages/my-antennas/editor.vue b/packages/frontend/src/pages/my-antennas/editor.vue
index 97edbc44cefa..2949bfc02cec 100644
--- a/packages/frontend/src/pages/my-antennas/editor.vue
+++ b/packages/frontend/src/pages/my-antennas/editor.vue
@@ -39,7 +39,6 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.localOnly }}
{{ i18n.ts.caseSensitive }}
{{ i18n.ts.withFileAntenna }}
- {{ i18n.ts.notifyAntenna }}
{{ i18n.ts.save }}
@@ -82,7 +81,6 @@ const localOnly = ref(props.antenna.localOnly);
const excludeBots = ref(props.antenna.excludeBots);
const withReplies = ref(props.antenna.withReplies);
const withFile = ref(props.antenna.withFile);
-const notify = ref(props.antenna.notify);
const userLists = ref(null);
watch(() => src.value, async () => {
@@ -99,7 +97,6 @@ async function saveAntenna() {
excludeBots: excludeBots.value,
withReplies: withReplies.value,
withFile: withFile.value,
- notify: notify.value,
caseSensitive: caseSensitive.value,
localOnly: localOnly.value,
users: users.value.trim().split('\n').map(x => x.trim()),
diff --git a/packages/frontend/src/scripts/form.ts b/packages/frontend/src/scripts/form.ts
index b0db404f2818..242a504c3b5f 100644
--- a/packages/frontend/src/scripts/form.ts
+++ b/packages/frontend/src/scripts/form.ts
@@ -3,18 +3,22 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import * as Misskey from 'misskey-js';
+
type EnumItem = string | {
label: string;
value: string;
};
+type Hidden = boolean | ((v: any) => boolean);
+
export type FormItem = {
label?: string;
type: 'string';
default: string | null;
description?: string;
required?: boolean;
- hidden?: boolean;
+ hidden?: Hidden;
multiline?: boolean;
treatAsMfm?: boolean;
} | {
@@ -23,27 +27,27 @@ export type FormItem = {
default: number | null;
description?: string;
required?: boolean;
- hidden?: boolean;
+ hidden?: Hidden;
step?: number;
} | {
label?: string;
type: 'boolean';
default: boolean | null;
description?: string;
- hidden?: boolean;
+ hidden?: Hidden;
} | {
label?: string;
type: 'enum';
default: string | null;
required?: boolean;
- hidden?: boolean;
+ hidden?: Hidden;
enum: EnumItem[];
} | {
label?: string;
type: 'radio';
default: unknown | null;
required?: boolean;
- hidden?: boolean;
+ hidden?: Hidden;
options: {
label: string;
value: unknown;
@@ -58,20 +62,27 @@ export type FormItem = {
min: number;
max: number;
textConverter?: (value: number) => string;
+ hidden?: Hidden;
} | {
label?: string;
type: 'object';
default: Record | null;
- hidden: boolean;
+ hidden: Hidden;
} | {
label?: string;
type: 'array';
default: unknown[] | null;
- hidden: boolean;
+ hidden: Hidden;
} | {
type: 'button';
content?: string;
+ hidden?: Hidden;
action: (ev: MouseEvent, v: any) => void;
+} | {
+ type: 'drive-file';
+ defaultFileId?: string | null;
+ hidden?: Hidden;
+ validate?: (v: Misskey.entities.DriveFile) => Promise;
};
export type Form = Record;
@@ -84,8 +95,9 @@ type GetItemType- =
Item['type'] extends 'range' ? number :
Item['type'] extends 'enum' ? string :
Item['type'] extends 'array' ? unknown[] :
- Item['type'] extends 'object' ? Record
- : never;
+ Item['type'] extends 'object' ? Record :
+ Item['type'] extends 'drive-file' ? Misskey.entities.DriveFile | undefined :
+ never;
export type GetFormResultType = {
[P in keyof F]: GetItemType;
diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue
index b42a21bf6fde..c3dc1e4fcec3 100644
--- a/packages/frontend/src/ui/deck/antenna-column.vue
+++ b/packages/frontend/src/ui/deck/antenna-column.vue
@@ -9,18 +9,22 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ column.name }}
-
+
diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts
index 70b55e8172a4..bb3c04cd5c8f 100644
--- a/packages/frontend/src/ui/deck/deck-store.ts
+++ b/packages/frontend/src/ui/deck/deck-store.ts
@@ -9,6 +9,7 @@ import { notificationTypes } from 'misskey-js';
import { Storage } from '@/pizzax.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { deepClone } from '@/scripts/clone.js';
+import { SoundStore } from '@/store.js';
type ColumnWidget = {
name: string;
@@ -33,6 +34,7 @@ export type Column = {
withRenotes?: boolean;
withReplies?: boolean;
onlyFiles?: boolean;
+ soundSetting: SoundStore;
};
export const deckStore = markRaw(new Storage('deck', {
diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue
index 70ea54326f34..5369112494c6 100644
--- a/packages/frontend/src/ui/deck/list-column.vue
+++ b/packages/frontend/src/ui/deck/list-column.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ column.name }}
-
+
@@ -21,6 +21,10 @@ import MkTimeline from '@/components/MkTimeline.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
+import { MenuItem } from '@/types/menu.js';
+import { SoundStore } from '@/store.js';
+import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
+import * as sound from '@/scripts/sound.js';
const props = defineProps<{
column: Column;
@@ -29,6 +33,7 @@ const props = defineProps<{
const timeline = shallowRef>();
const withRenotes = ref(props.column.withRenotes ?? true);
+const soundSetting = ref(props.column.soundSetting ?? { type: null, volume: 1 });
if (props.column.listId == null) {
setList();
@@ -40,6 +45,10 @@ watch(withRenotes, v => {
});
});
+watch(soundSetting, v => {
+ updateColumn(props.column.id, { soundSetting: v });
+});
+
async function setList() {
const lists = await misskeyApi('users/lists/list');
const { canceled, result: list } = await os.select({
@@ -59,7 +68,11 @@ function editList() {
os.pageWindow('my/lists/' + props.column.listId);
}
-const menu = [
+function onNote() {
+ sound.playMisskeySfxFile(soundSetting.value);
+}
+
+const menu: MenuItem[] = [
{
icon: 'ti ti-pencil',
text: i18n.ts.selectList,
@@ -75,5 +88,10 @@ const menu = [
text: i18n.ts.showRenotes,
ref: withRenotes,
},
+ {
+ icon: 'ti ti-bell',
+ text: i18n.ts._deck.newNoteNotificationSettings,
+ action: () => soundSettingsButton(soundSetting),
+ },
];
diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue
index eae2ee13f344..32ab7527b471 100644
--- a/packages/frontend/src/ui/deck/role-timeline-column.vue
+++ b/packages/frontend/src/ui/deck/role-timeline-column.vue
@@ -9,18 +9,22 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ column.name }}
-
+