Skip to content

Commit 76054ab

Browse files
authored
release: v2025.5.0-kakurega.1.42.0 (#179)
2 parents 81644f7 + dd7b57b commit 76054ab

File tree

14 files changed

+115
-42
lines changed

14 files changed

+115
-42
lines changed

locales/index.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5849,6 +5849,14 @@ export interface Locale extends ILocale {
58495849
* 「ファイル付きのみ」が有効になっています
58505850
*/
58515851
"onlyFilesIsEnabled": string;
5852+
/**
5853+
* 招待コードをコピー
5854+
*/
5855+
"copyInviteCode": string;
5856+
/**
5857+
* 招待URLをコピー
5858+
*/
5859+
"copyInviteUrl": string;
58525860
"_chat": {
58535861
/**
58545862
* まだメッセージはありません

locales/ja-JP.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,8 @@ federationJobs: "連合ジョブ"
14571457
driveAboutTip: "ドライブでは、過去にアップロードしたファイルの一覧が表示されます。<br>\nノートに添付する際に再利用したり、あとで投稿するファイルを予めアップロードしておくこともできます。<br>\n<b>ファイルを削除すると、今までそのファイルを使用した全ての場所(ノート、ページ、アバター、バナー等)からも見えなくなるので注意してください。</b><br>\nフォルダを作って整理することもできます。"
14581458
scrollToClose: "スクロールして閉じる"
14591459
onlyFilesIsEnabled: "「ファイル付きのみ」が有効になっています"
1460+
copyInviteCode: "招待コードをコピー"
1461+
copyInviteUrl: "招待URLをコピー"
14601462

14611463
_chat:
14621464
noMessagesYet: "まだメッセージはありません"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "misskey",
3-
"version": "2025.5.0-kakurega.1.41.0",
3+
"version": "2025.5.0-kakurega.1.42.0",
44
"codename": "nasubi",
55
"repository": {
66
"type": "git",

packages/frontend/src/boot/main-boot.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,5 +413,16 @@ export async function mainBoot() {
413413
} as const satisfies Keymap;
414414
window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
415415

416+
// もしURLのクエリにinvite-codeを持っていたらsignupダイアログを開く
417+
const params = new URLSearchParams(window.location.search);
418+
if (params.has('invite-code') && (instance.disableRegistration || instance.enableRegistrationLimit)) {
419+
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {
420+
autoSet: true,
421+
skipChoose: true,
422+
}, {
423+
closed: () => dispose(),
424+
});
425+
}
426+
416427
initializeSw();
417428
}

packages/frontend/src/components/MkInviteCode.vue

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ SPDX-License-Identifier: AGPL-3.0-only
1111
<span v-else-if="isExpired" style="color: var(--MI_THEME-error)">{{ i18n.ts.expired }}</span>
1212
<span v-else style="color: var(--MI_THEME-success)">{{ i18n.ts.unused }}</span>
1313
</template>
14-
<template #footer>
14+
<template v-if="!invite.used || moderator" #footer>
1515
<div class="_buttons">
16-
<MkButton v-if="!invite.used && !isExpired" primary rounded @click="copyInviteCode()"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
17-
<MkButton v-if="!invite.used || moderator" danger rounded @click="deleteCode()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
16+
<template v-if="!isExpired && !invite.used">
17+
<MkButton primary rounded @click="copyInviteUrl(invite.code)"><i class="ti ti-link"></i> {{ i18n.ts.copyInviteUrl }}</MkButton>
18+
<MkButton primary rounded @click="copyInviteCode(invite.code)"><i class="ti ti-copy"></i> {{ i18n.ts.copyInviteCode }}</MkButton>
19+
</template>
20+
<MkButton danger rounded @click="deleteCode()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
1821
</div>
1922
</template>
2023

@@ -64,7 +67,7 @@ import { computed } from 'vue';
6467
import * as Misskey from 'misskey-js';
6568
import MkFolder from '@/components/MkFolder.vue';
6669
import MkButton from '@/components/MkButton.vue';
67-
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
70+
import { copyInviteCode, copyInviteUrl } from '@/utility/invite.js';
6871
import { i18n } from '@/i18n.js';
6972
import * as os from '@/os.js';
7073
@@ -87,10 +90,6 @@ function deleteCode() {
8790
});
8891
emits('deleted', props.invite.id);
8992
}
90-
91-
function copyInviteCode() {
92-
copyToClipboard(props.invite.code);
93-
}
9493
</script>
9594

9695
<style lang="scss" module>

packages/frontend/src/components/MkSignupDialog.choice.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ async function doneWithoutCode() {
7373
.choiceButton {
7474
height: 60px;
7575
width: 100% !important;
76+
border-radius: 16px;
7677
}
7778
7879
.banner {

packages/frontend/src/components/MkSignupDialog.form.vue

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ SPDX-License-Identifier: AGPL-3.0-only
171171
</template>
172172

173173
<script lang="ts" setup>
174-
import { ref, computed } from 'vue';
174+
import { ref, computed, onMounted } from 'vue';
175175
import { toUnicode } from 'punycode.js';
176176
import * as Misskey from 'misskey-js';
177177
import * as config from '@@/js/config.js';
@@ -374,21 +374,29 @@ async function onSubmit(): Promise<void> {
374374
});
375375
376376
if (res && res.ok) {
377+
const redirect = new URL(window.location.href);
378+
const hasInviteCode = redirect.searchParams.has('invite-code');
379+
redirect.searchParams.delete('invite-code');
380+
377381
if (res.status === 204 || instance.emailRequiredForSignup) {
378-
os.alert({
382+
await os.alert({
379383
type: 'success',
380384
title: i18n.ts._signup.almostThere,
381385
text: i18n.tsx._signup.emailSent({ email: email.value }),
382386
});
383387
emit('signupEmailPending');
388+
389+
if (hasInviteCode) {
390+
window.location.href = redirect.toString();
391+
}
384392
} else {
385393
const resJson = (await res.json()) as Misskey.entities.SignupResponse;
386394
if (_DEV_) console.log(resJson);
387395
388396
emit('signup', resJson);
389397
390398
if (props.autoSet) {
391-
await login(resJson.token);
399+
await login(resJson.token, redirect.toString());
392400
}
393401
}
394402
} else {
@@ -411,6 +419,13 @@ function onSignupApiError() {
411419
text: i18n.ts.somethingHappened,
412420
});
413421
}
422+
423+
onMounted(() => {
424+
const params = new URLSearchParams(window.location.search);
425+
if (params.has('invite-code') && useInviteCode) {
426+
invitationCode.value = params.get('invite-code') ?? '';
427+
}
428+
});
414429
</script>
415430

416431
<style lang="scss" module>

packages/frontend/src/components/MkSignupDialog.rules.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ SPDX-License-Identifier: AGPL-3.0-only
1010
</div>
1111
<div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;">
1212
<div class="_gaps_m">
13-
<div v-if="instance.disableRegistration || instance.federation !== 'all'" class="_gaps_s">
13+
<div v-if="instance.disableRegistration || instance.enableRegistrationLimit || instance.federation !== 'all'" class="_gaps_s">
14+
<MkInfo v-if="!instance.disableRegistration && instance.enableRegistrationLimit" warn>{{ i18n.ts.registrationLimitEnabled }}</MkInfo>
1415
<MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
1516
<MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo>
1617
<MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo>
1718
</div>
18-
<div v-if="instance.enableRegistrationLimit" :class="$style.mainWarn">
19-
<MkInfo warn>{{ i18n.ts.registrationLimitEnabled }}</MkInfo>
20-
</div>
2119

2220
<div style="text-align: center;">
2321
<div>{{ i18n.ts.pleaseConfirmBelowBeforeSignup }}</div>

packages/frontend/src/components/MkSignupDialog.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
2424
<template v-if="!isAcceptedServerRule">
2525
<XServerRules @done="isAcceptedServerRule = true" @cancel="onClose"/>
2626
</template>
27-
<template v-else-if="!isChoosed && instance.enableRegistrationLimit">
27+
<template v-else-if="!skipChoose && !isChoosed && !instance.disableRegistration && instance.enableRegistrationLimit">
2828
<XChoice @done="doneChoice" @cancel="dialog?.close()"/>
2929
</template>
3030
<template v-else>
@@ -47,8 +47,10 @@ import { i18n } from '@/i18n.js';
4747
4848
const props = withDefaults(defineProps<{
4949
autoSet?: boolean;
50+
skipChoose?: boolean;
5051
}>(), {
5152
autoSet: false,
53+
skipChoose: false,
5254
});
5355
5456
const emit = defineEmits<{
@@ -61,7 +63,7 @@ const dialog = useTemplateRef('dialog');
6163
6264
const isAcceptedServerRule = ref(false);
6365
const isChoosed = ref(false);
64-
const withoutInviteCode = ref(true);
66+
const withoutInviteCode = ref(false);
6567
6668
function doneChoice(hasInviteCode: boolean) {
6769
isChoosed.value = true;

packages/frontend/src/components/MkUpdated.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function closePanel() {
4242
}
4343
4444
function whatIsNew() {
45-
window.open(`https://misskey-hub.net/ja/docs/releases/#_${misskeyVersion.replaceAll('.', '-')}`, '_blank');
45+
window.open(`https://misskey-hub.net/docs/releases/#_${misskeyVersion.replaceAll('.', '')}`, '_blank');
4646
}
4747
4848
function whatIsNewKakurega() {

packages/frontend/src/components/MkVisitorDashboard.vue

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ SPDX-License-Identifier: AGPL-3.0-only
1818
<!-- eslint-disable-next-line vue/no-v-html -->
1919
<div v-html="instance.description || i18n.ts.headlineMisskey"></div>
2020
</div>
21-
<div v-if="instance.disableRegistration || instance.federation !== 'all'" :class="$style.mainWarn" class="_gaps_s">
21+
<div v-if="instance.disableRegistration || instance.enableRegistrationLimit || instance.federation !== 'all'" :class="$style.mainWarn" class="_gaps_s">
22+
<MkInfo v-if="!instance.disableRegistration && instance.enableRegistrationLimit" info>{{ i18n.tsx.registrationLimitDetails({ limit: instance.registrationLimitCooldown, count: instance.registrationLimit }) }}</MkInfo>
2223
<MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
2324
<MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo>
2425
<MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo>
2526
</div>
26-
<div v-if="instance.enableRegistrationLimit" :class="$style.mainWarn">
27-
<MkInfo info>{{ i18n.tsx.registrationLimitDetails({ limit: instance.registrationLimitCooldown, count: instance.registrationLimit }) }}</MkInfo>
28-
</div>
2927
<div class="_gaps_s" :class="$style.mainActions">
3028
<MkButton :class="$style.mainAction" full rounded gradate data-cy-signup style="margin-right: 12px;" @click="signup()">{{ i18n.ts.joinThisServer }}</MkButton>
3129
<MkButton :class="$style.mainAction" full rounded link to="https://misskey-hub.net/servers/">{{ i18n.ts.exploreOtherServers }}</MkButton>
@@ -58,20 +56,20 @@ SPDX-License-Identifier: AGPL-3.0-only
5856
<script lang="ts" setup>
5957
import { ref } from 'vue';
6058
import * as Misskey from 'misskey-js';
59+
import { instanceName } from '@@/js/config.js';
60+
import type { MenuItem } from '@/types/menu.js';
6161
import XSigninDialog from '@/components/MkSigninDialog.vue';
6262
import XSignupDialog from '@/components/MkSignupDialog.vue';
6363
import MkButton from '@/components/MkButton.vue';
6464
import MkTimeline from '@/components/MkTimeline.vue';
6565
import MkInfo from '@/components/MkInfo.vue';
66-
import { instanceName } from '@@/js/config.js';
6766
import * as os from '@/os.js';
6867
import { misskeyApi } from '@/utility/misskey-api.js';
6968
import { i18n } from '@/i18n.js';
7069
import { instance } from '@/instance.js';
7170
import MkNumber from '@/components/MkNumber.vue';
7271
import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
7372
import { openInstanceMenu } from '@/ui/_common_/common.js';
74-
import type { MenuItem } from '@/types/menu.js';
7573
7674
const stats = ref<Misskey.entities.StatsResponse | null>(null);
7775

packages/frontend/src/pages/admin/moderation.vue

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,26 @@ SPDX-License-Identifier: AGPL-3.0-only
3232
<template #caption>{{ i18n.ts.blockMentionsFromUnfamiliarRemoteUsersDescription }} Cherry-picked from Misskey.io (https://github.com/MisskeyIO/misskey/commit/82cc3987c13db4ad0da1589386027c222ce85ff8)</template>
3333
</MkSwitch>
3434

35-
<MkSwitch v-model="enableRegistrationLimit" :disabled="!enableRegistration" @change="onChange_enableRegistrationLimit">
36-
<template #label>{{ i18n.ts.enableRegistrationLimit }}<span class="_beta">{{ i18n.ts.originalFeature }}</span></template>
37-
<template #caption>{{ i18n.ts.enableRegistrationLimitDescription }}</template>
38-
</MkSwitch>
39-
40-
<MkInput v-model="registrationLimitCooldown" type="number" :min="1" :disabled="!enableRegistration || !enableRegistrationLimit">
41-
<template #label>{{ i18n.ts.registrationLimitCooldown }}</template>
42-
<template #suffix>{{ i18n.ts._time.hour }}</template>
43-
<template #caption>{{ i18n.ts.registrationLimitCooldownDescription }}</template>
44-
</MkInput>
45-
46-
<MkInput v-model="registrationLimit" type="number" :min="0" :disabled="!enableRegistration || !enableRegistrationLimit">
47-
<template #label>{{ i18n.ts.registrationLimit }}</template>
48-
<template #caption>{{ i18n.ts.registrationLimitDescription }}</template>
49-
</MkInput>
50-
<MkButton primary :disabled="!enableRegistration || !enableRegistrationLimit" @click="save_registrationLimitSettings">{{ i18n.ts.save }}</MkButton>
35+
<MkDisableSection :disabled="!enableRegistration">
36+
<div class="_gaps_m">
37+
<MkSwitch v-model="enableRegistrationLimit" @change="onChange_enableRegistrationLimit">
38+
<template #label>{{ i18n.ts.enableRegistrationLimit }}<span class="_beta">{{ i18n.ts.originalFeature }}</span></template>
39+
<template #caption>{{ i18n.ts.enableRegistrationLimitDescription }}</template>
40+
</MkSwitch>
41+
42+
<MkInput v-model="registrationLimitCooldown" type="number" :min="1" :disabled="!enableRegistrationLimit">
43+
<template #label>{{ i18n.ts.registrationLimitCooldown }}</template>
44+
<template #suffix>{{ i18n.ts._time.hour }}</template>
45+
<template #caption>{{ i18n.ts.registrationLimitCooldownDescription }}</template>
46+
</MkInput>
47+
48+
<MkInput v-model="registrationLimit" type="number" :min="0" :disabled="!enableRegistrationLimit">
49+
<template #label>{{ i18n.ts.registrationLimit }}</template>
50+
<template #caption>{{ i18n.ts.registrationLimitDescription }}</template>
51+
</MkInput>
52+
<MkButton primary :disabled="!enableRegistrationLimit" @click="save_registrationLimitSettings">{{ i18n.ts.save }}</MkButton>
53+
</div>
54+
</MkDisableSection>
5155

5256
<MkSwitch v-model="disableExploreLocalUsers" @change="onChange_disableExploreLocalUsers">
5357
<template #label>{{ i18n.ts.disableExploreLocalUsers }}<span class="_beta">{{ i18n.ts.originalFeature }}</span></template>
@@ -179,6 +183,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
179183
import MkInput from '@/components/MkInput.vue';
180184
import MkTextarea from '@/components/MkTextarea.vue';
181185
import FormSuspense from '@/components/form/suspense.vue';
186+
import MkDisableSection from '@/components/MkDisableSection.vue';
182187
import * as os from '@/os.js';
183188
import { misskeyApi } from '@/utility/misskey-api.js';
184189
import { fetchInstance } from '@/instance.js';

packages/frontend/src/pages/invite.vue

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import type { Paging } from '@/components/MkPagination.vue';
3333
import { i18n } from '@/i18n.js';
3434
import * as os from '@/os.js';
3535
import { misskeyApi } from '@/utility/misskey-api.js';
36+
import { copyInviteCode, copyInviteUrl } from '@/utility/invite.js';
3637
import MkButton from '@/components/MkButton.vue';
3738
import MkPagination from '@/components/MkPagination.vue';
3839
import MkInviteCode from '@/components/MkInviteCode.vue';
@@ -62,12 +63,33 @@ const resetCycle = computed<null | string>(() => {
6263
6364
async function create() {
6465
const ticket = await misskeyApi('invite/create');
65-
os.alert({
66+
const { result } = await os.actions({
6667
type: 'success',
6768
title: i18n.ts.inviteCodeCreated,
6869
text: ticket.code,
70+
actions: [{
71+
value: 'copyUrl',
72+
text: i18n.ts.copyInviteUrl,
73+
primary: true,
74+
}, {
75+
value: 'copyCode',
76+
text: i18n.ts.copyInviteCode,
77+
primary: true,
78+
}, {
79+
value: 'close',
80+
text: i18n.ts.close,
81+
}],
6982
});
7083
84+
switch (result) {
85+
case 'copyUrl':
86+
copyInviteUrl(ticket.code);
87+
break;
88+
case 'copyCode':
89+
copyInviteCode(ticket.code);
90+
break;
91+
}
92+
7193
pagingComponent.value?.prepend(ticket);
7294
update();
7395
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
2+
import { instance } from '@/instance.js';
3+
4+
export function copyInviteCode(code: string) {
5+
copyToClipboard(code);
6+
}
7+
8+
export function copyInviteUrl(code: string) {
9+
const url = new URL(instance.uri);
10+
url.searchParams.set('invite-code', code);
11+
copyToClipboard(url.toString());
12+
}

0 commit comments

Comments
 (0)