Merge remote-tracking branch 'msky/develop' into feat-1714
This commit is contained in:
@@ -13,29 +13,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable id-denylist --
|
||||
Chart.js has a `data` attribute in most chart definitions, which triggers the
|
||||
id-denylist violation when setting it. This is causing about 60+ lint issues.
|
||||
As this is part of Chart.js's API it makes sense to disable the check here.
|
||||
*/
|
||||
import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||
import { Chart } from 'chart.js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||
import { alpha } from '@/scripts/color.js';
|
||||
import date from '@/filters/date.js';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import { initChart } from '@/scripts/init-chart.js';
|
||||
import { chartLegend } from '@/scripts/chart-legend.js';
|
||||
import MkChartLegend from '@/components/MkChartLegend.vue';
|
||||
|
||||
initChart();
|
||||
|
||||
type ChartSrc =
|
||||
<script lang="ts">
|
||||
export type ChartSrc =
|
||||
| 'federation'
|
||||
| 'ap-request'
|
||||
| 'users'
|
||||
@@ -62,7 +41,30 @@ type ChartSrc =
|
||||
| 'per-user-pv'
|
||||
| 'per-user-following'
|
||||
| 'per-user-followers'
|
||||
| 'per-user-drive'
|
||||
| 'per-user-drive';
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable id-denylist --
|
||||
Chart.js has a `data` attribute in most chart definitions, which triggers the
|
||||
id-denylist violation when setting it. This is causing about 60+ lint issues.
|
||||
As this is part of Chart.js's API it makes sense to disable the check here.
|
||||
*/
|
||||
import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||
import { Chart } from 'chart.js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||
import { alpha } from '@/scripts/color.js';
|
||||
import date from '@/filters/date.js';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import { initChart } from '@/scripts/init-chart.js';
|
||||
import { chartLegend } from '@/scripts/chart-legend.js';
|
||||
import MkChartLegend from '@/components/MkChartLegend.vue';
|
||||
|
||||
initChart();
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
src: ChartSrc;
|
||||
|
@@ -94,12 +94,12 @@ defineExpose({
|
||||
|
||||
--root-margin: 24px;
|
||||
|
||||
--headerHeight: 46px;
|
||||
--headerHeightNarrow: 42px;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
--root-margin: 16px;
|
||||
}
|
||||
|
||||
--headerHeight: 46px;
|
||||
--headerHeightNarrow: 42px;
|
||||
}
|
||||
|
||||
.header {
|
||||
|
@@ -100,14 +100,14 @@ defineProps<{
|
||||
|
||||
&.grid {
|
||||
> .group {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
|
||||
& + .group {
|
||||
padding-top: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
|
||||
> .title {
|
||||
font-size: 1em;
|
||||
opacity: 0.7;
|
||||
|
@@ -508,10 +508,6 @@ defineExpose({
|
||||
.header {
|
||||
--height: 39px;
|
||||
|
||||
&.mini {
|
||||
--height: 32px;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -524,6 +520,10 @@ defineExpose({
|
||||
//border-bottom: solid 1px var(--divider);
|
||||
font-size: 90%;
|
||||
font-weight: bold;
|
||||
|
||||
&.mini {
|
||||
--height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.headerButton {
|
||||
|
@@ -47,14 +47,14 @@ useInterval(fetch, 1000 * 60, {
|
||||
.root {
|
||||
&:global {
|
||||
> .users {
|
||||
.chart-move {
|
||||
transition: transform 1s ease;
|
||||
}
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
grid-gap: 12px;
|
||||
|
||||
.chart-move {
|
||||
transition: transform 1s ease;
|
||||
}
|
||||
|
||||
> .user:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@@ -12,19 +12,31 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #label>{{ avatarDecoration.name }}</template>
|
||||
<template #caption>{{ avatarDecoration.description }}</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkInput v-model="avatarDecoration.name">
|
||||
<template #label>{{ i18n.ts.name }}</template>
|
||||
</MkInput>
|
||||
<MkTextarea v-model="avatarDecoration.description">
|
||||
<template #label>{{ i18n.ts.description }}</template>
|
||||
</MkTextarea>
|
||||
<MkInput v-model="avatarDecoration.url">
|
||||
<template #label>{{ i18n.ts.imageUrl }}</template>
|
||||
</MkInput>
|
||||
<div class="buttons _buttons">
|
||||
<MkButton class="button" inline primary @click="save(avatarDecoration)"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
||||
<MkButton v-if="avatarDecoration.id != null" class="button" inline danger @click="del(avatarDecoration)"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
||||
<div :class="$style.editorRoot">
|
||||
<div :class="$style.editorWrapper">
|
||||
<div :class="$style.preview">
|
||||
<div :class="[$style.previewItem, $style.light]">
|
||||
<MkAvatar style="width: 60px; height: 60px;" :user="$i" :decorations="[avatarDecoration]" forceShowDecoration/>
|
||||
</div>
|
||||
<div :class="[$style.previewItem, $style.dark]">
|
||||
<MkAvatar style="width: 60px; height: 60px;" :user="$i" :decorations="[avatarDecoration]" forceShowDecoration/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_gaps_m">
|
||||
<MkInput v-model="avatarDecoration.name">
|
||||
<template #label>{{ i18n.ts.name }}</template>
|
||||
</MkInput>
|
||||
<MkTextarea v-model="avatarDecoration.description">
|
||||
<template #label>{{ i18n.ts.description }}</template>
|
||||
</MkTextarea>
|
||||
<MkInput v-model="avatarDecoration.url">
|
||||
<template #label>{{ i18n.ts.imageUrl }}</template>
|
||||
</MkInput>
|
||||
<div class="_buttons">
|
||||
<MkButton inline primary @click="save(avatarDecoration)"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
||||
<MkButton v-if="avatarDecoration.id != null" inline danger @click="del(avatarDecoration)"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MkFolder>
|
||||
@@ -39,6 +51,7 @@ import * as Misskey from 'misskey-js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
@@ -47,6 +60,8 @@ import MkFolder from '@/components/MkFolder.vue';
|
||||
|
||||
const avatarDecorations = ref<Misskey.entities.AdminAvatarDecorationsListResponse>([]);
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
function add() {
|
||||
avatarDecorations.value.unshift({
|
||||
_id: Math.random().toString(36),
|
||||
@@ -99,3 +114,55 @@ definePageMetadata(() => ({
|
||||
icon: 'ti ti-sparkles',
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.editorRoot {
|
||||
container: editor / inline-size;
|
||||
}
|
||||
|
||||
.editorWrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto auto;
|
||||
gap: var(--margin);
|
||||
}
|
||||
|
||||
.preview {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
gap: var(--margin);
|
||||
}
|
||||
|
||||
.previewItem {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 160px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius);
|
||||
|
||||
&.light {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background: #222;
|
||||
}
|
||||
}
|
||||
|
||||
@container editor (min-width: 600px) {
|
||||
.editorWrapper {
|
||||
grid-template-columns: 200px 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
gap: calc(var(--margin) * 2);
|
||||
}
|
||||
|
||||
.preview {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -134,7 +134,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, inject } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkChart from '@/components/MkChart.vue';
|
||||
import MkChart, { type ChartSrc } from '@/components/MkChart.vue';
|
||||
import MkObjectView from '@/components/MkObjectView.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import MkLink from '@/components/MkLink.vue';
|
||||
@@ -150,7 +150,7 @@ import { iAmModerator, iAmAdmin } from '@/account.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
|
||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||
import { dateString } from '@/filters/date.js';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
@@ -165,7 +165,7 @@ const props = defineProps<{
|
||||
|
||||
const tab = ref('overview');
|
||||
|
||||
const chartSrc = ref('instance-requests');
|
||||
const chartSrc = ref<ChartSrc>('instance-requests');
|
||||
const meta = ref<Misskey.entities.AdminMetaResponse | null>(null);
|
||||
const instance = ref<Misskey.entities.FederationInstance | null>(null);
|
||||
const suspensionState = ref<'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding'>('none');
|
||||
@@ -176,7 +176,7 @@ const faviconUrl = ref<string | null>(null);
|
||||
const moderationNote = ref('');
|
||||
|
||||
const usersPagination = {
|
||||
endpoint: iAmModerator ? 'admin/show-users' : 'users' as const,
|
||||
endpoint: iAmModerator ? 'admin/show-users' : 'users',
|
||||
limit: 10,
|
||||
params: {
|
||||
sort: '+updatedAt',
|
||||
@@ -184,11 +184,14 @@ const usersPagination = {
|
||||
hostname: props.host,
|
||||
},
|
||||
offsetMode: true,
|
||||
};
|
||||
} satisfies Paging;
|
||||
|
||||
watch(moderationNote, async () => {
|
||||
await misskeyApi('admin/federation/update-instance', { host: instance.value.host, moderationNote: moderationNote.value });
|
||||
});
|
||||
if (iAmModerator) {
|
||||
watch(moderationNote, async () => {
|
||||
if (instance.value == null) return;
|
||||
await misskeyApi('admin/federation/update-instance', { host: instance.value.host, moderationNote: moderationNote.value });
|
||||
});
|
||||
}
|
||||
|
||||
async function fetch(): Promise<void> {
|
||||
if (iAmAdmin) {
|
||||
@@ -206,6 +209,7 @@ async function fetch(): Promise<void> {
|
||||
}
|
||||
|
||||
async function toggleBlock(): Promise<void> {
|
||||
if (!iAmAdmin) return;
|
||||
if (!meta.value) throw new Error('No meta?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
const { host } = instance.value;
|
||||
@@ -215,6 +219,7 @@ async function toggleBlock(): Promise<void> {
|
||||
}
|
||||
|
||||
async function toggleSilenced(): Promise<void> {
|
||||
if (!iAmAdmin) return;
|
||||
if (!meta.value) throw new Error('No meta?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
const { host } = instance.value;
|
||||
@@ -225,6 +230,7 @@ async function toggleSilenced(): Promise<void> {
|
||||
}
|
||||
|
||||
async function toggleMediaSilenced(): Promise<void> {
|
||||
if (!iAmAdmin) return;
|
||||
if (!meta.value) throw new Error('No meta?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
const { host } = instance.value;
|
||||
@@ -235,6 +241,7 @@ async function toggleMediaSilenced(): Promise<void> {
|
||||
}
|
||||
|
||||
async function stopDelivery(): Promise<void> {
|
||||
if (!iAmModerator) return;
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
suspensionState.value = 'manuallySuspended';
|
||||
await misskeyApi('admin/federation/update-instance', {
|
||||
@@ -244,6 +251,7 @@ async function stopDelivery(): Promise<void> {
|
||||
}
|
||||
|
||||
async function resumeDelivery(): Promise<void> {
|
||||
if (!iAmModerator) return;
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
suspensionState.value = 'none';
|
||||
await misskeyApi('admin/federation/update-instance', {
|
||||
@@ -253,6 +261,7 @@ async function resumeDelivery(): Promise<void> {
|
||||
}
|
||||
|
||||
function refreshMetadata(): void {
|
||||
if (!iAmModerator) return;
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
misskeyApi('admin/federation/refresh-remote-instance-metadata', {
|
||||
host: instance.value.host,
|
||||
|
@@ -436,13 +436,12 @@ definePageMetadata(() => ({
|
||||
.pageBannerTitleUser {
|
||||
--height: 32px;
|
||||
flex-shrink: 0;
|
||||
line-height: var(--height);
|
||||
|
||||
.avatar {
|
||||
height: var(--height);
|
||||
width: var(--height);
|
||||
}
|
||||
|
||||
line-height: var(--height);
|
||||
}
|
||||
|
||||
.pageBannerTitleSubActions {
|
||||
|
@@ -17,10 +17,6 @@
|
||||
--minBottomSpacingMobile: calc(72px + max(12px, env(safe-area-inset-bottom, 0px)));
|
||||
--minBottomSpacing: var(--minBottomSpacingMobile);
|
||||
|
||||
@media (max-width: 500px) {
|
||||
--margin: var(--marginHalf);
|
||||
}
|
||||
|
||||
//--ad: rgb(255 169 0 / 10%);
|
||||
--eventFollow: #36aed2;
|
||||
--eventRenote: #36d298;
|
||||
@@ -29,6 +25,10 @@
|
||||
--eventReaction: #e99a0b;
|
||||
--eventAchievement: #cb9a11;
|
||||
--eventOther: #88a6b7;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
--margin: var(--marginHalf);
|
||||
}
|
||||
}
|
||||
|
||||
::selection {
|
||||
|
@@ -40,6 +40,14 @@ const XUserList = defineAsyncComponent(() => import('./statusbar-user-list.vue')
|
||||
--nameMargin: 10px;
|
||||
font-size: 0.85em;
|
||||
|
||||
display: flex;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
line-height: var(--height);
|
||||
height: var(--height);
|
||||
overflow: clip;
|
||||
contain: strict;
|
||||
|
||||
&.verySmall {
|
||||
--nameMargin: 7px;
|
||||
--height: 16px;
|
||||
@@ -64,14 +72,6 @@ const XUserList = defineAsyncComponent(() => import('./statusbar-user-list.vue')
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
line-height: var(--height);
|
||||
height: var(--height);
|
||||
overflow: clip;
|
||||
contain: strict;
|
||||
|
||||
&.black {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
|
@@ -324,11 +324,11 @@ function onDrop(ev) {
|
||||
|
||||
> .body {
|
||||
background: transparent !important;
|
||||
scrollbar-color: var(--scrollbarHandle) transparent;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
scrollbar-color: var(--scrollbarHandle) transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,11 +338,11 @@ function onDrop(ev) {
|
||||
> .body {
|
||||
background: var(--bg) !important;
|
||||
overflow-y: scroll !important;
|
||||
scrollbar-color: var(--scrollbarHandle) transparent;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: inherit;
|
||||
}
|
||||
scrollbar-color: var(--scrollbarHandle) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -423,10 +423,10 @@ function onDrop(ev) {
|
||||
box-sizing: border-box;
|
||||
container-type: size;
|
||||
background-color: var(--bg);
|
||||
scrollbar-color: var(--scrollbarHandle) var(--panel);
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--panel);
|
||||
}
|
||||
scrollbar-color: var(--scrollbarHandle) var(--panel);
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user