summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortamaina <tamaina@hotmail.co.jp>2022-07-04 15:26:21 +0000
committertamaina <tamaina@hotmail.co.jp>2022-07-04 15:26:21 +0000
commit2fe4a51d26bd2b5429528b8773ace408b44b4092 (patch)
tree91cbe02f75ccf2b82bdda4bca90c84aba9e5d195
parentupdate CHANGELOG.md (diff)
parentAdd additional drive capacity change support (#8867) (diff)
downloadmisskey-2fe4a51d26bd2b5429528b8773ace408b44b4092.tar.gz
misskey-2fe4a51d26bd2b5429528b8773ace408b44b4092.tar.bz2
misskey-2fe4a51d26bd2b5429528b8773ace408b44b4092.zip
Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop
-rw-r--r--locales/ja-JP.yml3
-rw-r--r--packages/backend/migration/1655813815729-driveCapacityOverrideMb.js13
-rw-r--r--packages/backend/src/models/entities/user.ts6
-rw-r--r--packages/backend/src/models/repositories/user.ts1
-rw-r--r--packages/backend/src/server/api/endpoints.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts47
-rw-r--r--packages/backend/src/server/api/endpoints/drive.ts2
-rw-r--r--packages/backend/src/services/drive/add-file.ts11
-rw-r--r--packages/client/src/components/code-core.vue2
-rw-r--r--packages/client/src/components/form-dialog.vue2
-rw-r--r--packages/client/src/components/global/router-view.vue3
-rw-r--r--packages/client/src/components/tag-cloud.vue2
-rw-r--r--packages/client/src/pages/admin/_header_.vue1
-rw-r--r--packages/client/src/pages/admin/bot-protection.vue11
-rw-r--r--packages/client/src/pages/admin/overview.user.vue2
-rw-r--r--packages/client/src/pages/gallery/post.vue4
-rw-r--r--packages/client/src/pages/my-antennas/editor.vue1
-rw-r--r--packages/client/src/pages/my-lists/list.vue1
-rw-r--r--packages/client/src/pages/theme-editor.vue3
-rw-r--r--packages/client/src/pages/user-info.vue38
-rw-r--r--packages/client/src/plugin.ts2
-rw-r--r--packages/client/src/scripts/array.ts2
-rw-r--r--packages/client/src/scripts/autocomplete.ts2
-rw-r--r--packages/client/src/scripts/hotkey.ts8
-rw-r--r--packages/client/src/scripts/url.ts2
-rw-r--r--packages/client/src/ui/classic.vue4
-rw-r--r--packages/client/src/ui/deck/main-column.vue2
-rw-r--r--packages/client/src/widgets/widget.ts5
28 files changed, 144 insertions, 38 deletions
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9684489927..ce25095d5a 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -203,6 +203,7 @@ done: "完了"
processing: "処理中"
preview: "プレビュー"
default: "デフォルト"
+defaultValueIs: "デフォルト: {value}"
noCustomEmojis: "絵文字はありません"
noJobs: "ジョブはありません"
federating: "連合中"
@@ -855,6 +856,8 @@ noEmailServerWarning: "メールサーバーの設定がされていません。
thereIsUnresolvedAbuseReportWarning: "未対応の通報があります。"
recommended: "推奨"
check: "チェック"
+driveCapOverrideLabel: "このユーザーのドライブ容量上限を変更"
+driveCapOverrideCaption: "0以下を指定すると解除されます。"
requireAdminForView: "閲覧するには管理者アカウントでログインしている必要があります。"
isSystemAccount: "システムにより自動で作成・管理されているアカウントです。"
typeToConfirm: "この操作を行うには {x} と入力してください"
diff --git a/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js b/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js
new file mode 100644
index 0000000000..f257cd112f
--- /dev/null
+++ b/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js
@@ -0,0 +1,13 @@
+export class driveCapacityOverrideMb1655813815729 {
+ name = 'driveCapacityOverrideMb1655813815729'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "user" ADD "driveCapacityOverrideMb" integer`);
+ await queryRunner.query(`COMMENT ON COLUMN "user"."driveCapacityOverrideMb" IS 'Overrides user drive capacity limit'`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`COMMENT ON COLUMN "user"."driveCapacityOverrideMb" IS 'Overrides user drive capacity limit'`);
+ await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "driveCapacityOverrideMb"`);
+ }
+}
diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts
index df92fb8259..bc9446be41 100644
--- a/packages/backend/src/models/entities/user.ts
+++ b/packages/backend/src/models/entities/user.ts
@@ -218,6 +218,12 @@ export class User {
})
public token: string | null;
+ @Column('integer', {
+ nullable: true,
+ comment: 'Overrides user drive capacity limit',
+ })
+ public driveCapacityOverrideMb: number | null;
+
constructor(data: Partial<User>) {
if (data == null) return;
diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts
index 8a4e48efdd..645091395a 100644
--- a/packages/backend/src/models/repositories/user.ts
+++ b/packages/backend/src/models/repositories/user.ts
@@ -315,6 +315,7 @@ export const UserRepository = db.getRepository(User).extend({
} : undefined) : undefined,
emojis: populateEmojis(user.emojis, user.host),
onlineStatus: this.getOnlineStatus(user),
+ driveCapacityOverrideMb: user.driveCapacityOverrideMb,
...(opts.detail ? {
url: profile!.url,
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index 4a2ecebd86..4644f34d94 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -314,6 +314,7 @@ import * as ep___users_search from './endpoints/users/search.js';
import * as ep___users_show from './endpoints/users/show.js';
import * as ep___users_stats from './endpoints/users/stats.js';
import * as ep___fetchRss from './endpoints/fetch-rss.js';
+import * as ep___admin_driveCapOverride from './endpoints/admin/drive-capacity-override.js';
const eps = [
['admin/meta', ep___admin_meta],
@@ -629,6 +630,7 @@ const eps = [
['users/search', ep___users_search],
['users/show', ep___users_show],
['users/stats', ep___users_stats],
+ ['admin/drive-capacity-override', ep___admin_driveCapOverride],
['fetch-rss', ep___fetchRss],
];
diff --git a/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts b/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts
new file mode 100644
index 0000000000..a4b29770e1
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts
@@ -0,0 +1,47 @@
+import define from '../../define.js';
+import { Users } from '@/models/index.js';
+import { User } from '@/models/entities/user.js';
+import { insertModerationLog } from '@/services/insert-moderation-log.js';
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ userId: { type: 'string', format: 'misskey:id' },
+ overrideMb: { type: 'number', nullable: true },
+ },
+ required: ['userId', 'overrideMb'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+export default define(meta, paramDef, async (ps, me) => {
+ const user = await Users.findOneBy({ id: ps.userId });
+
+ if (user == null) {
+ throw new Error('user not found');
+ }
+
+ if (!Users.isLocalUser(user)) {
+ throw new Error('user is not local user');
+ }
+
+ /*if (user.isAdmin) {
+ throw new Error('cannot suspend admin');
+ }
+ if (user.isModerator) {
+ throw new Error('cannot suspend moderator');
+ }*/
+
+ await Users.update(user.id, {
+ driveCapacityOverrideMb: ps.overrideMb,
+ });
+
+ insertModerationLog(me, 'change-drive-capacity-override', {
+ targetId: user.id,
+ });
+});
diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts
index 47e940cddd..82497adefa 100644
--- a/packages/backend/src/server/api/endpoints/drive.ts
+++ b/packages/backend/src/server/api/endpoints/drive.ts
@@ -39,7 +39,7 @@ export default define(meta, paramDef, async (ps, user) => {
const usage = await DriveFiles.calcDriveUsageOf(user.id);
return {
- capacity: 1024 * 1024 * instance.localDriveCapacityMb,
+ capacity: 1024 * 1024 * (user.driveCapacityOverrideMb || instance.localDriveCapacityMb),
usage: usage,
};
});
diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts
index a25413187b..0dfad11cfb 100644
--- a/packages/backend/src/services/drive/add-file.ts
+++ b/packages/backend/src/services/drive/add-file.ts
@@ -307,7 +307,7 @@ async function deleteOldFile(user: IRemoteUser) {
type AddFileArgs = {
/** User who wish to add file */
- user: { id: User['id']; host: User['host'] } | null;
+ user: { id: User['id']; host: User['host']; driveCapacityOverrideMb: User['driveCapacityOverrideMb'] } | null;
/** File path */
path: string;
/** Name */
@@ -371,9 +371,16 @@ export async function addFile({
//#region Check drive usage
if (user && !isLink) {
const usage = await DriveFiles.calcDriveUsageOf(user);
+ const u = await Users.findOneBy({ id: user.id });
const instance = await fetchMeta();
- const driveCapacity = 1024 * 1024 * (Users.isLocalUser(user) ? instance.localDriveCapacityMb : instance.remoteDriveCapacityMb);
+ let driveCapacity = 1024 * 1024 * (Users.isLocalUser(user) ? instance.localDriveCapacityMb : instance.remoteDriveCapacityMb);
+
+ if (Users.isLocalUser(user) && u?.driveCapacityOverrideMb != null) {
+ driveCapacity = 1024 * 1024 * u.driveCapacityOverrideMb;
+ logger.debug('drive capacity override applied');
+ logger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
+ }
logger.debug(`drive usage is ${usage} (max: ${driveCapacity})`);
diff --git a/packages/client/src/components/code-core.vue b/packages/client/src/components/code-core.vue
index 45a38afe04..65dee5cdae 100644
--- a/packages/client/src/components/code-core.vue
+++ b/packages/client/src/components/code-core.vue
@@ -5,7 +5,7 @@
<script lang="ts" setup>
import { computed } from 'vue';
-import 'prismjs';
+import { Prism } from 'prismjs';
import 'prismjs/themes/prism-okaidia.css';
const props = defineProps<{
diff --git a/packages/client/src/components/form-dialog.vue b/packages/client/src/components/form-dialog.vue
index 5fd9ec460b..f05dde16f8 100644
--- a/packages/client/src/components/form-dialog.vue
+++ b/packages/client/src/components/form-dialog.vue
@@ -98,7 +98,7 @@ export default defineComponent({
created() {
for (const item in this.form) {
- this.values[item] = this.form[item].hasOwnProperty('default') ? this.form[item].default : null;
+ this.values[item] = this.form[item].default ?? null;
}
},
diff --git a/packages/client/src/components/global/router-view.vue b/packages/client/src/components/global/router-view.vue
index 7138faaa9d..fca2371f0d 100644
--- a/packages/client/src/components/global/router-view.vue
+++ b/packages/client/src/components/global/router-view.vue
@@ -13,9 +13,6 @@ const props = defineProps<{
router?: Router;
}>();
-const emit = defineEmits<{
-}>();
-
const router = props.router ?? inject('router');
if (router == null) {
diff --git a/packages/client/src/components/tag-cloud.vue b/packages/client/src/components/tag-cloud.vue
index 5ffa7321e4..9f3bc1c603 100644
--- a/packages/client/src/components/tag-cloud.vue
+++ b/packages/client/src/components/tag-cloud.vue
@@ -13,8 +13,6 @@
import { onMounted, ref, watch, PropType, onBeforeUnmount } from 'vue';
import tinycolor from 'tinycolor2';
-const props = defineProps<{}>();
-
const loaded = !!window.TagCanvas;
const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz';
const computedStyle = getComputedStyle(document.documentElement);
diff --git a/packages/client/src/pages/admin/_header_.vue b/packages/client/src/pages/admin/_header_.vue
index 73747e1164..aea2663c39 100644
--- a/packages/client/src/pages/admin/_header_.vue
+++ b/packages/client/src/pages/admin/_header_.vue
@@ -75,7 +75,6 @@ const hasTabs = computed(() => {
const showTabsPopup = (ev: MouseEvent) => {
if (!hasTabs.value) return;
- if (!narrow.value) return;
ev.preventDefault();
ev.stopPropagation();
const menu = props.tabs.map(tab => ({
diff --git a/packages/client/src/pages/admin/bot-protection.vue b/packages/client/src/pages/admin/bot-protection.vue
index d2e7919b4f..d316f973bc 100644
--- a/packages/client/src/pages/admin/bot-protection.vue
+++ b/packages/client/src/pages/admin/bot-protection.vue
@@ -61,27 +61,22 @@ let hcaptchaSecretKey: string | null = $ref(null);
let recaptchaSiteKey: string | null = $ref(null);
let recaptchaSecretKey: string | null = $ref(null);
-const enableHcaptcha = $computed(() => provider === 'hcaptcha');
-const enableRecaptcha = $computed(() => provider === 'recaptcha');
-
async function init() {
const meta = await os.api('admin/meta');
- enableHcaptcha = meta.enableHcaptcha;
hcaptchaSiteKey = meta.hcaptchaSiteKey;
hcaptchaSecretKey = meta.hcaptchaSecretKey;
- enableRecaptcha = meta.enableRecaptcha;
recaptchaSiteKey = meta.recaptchaSiteKey;
recaptchaSecretKey = meta.recaptchaSecretKey;
- provider = enableHcaptcha ? 'hcaptcha' : enableRecaptcha ? 'recaptcha' : null;
+ provider = meta.enableHcaptcha ? 'hcaptcha' : meta.enableRecaptcha ? 'recaptcha' : null;
}
function save() {
os.apiWithDialog('admin/update-meta', {
- enableHcaptcha,
+ enableHcaptcha: provider === 'hcaptcha',
hcaptchaSiteKey,
hcaptchaSecretKey,
- enableRecaptcha,
+ enableRecaptcha: provider === 'recaptcha',
recaptchaSiteKey,
recaptchaSecretKey,
}).then(() => {
diff --git a/packages/client/src/pages/admin/overview.user.vue b/packages/client/src/pages/admin/overview.user.vue
index 40592b280b..d70336f3c2 100644
--- a/packages/client/src/pages/admin/overview.user.vue
+++ b/packages/client/src/pages/admin/overview.user.vue
@@ -19,7 +19,7 @@ const props = defineProps<{
user: misskey.entities.User;
}>();
-const chart = $ref(null);
+let chart = $ref(null);
os.apiGet('charts/user/notes', { userId: props.user.id, limit: 16, span: 'day' }).then(res => {
chart = res;
diff --git a/packages/client/src/pages/gallery/post.vue b/packages/client/src/pages/gallery/post.vue
index e16ccc3150..e87a541e98 100644
--- a/packages/client/src/pages/gallery/post.vue
+++ b/packages/client/src/pages/gallery/post.vue
@@ -74,8 +74,8 @@ const props = defineProps<{
postId: string;
}>();
-const post = $ref(null);
-const error = $ref(null);
+let post = $ref(null);
+let error = $ref(null);
const otherPostsPagination = {
endpoint: 'users/gallery/posts' as const,
limit: 6,
diff --git a/packages/client/src/pages/my-antennas/editor.vue b/packages/client/src/pages/my-antennas/editor.vue
index 6f3c4afbfe..9470257c6c 100644
--- a/packages/client/src/pages/my-antennas/editor.vue
+++ b/packages/client/src/pages/my-antennas/editor.vue
@@ -46,6 +46,7 @@
<script lang="ts" setup>
import { watch } from 'vue';
+import * as Acct from 'misskey-js/built/acct';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
import MkTextarea from '@/components/form/textarea.vue';
diff --git a/packages/client/src/pages/my-lists/list.vue b/packages/client/src/pages/my-lists/list.vue
index 5bc0bf41dd..892878ae88 100644
--- a/packages/client/src/pages/my-lists/list.vue
+++ b/packages/client/src/pages/my-lists/list.vue
@@ -41,6 +41,7 @@ import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
import { mainRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
+import { i18n } from '@/i18n';
const props = defineProps<{
listId: string;
diff --git a/packages/client/src/pages/theme-editor.vue b/packages/client/src/pages/theme-editor.vue
index cec3833594..44b5a05f27 100644
--- a/packages/client/src/pages/theme-editor.vue
+++ b/packages/client/src/pages/theme-editor.vue
@@ -78,6 +78,7 @@ import FormButton from '@/components/ui/button.vue';
import FormTextarea from '@/components/form/textarea.vue';
import FormFolder from '@/components/form/folder.vue';
+import { $i } from '@/account';
import { Theme, applyTheme } from '@/scripts/theme';
import lightTheme from '@/themes/_light.json5';
import darkTheme from '@/themes/_dark.json5';
@@ -118,7 +119,7 @@ const fgColors = [
{ color: 'pink', forLight: '#84667d', forDark: '#e4d1e0', forPreview: '#b12390' },
];
-const theme = $ref<Partial<Theme>>({
+let theme = $ref<Partial<Theme>>({
base: 'light',
props: lightTheme.props,
});
diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue
index 204ece7eb6..51d224dfdd 100644
--- a/packages/client/src/pages/user-info.vue
+++ b/packages/client/src/pages/user-info.vue
@@ -85,6 +85,17 @@
</FormSection>
</div>
<div v-else-if="tab === 'moderation'" class="_formRoot">
+ <FormSection>
+ <template #label>Drive Capacity Override</template>
+
+ <FormInput v-if="user.host == null" v-model="driveCapacityOverrideMb" inline :manual-save="true" type="number" :placeholder="i18n.t('defaultValueIs', { value: instance.driveCapacityPerLocalUserMb })" @update:model-value="applyDriveCapacityOverride">
+ <template #label>{{ i18n.ts.driveCapOverrideLabel }}</template>
+ <template #suffix>MB</template>
+ <template #caption>
+ {{ i18n.ts.driveCapOverrideCaption }}
+ </template>
+ </FormInput>
+ </FormSection>
<FormSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" v-model="moderator" class="_formBlock" @update:modelValue="toggleModerator">{{ $ts.moderator }}</FormSwitch>
<FormSwitch v-model="silenced" class="_formBlock" @update:modelValue="toggleSilence">{{ $ts.silence }}</FormSwitch>
<FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ $ts.suspend }}</FormSwitch>
@@ -141,7 +152,7 @@
</template>
<script lang="ts" setup>
-import { computed, defineAsyncComponent, defineComponent, watch } from 'vue';
+import { computed, watch } from 'vue';
import * as misskey from 'misskey-js';
import MkChart from '@/components/chart.vue';
import MkObjectView from '@/components/object-view.vue';
@@ -150,6 +161,8 @@ import FormSwitch from '@/components/form/switch.vue';
import FormLink from '@/components/form/link.vue';
import FormSection from '@/components/form/section.vue';
import FormButton from '@/components/ui/button.vue';
+import FormInput from '@/components/form/input.vue';
+import FormSplit from '@/components/form/split.vue';
import FormFolder from '@/components/form/folder.vue';
import MkKeyValue from '@/components/key-value.vue';
import MkSelect from '@/components/form/select.vue';
@@ -164,6 +177,7 @@ import { userPage, acct } from '@/filters/user';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { iAmAdmin, iAmModerator } from '@/account';
+import { instance } from '@/instance';
const props = defineProps<{
userId: string;
@@ -172,13 +186,14 @@ const props = defineProps<{
let tab = $ref('overview');
let chartSrc = $ref('per-user-notes');
let user = $ref<null | misskey.entities.UserDetailed>();
-let init = $ref();
+let init = $ref<ReturnType<typeof createFetcher>>();
let info = $ref();
let ips = $ref(null);
let ap = $ref(null);
let moderator = $ref(false);
let silenced = $ref(false);
let suspended = $ref(false);
+let driveCapacityOverrideMb: number | null = $ref(0);
let moderationNote = $ref('');
const filesPagination = {
endpoint: 'admin/drive/files' as const,
@@ -203,6 +218,7 @@ function createFetcher() {
moderator = info.isModerator;
silenced = info.isSilenced;
suspended = info.isSuspended;
+ driveCapacityOverrideMb = user.driveCapacityOverrideMb;
moderationNote = info.moderationNote;
watch($$(moderationNote), async () => {
@@ -289,6 +305,22 @@ async function deleteAllFiles() {
await refreshUser();
}
+async function applyDriveCapacityOverride() {
+ let driveCapOrMb = driveCapacityOverrideMb;
+ if (driveCapacityOverrideMb && driveCapacityOverrideMb < 0) {
+ driveCapOrMb = null;
+ }
+ try {
+ await os.apiWithDialog('admin/drive-capacity-override', { userId: user.id, overrideMb: driveCapOrMb });
+ await refreshUser();
+ } catch (e) {
+ os.alert({
+ type: 'error',
+ text: e.toString(),
+ });
+ }
+}
+
async function deleteAccount() {
const confirm = await os.confirm({
type: 'warning',
@@ -319,7 +351,7 @@ watch(() => props.userId, () => {
immediate: true,
});
-watch(() => user, () => {
+watch($$(user), () => {
os.api('ap/get', {
uri: user.uri ?? `${url}/users/${user.id}`,
}).then(res => {
diff --git a/packages/client/src/plugin.ts b/packages/client/src/plugin.ts
index ca7b4b73d3..de1c955675 100644
--- a/packages/client/src/plugin.ts
+++ b/packages/client/src/plugin.ts
@@ -38,7 +38,7 @@ export function install(plugin) {
function createPluginEnv(opts) {
const config = new Map();
for (const [k, v] of Object.entries(opts.plugin.config || {})) {
- config.set(k, jsToVal(opts.plugin.configData.hasOwnProperty(k) ? opts.plugin.configData[k] : v.default));
+ config.set(k, jsToVal(typeof opts.plugin.configData[k] !== 'undefined' ? opts.plugin.configData[k] : v.default));
}
return {
diff --git a/packages/client/src/scripts/array.ts b/packages/client/src/scripts/array.ts
index 29d027de14..26c6195d66 100644
--- a/packages/client/src/scripts/array.ts
+++ b/packages/client/src/scripts/array.ts
@@ -98,7 +98,7 @@ export function groupOn<T, S>(f: (x: T) => S, xs: T[]): T[][] {
export function groupByX<T>(collections: T[], keySelector: (x: T) => string) {
return collections.reduce((obj: Record<string, T[]>, item: T) => {
const key = keySelector(item);
- if (!obj.hasOwnProperty(key)) {
+ if (typeof obj[key] === 'undefined') {
obj[key] = [];
}
diff --git a/packages/client/src/scripts/autocomplete.ts b/packages/client/src/scripts/autocomplete.ts
index 8d9bdee8f5..3ef6224175 100644
--- a/packages/client/src/scripts/autocomplete.ts
+++ b/packages/client/src/scripts/autocomplete.ts
@@ -8,7 +8,7 @@ export class Autocomplete {
x: Ref<number>;
y: Ref<number>;
q: Ref<string | null>;
- close: Function;
+ close: () => void;
} | null;
private textarea: HTMLInputElement | HTMLTextAreaElement;
private currentType: string;
diff --git a/packages/client/src/scripts/hotkey.ts b/packages/client/src/scripts/hotkey.ts
index fd9c74f6c8..bd8c3b6cab 100644
--- a/packages/client/src/scripts/hotkey.ts
+++ b/packages/client/src/scripts/hotkey.ts
@@ -1,6 +1,8 @@
import keyCode from './keycode';
-type Keymap = Record<string, Function>;
+type Callback = (ev: KeyboardEvent) => void;
+
+type Keymap = Record<string, Callback>;
type Pattern = {
which: string[];
@@ -11,14 +13,14 @@ type Pattern = {
type Action = {
patterns: Pattern[];
- callback: Function;
+ callback: Callback;
allowRepeat: boolean;
};
const parseKeymap = (keymap: Keymap) => Object.entries(keymap).map(([patterns, callback]): Action => {
const result = {
patterns: [],
- callback: callback,
+ callback,
allowRepeat: true
} as Action;
diff --git a/packages/client/src/scripts/url.ts b/packages/client/src/scripts/url.ts
index 542b00e0f0..86735de9f0 100644
--- a/packages/client/src/scripts/url.ts
+++ b/packages/client/src/scripts/url.ts
@@ -1,4 +1,4 @@
-export function query(obj: {}): string {
+export function query(obj: Record<string, any>): string {
const params = Object.entries(obj)
.filter(([, v]) => Array.isArray(v) ? v.length : v !== undefined)
.reduce((a, [k, v]) => (a[k] = v, a), {} as Record<string, any>);
diff --git a/packages/client/src/ui/classic.vue b/packages/client/src/ui/classic.vue
index 310232aec0..a2c26f536e 100644
--- a/packages/client/src/ui/classic.vue
+++ b/packages/client/src/ui/classic.vue
@@ -60,8 +60,8 @@ const DESKTOP_THRESHOLD = 1100;
let isDesktop = $ref(window.innerWidth >= DESKTOP_THRESHOLD);
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();
-const widgetsShowing = $ref(false);
-const fullView = $ref(false);
+let widgetsShowing = $ref(false);
+let fullView = $ref(false);
let globalHeaderHeight = $ref(0);
const wallpaper = localStorage.getItem('wallpaper') != null;
const showMenuOnTop = $computed(() => defaultStore.state.menuDisplay === 'top');
diff --git a/packages/client/src/ui/deck/main-column.vue b/packages/client/src/ui/deck/main-column.vue
index 670b4a212b..9a5fd43af7 100644
--- a/packages/client/src/ui/deck/main-column.vue
+++ b/packages/client/src/ui/deck/main-column.vue
@@ -53,7 +53,7 @@ function onContextmenu(ev: MouseEvent) {
if (isLink(ev.target as HTMLElement)) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes((ev.target as HTMLElement).tagName) || (ev.target as HTMLElement).attributes['contenteditable']) return;
if (window.getSelection()?.toString() !== '') return;
- const path = router.currentRoute.value.path;
+ const path = mainRouter.currentRoute.value.path;
os.contextMenu([{
type: 'label',
text: path,
diff --git a/packages/client/src/widgets/widget.ts b/packages/client/src/widgets/widget.ts
index 9626d01619..9fdfe7f3e1 100644
--- a/packages/client/src/widgets/widget.ts
+++ b/packages/client/src/widgets/widget.ts
@@ -36,8 +36,9 @@ export const useWidgetPropsManager = <F extends Form & Record<string, { default:
const mergeProps = () => {
for (const prop of Object.keys(propsDef)) {
- if (widgetProps.hasOwnProperty(prop)) continue;
- widgetProps[prop] = propsDef[prop].default;
+ if (typeof widgetProps[prop] === 'undefined') {
+ widgetProps[prop] = propsDef[prop].default;
+ }
}
};
watch(widgetProps, () => {