release: 2023.11.2
This commit is contained in:
commit
1022280465
44 changed files with 706 additions and 407 deletions
|
@ -112,6 +112,7 @@ redis:
|
||||||
# apiKey: ''
|
# apiKey: ''
|
||||||
# ssl: true
|
# ssl: true
|
||||||
# index: ''
|
# index: ''
|
||||||
|
# scope: global
|
||||||
|
|
||||||
# ┌───────────────┐
|
# ┌───────────────┐
|
||||||
#───┘ ID generation └───────────────────────────────────────────
|
#───┘ ID generation └───────────────────────────────────────────
|
||||||
|
@ -144,15 +145,22 @@ id: 'aidx'
|
||||||
# Job concurrency per worker
|
# Job concurrency per worker
|
||||||
# deliverJobConcurrency: 128
|
# deliverJobConcurrency: 128
|
||||||
# inboxJobConcurrency: 16
|
# inboxJobConcurrency: 16
|
||||||
|
# relashionshipJobConcurrency: 16
|
||||||
|
# What's relashionshipJob?:
|
||||||
|
# Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations.
|
||||||
|
|
||||||
# Job rate limiter
|
# Job rate limiter
|
||||||
# deliverJobPerSec: 128
|
# deliverJobPerSec: 128
|
||||||
# inboxJobPerSec: 16
|
# inboxJobPerSec: 16
|
||||||
|
# relashionshipJobPerSec: 64
|
||||||
|
|
||||||
# Job attempts
|
# Job attempts
|
||||||
# deliverJobMaxAttempts: 12
|
# deliverJobMaxAttempts: 12
|
||||||
# inboxJobMaxAttempts: 8
|
# inboxJobMaxAttempts: 8
|
||||||
|
|
||||||
|
# Local address used for outgoing requests
|
||||||
|
#outgoingAddress: 127.0.0.1
|
||||||
|
|
||||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||||
#outgoingAddressFamily: ipv4
|
#outgoingAddressFamily: ipv4
|
||||||
|
|
||||||
|
@ -175,8 +183,15 @@ proxyBypassHosts:
|
||||||
#mediaProxy: https://example.com/proxy
|
#mediaProxy: https://example.com/proxy
|
||||||
|
|
||||||
# Proxy remote files (default: true)
|
# Proxy remote files (default: true)
|
||||||
|
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
|
||||||
proxyRemoteFiles: true
|
proxyRemoteFiles: true
|
||||||
|
|
||||||
|
# Movie Thumbnail Generation URL
|
||||||
|
# There is no reference implementation.
|
||||||
|
# For example, Misskey will point to the following URL:
|
||||||
|
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
|
||||||
|
#videoThumbnailGenerator: https://example.com
|
||||||
|
|
||||||
# Sign to ActivityPub GET request (default: true)
|
# Sign to ActivityPub GET request (default: true)
|
||||||
signToActivityPubGet: true
|
signToActivityPubGet: true
|
||||||
|
|
||||||
|
|
2
.github/workflows/welcome.yml
vendored
2
.github/workflows/welcome.yml
vendored
|
@ -8,7 +8,7 @@ jobs:
|
||||||
run:
|
run:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/first-interaction@v1.2.0
|
- uses: actions/first-interaction@v1.3.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
issue-message: |
|
issue-message: |
|
||||||
|
|
|
@ -55,6 +55,7 @@ addToAntenna: "Add to antenna"
|
||||||
sendMessage: "Send a message"
|
sendMessage: "Send a message"
|
||||||
copyRSS: "Copy RSS"
|
copyRSS: "Copy RSS"
|
||||||
copyUsername: "Copy username"
|
copyUsername: "Copy username"
|
||||||
|
openRemoteProfile: "Open remote profile"
|
||||||
copyUserId: "Copy user ID"
|
copyUserId: "Copy user ID"
|
||||||
copyNoteId: "Copy note ID"
|
copyNoteId: "Copy note ID"
|
||||||
copyFileId: "Copy file ID"
|
copyFileId: "Copy file ID"
|
||||||
|
@ -110,7 +111,6 @@ renote: "Boost"
|
||||||
unrenote: "Remove boost"
|
unrenote: "Remove boost"
|
||||||
renoted: "Boosted."
|
renoted: "Boosted."
|
||||||
quoted: "Quoted."
|
quoted: "Quoted."
|
||||||
rmquote: "Removed quote."
|
|
||||||
rmboost: "Unboosted."
|
rmboost: "Unboosted."
|
||||||
cantRenote: "This post can't be boosted."
|
cantRenote: "This post can't be boosted."
|
||||||
cantReRenote: "A boost can't be boosted."
|
cantReRenote: "A boost can't be boosted."
|
||||||
|
@ -891,6 +891,7 @@ continueThread: "View thread continuation"
|
||||||
deleteAccountConfirm: "This will irreversibly delete your account. Proceed?"
|
deleteAccountConfirm: "This will irreversibly delete your account. Proceed?"
|
||||||
incorrectPassword: "Incorrect password."
|
incorrectPassword: "Incorrect password."
|
||||||
voteConfirm: "Confirm your vote for \"{choice}\"?"
|
voteConfirm: "Confirm your vote for \"{choice}\"?"
|
||||||
|
voteConfirmMulti: "Confirm your vote for \"{choice}\"?\n You can choose more options after confirmation."
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile"
|
useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile"
|
||||||
welcomeBackWithName: "Welcome back, {name}"
|
welcomeBackWithName: "Welcome back, {name}"
|
||||||
|
@ -987,6 +988,7 @@ cannotLoad: "Unable to load"
|
||||||
numberOfProfileView: "Profile views"
|
numberOfProfileView: "Profile views"
|
||||||
like: "Like"
|
like: "Like"
|
||||||
unlike: "Unlike"
|
unlike: "Unlike"
|
||||||
|
defaultLike: "Default like emoji"
|
||||||
numberOfLikes: "Likes"
|
numberOfLikes: "Likes"
|
||||||
show: "Show"
|
show: "Show"
|
||||||
neverShow: "Don't show again"
|
neverShow: "Don't show again"
|
||||||
|
@ -1855,6 +1857,14 @@ _ago:
|
||||||
monthsAgo: "{n}mo ago"
|
monthsAgo: "{n}mo ago"
|
||||||
yearsAgo: "{n}y ago"
|
yearsAgo: "{n}y ago"
|
||||||
invalid: "None"
|
invalid: "None"
|
||||||
|
_timeIn:
|
||||||
|
seconds: "in {n} seconds"
|
||||||
|
minutes: "in {n} minutes"
|
||||||
|
hours: "in {n} hours"
|
||||||
|
days: "in {n} days"
|
||||||
|
weeks: "in {n} weeks"
|
||||||
|
months: "in {n} months"
|
||||||
|
years: "in {n} years"
|
||||||
_time:
|
_time:
|
||||||
second: "Second(s)"
|
second: "Second(s)"
|
||||||
minute: "Minute(s)"
|
minute: "Minute(s)"
|
||||||
|
@ -1980,6 +1990,7 @@ _widgets:
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "Select a list"
|
chooseList: "Select a list"
|
||||||
clicker: "Clicker"
|
clicker: "Clicker"
|
||||||
|
search: "Search"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
show: "Show content"
|
show: "Show content"
|
||||||
|
@ -2007,6 +2018,7 @@ _poll:
|
||||||
remainingHours: "{h} hour(s) {m} minute(s) remaining"
|
remainingHours: "{h} hour(s) {m} minute(s) remaining"
|
||||||
remainingMinutes: "{m} minute(s) {s} second(s) remaining"
|
remainingMinutes: "{m} minute(s) {s} second(s) remaining"
|
||||||
remainingSeconds: "{s} second(s) remaining"
|
remainingSeconds: "{s} second(s) remaining"
|
||||||
|
multiple: "Multiple choices"
|
||||||
_visibility:
|
_visibility:
|
||||||
public: "Public"
|
public: "Public"
|
||||||
publicDescription: "Your note will be visible for all users"
|
publicDescription: "Your note will be visible for all users"
|
||||||
|
|
6
locales/index.d.ts
vendored
6
locales/index.d.ts
vendored
|
@ -58,6 +58,7 @@ export interface Locale {
|
||||||
"sendMessage": string;
|
"sendMessage": string;
|
||||||
"copyRSS": string;
|
"copyRSS": string;
|
||||||
"copyUsername": string;
|
"copyUsername": string;
|
||||||
|
"openRemoteProfile": string;
|
||||||
"copyUserId": string;
|
"copyUserId": string;
|
||||||
"copyNoteId": string;
|
"copyNoteId": string;
|
||||||
"copyFileId": string;
|
"copyFileId": string;
|
||||||
|
@ -114,7 +115,6 @@ export interface Locale {
|
||||||
"renoted": string;
|
"renoted": string;
|
||||||
"quoted": string;
|
"quoted": string;
|
||||||
"rmboost": string;
|
"rmboost": string;
|
||||||
"rmquote": string;
|
|
||||||
"cantRenote": string;
|
"cantRenote": string;
|
||||||
"cantReRenote": string;
|
"cantReRenote": string;
|
||||||
"quote": string;
|
"quote": string;
|
||||||
|
@ -894,6 +894,7 @@ export interface Locale {
|
||||||
"deleteAccountConfirm": string;
|
"deleteAccountConfirm": string;
|
||||||
"incorrectPassword": string;
|
"incorrectPassword": string;
|
||||||
"voteConfirm": string;
|
"voteConfirm": string;
|
||||||
|
"voteConfirmMulti": string;
|
||||||
"hide": string;
|
"hide": string;
|
||||||
"useDrawerReactionPickerForMobile": string;
|
"useDrawerReactionPickerForMobile": string;
|
||||||
"welcomeBackWithName": string;
|
"welcomeBackWithName": string;
|
||||||
|
@ -990,6 +991,7 @@ export interface Locale {
|
||||||
"numberOfProfileView": string;
|
"numberOfProfileView": string;
|
||||||
"like": string;
|
"like": string;
|
||||||
"unlike": string;
|
"unlike": string;
|
||||||
|
"defaultLike": string;
|
||||||
"numberOfLikes": string;
|
"numberOfLikes": string;
|
||||||
"show": string;
|
"show": string;
|
||||||
"neverShow": string;
|
"neverShow": string;
|
||||||
|
@ -2125,6 +2127,7 @@ export interface Locale {
|
||||||
"chooseList": string;
|
"chooseList": string;
|
||||||
};
|
};
|
||||||
"clicker": string;
|
"clicker": string;
|
||||||
|
"search": string;
|
||||||
};
|
};
|
||||||
"_cw": {
|
"_cw": {
|
||||||
"hide": string;
|
"hide": string;
|
||||||
|
@ -2154,6 +2157,7 @@ export interface Locale {
|
||||||
"remainingHours": string;
|
"remainingHours": string;
|
||||||
"remainingMinutes": string;
|
"remainingMinutes": string;
|
||||||
"remainingSeconds": string;
|
"remainingSeconds": string;
|
||||||
|
"multiple": string;
|
||||||
};
|
};
|
||||||
"_visibility": {
|
"_visibility": {
|
||||||
"public": string;
|
"public": string;
|
||||||
|
|
|
@ -54,6 +54,7 @@ addToAntenna: "Aggiungi all'antenna"
|
||||||
sendMessage: "Invia messaggio"
|
sendMessage: "Invia messaggio"
|
||||||
copyRSS: "Copia RSS"
|
copyRSS: "Copia RSS"
|
||||||
copyUsername: "Copia nome utente"
|
copyUsername: "Copia nome utente"
|
||||||
|
openRemoteProfile: "Apri profilo remoto"
|
||||||
copyUserId: "Copia ID del profilo"
|
copyUserId: "Copia ID del profilo"
|
||||||
copyNoteId: "Copia ID della Nota"
|
copyNoteId: "Copia ID della Nota"
|
||||||
copyFileId: "Copia ID del file"
|
copyFileId: "Copia ID del file"
|
||||||
|
@ -731,6 +732,8 @@ thisIsExperimentalFeature: "Questa è una funzionalità sperimentale. Potrebbe e
|
||||||
developer: "Sviluppatore"
|
developer: "Sviluppatore"
|
||||||
makeExplorable: "Profilo visibile pubblicamente nella pagina \"Esplora\""
|
makeExplorable: "Profilo visibile pubblicamente nella pagina \"Esplora\""
|
||||||
makeExplorableDescription: "Disabilitando questa opzione, il tuo profilo non verrà elencato nella pagina \"Esplora\"."
|
makeExplorableDescription: "Disabilitando questa opzione, il tuo profilo non verrà elencato nella pagina \"Esplora\"."
|
||||||
|
makeIndexable: "Non indicizzare le note pubbliche"
|
||||||
|
makeIndexableDescription: "Le tue note pubbliche non saranno cercabili"
|
||||||
showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
|
showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
|
||||||
duplicate: "Duplica"
|
duplicate: "Duplica"
|
||||||
left: "Sinistra"
|
left: "Sinistra"
|
||||||
|
@ -964,6 +967,7 @@ cannotLoad: "Caricamento impossibile"
|
||||||
numberOfProfileView: "Visualizzazioni profilo"
|
numberOfProfileView: "Visualizzazioni profilo"
|
||||||
like: "Mi piace!"
|
like: "Mi piace!"
|
||||||
unlike: "Non mi piace"
|
unlike: "Non mi piace"
|
||||||
|
defaultLike: "Emoji predefinita per \"mi piace\""
|
||||||
numberOfLikes: "Numero di Like"
|
numberOfLikes: "Numero di Like"
|
||||||
show: "Visualizza"
|
show: "Visualizza"
|
||||||
neverShow: "Non mostrare più"
|
neverShow: "Non mostrare più"
|
||||||
|
@ -1266,6 +1270,8 @@ _serverSettings:
|
||||||
shortName: "Abbreviazione"
|
shortName: "Abbreviazione"
|
||||||
shortNameDescription: "Un'abbreviazione o un nome comune che può essere visualizzato al posto del nome ufficiale lungo del server."
|
shortNameDescription: "Un'abbreviazione o un nome comune che può essere visualizzato al posto del nome ufficiale lungo del server."
|
||||||
fanoutTimelineDescription: "Attivando questa funzionalità migliori notevolmente la capacità delle Timeline di collezionare Note, riducendo il carico sul database. Tuttavia, aumenterà l'impiego di memoria RAM per Redis. Disattiva se il tuo server ha poca RAM o la funzionalità è irregolare."
|
fanoutTimelineDescription: "Attivando questa funzionalità migliori notevolmente la capacità delle Timeline di collezionare Note, riducendo il carico sul database. Tuttavia, aumenterà l'impiego di memoria RAM per Redis. Disattiva se il tuo server ha poca RAM o la funzionalità è irregolare."
|
||||||
|
fanoutTimelineDbFallback: "Ripiega sul database"
|
||||||
|
fanoutTimelineDbFallbackDescription: "Attivando questa funzionalità, nel caso che il contenuto di una Timeline non sia presente nella cache, verrà consultato il database. Disattivandola, il carico sul database sarà ulteriormente ridotto, ma le Timeline saranno limitate"
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "Migra un altro profilo dentro a questo"
|
moveFrom: "Migra un altro profilo dentro a questo"
|
||||||
moveFromSub: "Crea un alias verso un altro profilo remoto"
|
moveFromSub: "Crea un alias verso un altro profilo remoto"
|
||||||
|
@ -1702,6 +1708,7 @@ _serverDisconnectedBehavior:
|
||||||
reload: "Ricarica automaticamente"
|
reload: "Ricarica automaticamente"
|
||||||
dialog: "Apri avviso in finestra"
|
dialog: "Apri avviso in finestra"
|
||||||
quiet: "Visualizza avviso in modo discreto"
|
quiet: "Visualizza avviso in modo discreto"
|
||||||
|
disabled: "Non visualizzare l'avviso"
|
||||||
_channel:
|
_channel:
|
||||||
create: "Nuovo canale"
|
create: "Nuovo canale"
|
||||||
edit: "Gerisci canale"
|
edit: "Gerisci canale"
|
||||||
|
@ -1817,6 +1824,14 @@ _ago:
|
||||||
monthsAgo: "{n} mesi fa"
|
monthsAgo: "{n} mesi fa"
|
||||||
yearsAgo: "{n} anni fa"
|
yearsAgo: "{n} anni fa"
|
||||||
invalid: "Niente da visualizzare"
|
invalid: "Niente da visualizzare"
|
||||||
|
_timeIn:
|
||||||
|
seconds: "fra {n} secondi"
|
||||||
|
minutes: "fra {n} minuti"
|
||||||
|
hours: "fra {n} ore"
|
||||||
|
days: "fra {n} giorni"
|
||||||
|
weeks: "fra {n} settimane"
|
||||||
|
months: "fra {n} mesi"
|
||||||
|
years: "fra {n} anni"
|
||||||
_time:
|
_time:
|
||||||
second: "s"
|
second: "s"
|
||||||
minute: "min"
|
minute: "min"
|
||||||
|
|
|
@ -55,6 +55,7 @@ addToAntenna: "アンテナに追加"
|
||||||
sendMessage: "メッセージを送信"
|
sendMessage: "メッセージを送信"
|
||||||
copyRSS: "RSSをコピー"
|
copyRSS: "RSSをコピー"
|
||||||
copyUsername: "ユーザー名をコピー"
|
copyUsername: "ユーザー名をコピー"
|
||||||
|
openRemoteProfile: "リモートプロファイルを開く"
|
||||||
copyUserId: "ユーザーIDをコピー"
|
copyUserId: "ユーザーIDをコピー"
|
||||||
copyNoteId: "ノートIDをコピー"
|
copyNoteId: "ノートIDをコピー"
|
||||||
copyFileId: "ファイルIDをコピー"
|
copyFileId: "ファイルIDをコピー"
|
||||||
|
@ -111,7 +112,6 @@ unrenote: "リノート解除"
|
||||||
renoted: "ブースト。"
|
renoted: "ブースト。"
|
||||||
quoted: "引用。"
|
quoted: "引用。"
|
||||||
rmboost: "アンブースト。"
|
rmboost: "アンブースト。"
|
||||||
rmquote: "引用を削除しました。"
|
|
||||||
cantRenote: "この投稿はリノートできません。"
|
cantRenote: "この投稿はリノートできません。"
|
||||||
cantReRenote: "リノートをリノートすることはできません。"
|
cantReRenote: "リノートをリノートすることはできません。"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
|
@ -891,6 +891,7 @@ continueThread: "さらにスレッドを見る"
|
||||||
deleteAccountConfirm: "アカウントが削除されます。よろしいですか?"
|
deleteAccountConfirm: "アカウントが削除されます。よろしいですか?"
|
||||||
incorrectPassword: "パスワードが間違っています。"
|
incorrectPassword: "パスワードが間違っています。"
|
||||||
voteConfirm: "「{choice}」に投票しますか?"
|
voteConfirm: "「{choice}」に投票しますか?"
|
||||||
|
voteConfirmMulti: "「{choice}」に投票しますか?\n 確認後、選択肢を増やすことができます。"
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
|
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
|
||||||
welcomeBackWithName: "おかえりなさい、{name}さん"
|
welcomeBackWithName: "おかえりなさい、{name}さん"
|
||||||
|
@ -987,6 +988,7 @@ cannotLoad: "読み込めません"
|
||||||
numberOfProfileView: "プロフィール表示回数"
|
numberOfProfileView: "プロフィール表示回数"
|
||||||
like: "いいね!"
|
like: "いいね!"
|
||||||
unlike: "いいねを解除"
|
unlike: "いいねを解除"
|
||||||
|
defaultLike: "絵文字のようなデフォルト"
|
||||||
numberOfLikes: "いいね数"
|
numberOfLikes: "いいね数"
|
||||||
show: "表示"
|
show: "表示"
|
||||||
neverShow: "今後表示しない"
|
neverShow: "今後表示しない"
|
||||||
|
@ -2029,6 +2031,7 @@ _widgets:
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "リストを選択"
|
chooseList: "リストを選択"
|
||||||
clicker: "クリッカー"
|
clicker: "クリッカー"
|
||||||
|
search: "検索"
|
||||||
|
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
|
@ -2058,6 +2061,7 @@ _poll:
|
||||||
remainingHours: "終了まであと{h}時間{m}分"
|
remainingHours: "終了まであと{h}時間{m}分"
|
||||||
remainingMinutes: "終了まであと{m}分{s}秒"
|
remainingMinutes: "終了まであと{m}分{s}秒"
|
||||||
remainingSeconds: "終了まであと{s}秒"
|
remainingSeconds: "終了まであと{s}秒"
|
||||||
|
multiple: "複数の選択肢"
|
||||||
|
|
||||||
_visibility:
|
_visibility:
|
||||||
public: "パブリック"
|
public: "パブリック"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sharkey",
|
"name": "sharkey",
|
||||||
"version": "2023.11.1",
|
"version": "2023.11.2",
|
||||||
"codename": "shonk",
|
"codename": "shonk",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiEmoji } from '@/models/Emoji.js';
|
import type { MiEmoji } from '@/models/Emoji.js';
|
||||||
import type { EmojisRepository, MiRole, MiUser } from '@/models/_.js';
|
import type { DriveFilesRepository, EmojisRepository, MiRole, MiUser } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { MemoryKVCache, RedisSingleCache } from '@/misc/cache.js';
|
import { MemoryKVCache, RedisSingleCache } from '@/misc/cache.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
@ -20,6 +20,7 @@ import { query } from '@/misc/prelude/url.js';
|
||||||
import type { Serialized } from '@/types.js';
|
import type { Serialized } from '@/types.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
|
import { DriveService } from './DriveService.js';
|
||||||
|
|
||||||
const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/;
|
const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/;
|
||||||
|
|
||||||
|
@ -38,11 +39,15 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
||||||
@Inject(DI.emojisRepository)
|
@Inject(DI.emojisRepository)
|
||||||
private emojisRepository: EmojisRepository,
|
private emojisRepository: EmojisRepository,
|
||||||
|
|
||||||
|
@Inject(DI.driveFilesRepository)
|
||||||
|
private driveFilesRepository: DriveFilesRepository,
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private emojiEntityService: EmojiEntityService,
|
private emojiEntityService: EmojiEntityService,
|
||||||
private moderationLogService: ModerationLogService,
|
private moderationLogService: ModerationLogService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
private driveService: DriveService,
|
||||||
) {
|
) {
|
||||||
this.cache = new MemoryKVCache<MiEmoji | null>(1000 * 60 * 60 * 12);
|
this.cache = new MemoryKVCache<MiEmoji | null>(1000 * 60 * 60 * 12);
|
||||||
|
|
||||||
|
@ -259,6 +264,12 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
||||||
|
|
||||||
this.localEmojisCache.refresh();
|
this.localEmojisCache.refresh();
|
||||||
|
|
||||||
|
const file = await this.driveFilesRepository.findOneBy({ url: emoji.originalUrl, userHost: emoji.host ? emoji.host : IsNull() });
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
await this.driveService.deleteFile(file, false, moderator ? moderator : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
this.globalEventService.publishBroadcastStream('emojiDeleted', {
|
this.globalEventService.publishBroadcastStream('emojiDeleted', {
|
||||||
emojis: [await this.emojiEntityService.packDetailed(emoji)],
|
emojis: [await this.emojiEntityService.packDetailed(emoji)],
|
||||||
});
|
});
|
||||||
|
@ -280,6 +291,12 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
||||||
for (const emoji of emojis) {
|
for (const emoji of emojis) {
|
||||||
await this.emojisRepository.delete(emoji.id);
|
await this.emojisRepository.delete(emoji.id);
|
||||||
|
|
||||||
|
const file = await this.driveFilesRepository.findOneBy({ url: emoji.originalUrl, userHost: emoji.host ? emoji.host : IsNull() });
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
await this.driveService.deleteFile(file, false, moderator ? moderator : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
this.moderationLogService.log(moderator, 'deleteCustomEmoji', {
|
this.moderationLogService.log(moderator, 'deleteCustomEmoji', {
|
||||||
emojiId: emoji.id,
|
emojiId: emoji.id,
|
||||||
|
|
|
@ -14,18 +14,15 @@ import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mf
|
||||||
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
||||||
import type { IMentionedRemoteUsers } from '@/models/Note.js';
|
import type { IMentionedRemoteUsers } from '@/models/Note.js';
|
||||||
import { MiNote } from '@/models/Note.js';
|
import { MiNote } from '@/models/Note.js';
|
||||||
import type { NoteEditRepository, ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
import type { NoteEditRepository, ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository, PollsRepository } from '@/models/_.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiApp } from '@/models/App.js';
|
import type { MiApp } from '@/models/App.js';
|
||||||
import { concat } from '@/misc/prelude/array.js';
|
import { concat } from '@/misc/prelude/array.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||||
import { MiPoll, type IPoll } from '@/models/Poll.js';
|
import { MiPoll, type IPoll } from '@/models/Poll.js';
|
||||||
import { checkWordMute } from '@/misc/check-word-mute.js';
|
|
||||||
import type { MiChannel } from '@/models/Channel.js';
|
import type { MiChannel } from '@/models/Channel.js';
|
||||||
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
||||||
import { MemorySingleCache } from '@/misc/cache.js';
|
|
||||||
import type { MiUserProfile } from '@/models/UserProfile.js';
|
|
||||||
import { RelayService } from '@/core/RelayService.js';
|
import { RelayService } from '@/core/RelayService.js';
|
||||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
@ -35,7 +32,6 @@ import ActiveUsersChart from '@/core/chart/charts/active-users.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { NotificationService } from '@/core/NotificationService.js';
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
import { WebhookService } from '@/core/WebhookService.js';
|
import { WebhookService } from '@/core/WebhookService.js';
|
||||||
import { HashtagService } from '@/core/HashtagService.js';
|
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
@ -48,11 +44,7 @@ import { DB_MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { SearchService } from '@/core/SearchService.js';
|
import { SearchService } from '@/core/SearchService.js';
|
||||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
|
||||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||||
import { AntennaService } from './AntennaService.js';
|
|
||||||
import NotesChart from './chart/charts/notes.js';
|
|
||||||
import PerUserNotesChart from './chart/charts/per-user-notes.js';
|
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
@ -191,6 +183,9 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
@Inject(DI.noteEditRepository)
|
@Inject(DI.noteEditRepository)
|
||||||
private noteEditRepository: NoteEditRepository,
|
private noteEditRepository: NoteEditRepository,
|
||||||
|
|
||||||
|
@Inject(DI.pollsRepository)
|
||||||
|
private pollsRepository: PollsRepository,
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
|
@ -201,18 +196,13 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
private relayService: RelayService,
|
private relayService: RelayService,
|
||||||
private federatedInstanceService: FederatedInstanceService,
|
private federatedInstanceService: FederatedInstanceService,
|
||||||
private hashtagService: HashtagService,
|
|
||||||
private antennaService: AntennaService,
|
|
||||||
private webhookService: WebhookService,
|
private webhookService: WebhookService,
|
||||||
private featuredService: FeaturedService,
|
|
||||||
private remoteUserResolveService: RemoteUserResolveService,
|
private remoteUserResolveService: RemoteUserResolveService,
|
||||||
private apDeliverManagerService: ApDeliverManagerService,
|
private apDeliverManagerService: ApDeliverManagerService,
|
||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private notesChart: NotesChart,
|
|
||||||
private perUserNotesChart: PerUserNotesChart,
|
|
||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
private instanceChart: InstanceChart,
|
private instanceChart: InstanceChart,
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
|
@ -385,6 +375,10 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
update.hasPoll = !!data.poll;
|
update.hasPoll = !!data.poll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const poll = await this.pollsRepository.findOneBy({ noteId: oldnote.id });
|
||||||
|
|
||||||
|
const oldPoll = poll ? { choices: poll.choices, multiple: poll.multiple, expiresAt: poll.expiresAt } : null;
|
||||||
|
|
||||||
if (Object.keys(update).length > 0) {
|
if (Object.keys(update).length > 0) {
|
||||||
const exists = await this.noteEditRepository.findOneBy({ noteId: oldnote.id });
|
const exists = await this.noteEditRepository.findOneBy({ noteId: oldnote.id });
|
||||||
|
|
||||||
|
@ -456,7 +450,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.poll != null) {
|
if (data.poll != null && JSON.stringify(data.poll) !== JSON.stringify(oldPoll)) {
|
||||||
// Start transaction
|
// Start transaction
|
||||||
await this.db.transaction(async transactionalEntityManager => {
|
await this.db.transaction(async transactionalEntityManager => {
|
||||||
await transactionalEntityManager.update(MiNote, oldnote.id, note);
|
await transactionalEntityManager.update(MiNote, oldnote.id, note);
|
||||||
|
|
|
@ -278,14 +278,14 @@ export class QueueService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createImportMastoToDbJob(user: ThinUser, targets: string[]) {
|
public createImportMastoToDbJob(user: ThinUser, targets: string[], note: MiNote['id'] | null) {
|
||||||
const jobs = targets.map(rel => this.generateToDbJobData('importMastoToDb', { user, target: rel }));
|
const jobs = targets.map(rel => this.generateToDbJobData('importMastoToDb', { user, target: rel, note }));
|
||||||
return this.dbQueue.addBulk(jobs);
|
return this.dbQueue.addBulk(jobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createImportPleroToDbJob(user: ThinUser, targets: string[]) {
|
public createImportPleroToDbJob(user: ThinUser, targets: string[], note: MiNote['id'] | null) {
|
||||||
const jobs = targets.map(rel => this.generateToDbJobData('importPleroToDb', { user, target: rel }));
|
const jobs = targets.map(rel => this.generateToDbJobData('importPleroToDb', { user, target: rel, note }));
|
||||||
return this.dbQueue.addBulk(jobs);
|
return this.dbQueue.addBulk(jobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,7 @@ export class ApRendererService {
|
||||||
mediaType: file.webpublicType ?? file.type,
|
mediaType: file.webpublicType ?? file.type,
|
||||||
url: this.driveFileEntityService.getPublicUrl(file),
|
url: this.driveFileEntityService.getPublicUrl(file),
|
||||||
name: file.comment,
|
name: file.comment,
|
||||||
|
summary: file.comment,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export interface IObject {
|
||||||
type: string | string[];
|
type: string | string[];
|
||||||
id?: string;
|
id?: string;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
summary?: string;
|
summary?: string | null;
|
||||||
_misskey_summary?: string;
|
_misskey_summary?: string;
|
||||||
published?: string;
|
published?: string;
|
||||||
cc?: ApObject;
|
cc?: ApObject;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as vm from 'node:vm';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ZipReader } from 'slacc';
|
import { ZipReader } from 'slacc';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository, DriveFilesRepository, MiDriveFile, MiNote, NotesRepository, MiUser } from '@/models/_.js';
|
import type { UsersRepository, DriveFilesRepository, MiDriveFile, MiNote, NotesRepository, MiUser, DriveFoldersRepository, MiDriveFolder } from '@/models/_.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { DownloadService } from '@/core/DownloadService.js';
|
import { DownloadService } from '@/core/DownloadService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
@ -14,9 +14,10 @@ import { DriveService } from '@/core/DriveService.js';
|
||||||
import { MfmService } from '@/core/MfmService.js';
|
import { MfmService } from '@/core/MfmService.js';
|
||||||
import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js';
|
import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js';
|
||||||
import { extractApHashtagObjects } from '@/core/activitypub/models/tag.js';
|
import { extractApHashtagObjects } from '@/core/activitypub/models/tag.js';
|
||||||
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import type { DbNoteImportToDbJobData, DbNoteImportJobData, DbKeyNoteImportToDbJobData } from '../types.js';
|
import type { DbNoteImportToDbJobData, DbNoteImportJobData, DbNoteWithParentImportToDbJobData } from '../types.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportNotesProcessorService {
|
export class ImportNotesProcessorService {
|
||||||
|
@ -29,6 +30,9 @@ export class ImportNotesProcessorService {
|
||||||
@Inject(DI.driveFilesRepository)
|
@Inject(DI.driveFilesRepository)
|
||||||
private driveFilesRepository: DriveFilesRepository,
|
private driveFilesRepository: DriveFilesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.driveFoldersRepository)
|
||||||
|
private driveFoldersRepository: DriveFoldersRepository,
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
|
@ -38,20 +42,21 @@ export class ImportNotesProcessorService {
|
||||||
private apNoteService: ApNoteService,
|
private apNoteService: ApNoteService,
|
||||||
private driveService: DriveService,
|
private driveService: DriveService,
|
||||||
private downloadService: DownloadService,
|
private downloadService: DownloadService,
|
||||||
|
private idService: IdService,
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('import-notes');
|
this.logger = this.queueLoggerService.logger.createSubLogger('import-notes');
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async uploadFiles(dir: string, user: MiUser) {
|
private async uploadFiles(dir: string, user: MiUser, folder?: MiDriveFolder['id']) {
|
||||||
const fileList = fs.readdirSync(dir);
|
const fileList = fs.readdirSync(dir);
|
||||||
for await (const file of fileList) {
|
for await (const file of fileList) {
|
||||||
const name = `${dir}/${file}`;
|
const name = `${dir}/${file}`;
|
||||||
if (fs.statSync(name).isDirectory()) {
|
if (fs.statSync(name).isDirectory()) {
|
||||||
await this.uploadFiles(name, user);
|
await this.uploadFiles(name, user, folder);
|
||||||
} else {
|
} else {
|
||||||
const exists = await this.driveFilesRepository.findOneBy({ name: file, userId: user.id });
|
const exists = await this.driveFilesRepository.findOneBy({ name: file, userId: user.id, folderId: folder });
|
||||||
|
|
||||||
if (file.endsWith('.srt')) return;
|
if (file.endsWith('.srt')) return;
|
||||||
|
|
||||||
|
@ -60,6 +65,7 @@ export class ImportNotesProcessorService {
|
||||||
user: user,
|
user: user,
|
||||||
path: name,
|
path: name,
|
||||||
name: file,
|
name: file,
|
||||||
|
folderId: folder,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +74,7 @@ export class ImportNotesProcessorService {
|
||||||
|
|
||||||
// Function was taken from Firefish and modified for our needs
|
// Function was taken from Firefish and modified for our needs
|
||||||
@bindThis
|
@bindThis
|
||||||
private async recreateChain(idField: string, replyField: string, arr: any[]): Promise<any[]> {
|
private async recreateChain(idFieldPath: string[], replyFieldPath: string[], arr: any[], includeOrphans: boolean): Promise<any[]> {
|
||||||
type NotesMap = {
|
type NotesMap = {
|
||||||
[id: string]: any;
|
[id: string]: any;
|
||||||
};
|
};
|
||||||
|
@ -77,28 +83,42 @@ export class ImportNotesProcessorService {
|
||||||
const notesWaitingForParent: NotesMap = {};
|
const notesWaitingForParent: NotesMap = {};
|
||||||
|
|
||||||
for await (const note of arr) {
|
for await (const note of arr) {
|
||||||
noteById[note[idField]] = note;
|
const noteId = idFieldPath.reduce(
|
||||||
|
(obj, step) => obj[step],
|
||||||
|
note,
|
||||||
|
);
|
||||||
|
|
||||||
|
noteById[noteId] = note;
|
||||||
note.childNotes = [];
|
note.childNotes = [];
|
||||||
|
|
||||||
const children = notesWaitingForParent[note[idField]];
|
const children = notesWaitingForParent[noteId];
|
||||||
if (children) {
|
if (children) {
|
||||||
note.childNotes.push(...children);
|
note.childNotes.push(...children);
|
||||||
|
delete notesWaitingForParent[noteId];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note[replyField] == null) {
|
const noteReplyId = replyFieldPath.reduce(
|
||||||
|
(obj, step) => obj[step],
|
||||||
|
note,
|
||||||
|
);
|
||||||
|
if (noteReplyId == null) {
|
||||||
notesTree.push(note);
|
notesTree.push(note);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent = noteById[note[replyField]];
|
const parent = noteById[noteReplyId];
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent.childNotes.push(note);
|
parent.childNotes.push(note);
|
||||||
} else {
|
} else {
|
||||||
notesWaitingForParent[note[replyField]] ||= [];
|
notesWaitingForParent[noteReplyId] ||= [];
|
||||||
notesWaitingForParent[note[replyField]].push(note);
|
notesWaitingForParent[noteReplyId].push(note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includeOrphans) {
|
||||||
|
notesTree.push(...Object.values(notesWaitingForParent).flat(1));
|
||||||
|
}
|
||||||
|
|
||||||
return notesTree;
|
return notesTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +146,12 @@ export class ImportNotesProcessorService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let folder = await this.driveFoldersRepository.findOneBy({ name: 'Imports', userId: job.data.user.id });
|
||||||
|
if (folder == null) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Imports', userId: job.data.user.id });
|
||||||
|
folder = await this.driveFoldersRepository.findOneBy({ name: 'Imports', userId: job.data.user.id });
|
||||||
|
}
|
||||||
|
|
||||||
const type = job.data.type;
|
const type = job.data.type;
|
||||||
|
|
||||||
if (type === 'Twitter' || file.name.startsWith('twitter') && file.name.endsWith('.zip')) {
|
if (type === 'Twitter' || file.name.startsWith('twitter') && file.name.endsWith('.zip')) {
|
||||||
|
@ -164,7 +190,7 @@ export class ImportNotesProcessorService {
|
||||||
const tweets = Object.keys(fakeWindow.window.YTD.tweets.part0).reduce((m, key, i, obj) => {
|
const tweets = Object.keys(fakeWindow.window.YTD.tweets.part0).reduce((m, key, i, obj) => {
|
||||||
return m.concat(fakeWindow.window.YTD.tweets.part0[key].tweet);
|
return m.concat(fakeWindow.window.YTD.tweets.part0[key].tweet);
|
||||||
}, []);
|
}, []);
|
||||||
const processedTweets = await this.recreateChain("id_str", "in_reply_to_status_id_str", tweets);
|
const processedTweets = await this.recreateChain(['id_str'], ['in_reply_to_status_id_str'], tweets, false);
|
||||||
this.queueService.createImportTweetsToDbJob(job.data.user, processedTweets, null);
|
this.queueService.createImportTweetsToDbJob(job.data.user, processedTweets, null);
|
||||||
} finally {
|
} finally {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -192,7 +218,12 @@ export class ImportNotesProcessorService {
|
||||||
ZipReader.withDestinationPath(outputPath).viaBuffer(await fs.promises.readFile(destPath));
|
ZipReader.withDestinationPath(outputPath).viaBuffer(await fs.promises.readFile(destPath));
|
||||||
const postsJson = fs.readFileSync(outputPath + '/your_activity_across_facebook/posts/your_posts__check_ins__photos_and_videos_1.json', 'utf-8');
|
const postsJson = fs.readFileSync(outputPath + '/your_activity_across_facebook/posts/your_posts__check_ins__photos_and_videos_1.json', 'utf-8');
|
||||||
const posts = JSON.parse(postsJson);
|
const posts = JSON.parse(postsJson);
|
||||||
await this.uploadFiles(outputPath + '/your_activity_across_facebook/posts/media', user);
|
const facebookFolder = await this.driveFoldersRepository.findOneBy({ name: 'Facebook', userId: job.data.user.id, parentId: folder?.id });
|
||||||
|
if (facebookFolder == null && folder) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Facebook', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
const createdFolder = await this.driveFoldersRepository.findOneBy({ name: 'Facebook', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
if (createdFolder) await this.uploadFiles(outputPath + '/your_activity_across_facebook/posts/media', user, createdFolder.id);
|
||||||
|
}
|
||||||
this.queueService.createImportFBToDbJob(job.data.user, posts);
|
this.queueService.createImportFBToDbJob(job.data.user, posts);
|
||||||
} finally {
|
} finally {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -223,7 +254,12 @@ export class ImportNotesProcessorService {
|
||||||
if (isInstagram) {
|
if (isInstagram) {
|
||||||
const postsJson = fs.readFileSync(outputPath + '/content/posts_1.json', 'utf-8');
|
const postsJson = fs.readFileSync(outputPath + '/content/posts_1.json', 'utf-8');
|
||||||
const posts = JSON.parse(postsJson);
|
const posts = JSON.parse(postsJson);
|
||||||
await this.uploadFiles(outputPath + '/media/posts', user);
|
const igFolder = await this.driveFoldersRepository.findOneBy({ name: 'Instagram', userId: job.data.user.id, parentId: folder?.id });
|
||||||
|
if (igFolder == null && folder) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Instagram', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
const createdFolder = await this.driveFoldersRepository.findOneBy({ name: 'Instagram', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
if (createdFolder) await this.uploadFiles(outputPath + '/media/posts', user, createdFolder.id);
|
||||||
|
}
|
||||||
this.queueService.createImportIGToDbJob(job.data.user, posts);
|
this.queueService.createImportIGToDbJob(job.data.user, posts);
|
||||||
} else if (isOutbox) {
|
} else if (isOutbox) {
|
||||||
const actorJson = fs.readFileSync(outputPath + '/actor.json', 'utf-8');
|
const actorJson = fs.readFileSync(outputPath + '/actor.json', 'utf-8');
|
||||||
|
@ -232,12 +268,21 @@ export class ImportNotesProcessorService {
|
||||||
if (isPleroma) {
|
if (isPleroma) {
|
||||||
const outboxJson = fs.readFileSync(outputPath + '/outbox.json', 'utf-8');
|
const outboxJson = fs.readFileSync(outputPath + '/outbox.json', 'utf-8');
|
||||||
const outbox = JSON.parse(outboxJson);
|
const outbox = JSON.parse(outboxJson);
|
||||||
this.queueService.createImportPleroToDbJob(job.data.user, outbox.orderedItems.filter((x: any) => x.type === 'Create' && x.object.type === 'Note'));
|
const processedToots = await this.recreateChain(['object', 'id'], ['object', 'inReplyTo'], outbox.orderedItems.filter((x: any) => x.type === 'Create' && x.object.type === 'Note'), true);
|
||||||
|
this.queueService.createImportPleroToDbJob(job.data.user, processedToots, null);
|
||||||
} else {
|
} else {
|
||||||
const outboxJson = fs.readFileSync(outputPath + '/outbox.json', 'utf-8');
|
const outboxJson = fs.readFileSync(outputPath + '/outbox.json', 'utf-8');
|
||||||
const outbox = JSON.parse(outboxJson);
|
const outbox = JSON.parse(outboxJson);
|
||||||
if (fs.existsSync(outputPath + '/media_attachments/files')) await this.uploadFiles(outputPath + '/media_attachments/files', user);
|
let mastoFolder = await this.driveFoldersRepository.findOneBy({ name: 'Mastodon', userId: job.data.user.id, parentId: folder?.id });
|
||||||
this.queueService.createImportMastoToDbJob(job.data.user, outbox.orderedItems.filter((x: any) => x.type === 'Create' && x.object.type === 'Note'));
|
if (mastoFolder == null && folder) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Mastodon', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
mastoFolder = await this.driveFoldersRepository.findOneBy({ name: 'Mastodon', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
}
|
||||||
|
if (fs.existsSync(outputPath + '/media_attachments/files') && mastoFolder) {
|
||||||
|
await this.uploadFiles(outputPath + '/media_attachments/files', user, mastoFolder.id);
|
||||||
|
}
|
||||||
|
const processedToots = await this.recreateChain(['object', 'id'], ['object', 'inReplyTo'], outbox.orderedItems.filter((x: any) => x.type === 'Create' && x.object.type === 'Note'), true);
|
||||||
|
this.queueService.createImportMastoToDbJob(job.data.user, processedToots, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -260,7 +305,7 @@ export class ImportNotesProcessorService {
|
||||||
|
|
||||||
const notesJson = fs.readFileSync(path, 'utf-8');
|
const notesJson = fs.readFileSync(path, 'utf-8');
|
||||||
const notes = JSON.parse(notesJson);
|
const notes = JSON.parse(notesJson);
|
||||||
const processedNotes = await this.recreateChain("id", "replyId", notes);
|
const processedNotes = await this.recreateChain(['id'], ['replyId'], notes, false);
|
||||||
this.queueService.createImportKeyNotesToDbJob(job.data.user, processedNotes, null);
|
this.queueService.createImportKeyNotesToDbJob(job.data.user, processedNotes, null);
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
@ -269,7 +314,7 @@ export class ImportNotesProcessorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async processKeyNotesToDb(job: Bull.Job<DbKeyNoteImportToDbJobData>): Promise<void> {
|
public async processKeyNotesToDb(job: Bull.Job<DbNoteWithParentImportToDbJobData>): Promise<void> {
|
||||||
const note = job.data.target;
|
const note = job.data.target;
|
||||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
@ -280,16 +325,25 @@ export class ImportNotesProcessorService {
|
||||||
|
|
||||||
const parentNote = job.data.note ? await this.notesRepository.findOneBy({ id: job.data.note }) : null;
|
const parentNote = job.data.note ? await this.notesRepository.findOneBy({ id: job.data.note }) : null;
|
||||||
|
|
||||||
|
const folder = await this.driveFoldersRepository.findOneBy({ name: 'Imports', userId: job.data.user.id });
|
||||||
|
if (folder == null) return;
|
||||||
|
|
||||||
const files: MiDriveFile[] = [];
|
const files: MiDriveFile[] = [];
|
||||||
const date = new Date(note.createdAt);
|
const date = new Date(note.createdAt);
|
||||||
|
|
||||||
if (note.files && this.isIterable(note.files)) {
|
if (note.files && this.isIterable(note.files)) {
|
||||||
|
let keyFolder = await this.driveFoldersRepository.findOneBy({ name: 'Misskey', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
if (keyFolder == null) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Misskey', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
keyFolder = await this.driveFoldersRepository.findOneBy({ name: 'Misskey', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
}
|
||||||
|
|
||||||
for await (const file of note.files) {
|
for await (const file of note.files) {
|
||||||
const [filePath, cleanup] = await createTemp();
|
const [filePath, cleanup] = await createTemp();
|
||||||
const slashdex = file.url.lastIndexOf('/');
|
const slashdex = file.url.lastIndexOf('/');
|
||||||
const name = file.url.substring(slashdex + 1);
|
const name = file.url.substring(slashdex + 1);
|
||||||
|
|
||||||
const exists = await this.driveFilesRepository.findOneBy({ name: name, userId: user.id });
|
const exists = await this.driveFilesRepository.findOneBy({ name: name, userId: user.id }) ?? await this.driveFilesRepository.findOneBy({ name: name, userId: user.id, folderId: keyFolder?.id });
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
try {
|
try {
|
||||||
|
@ -301,6 +355,7 @@ export class ImportNotesProcessorService {
|
||||||
user: user,
|
user: user,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
name: name,
|
name: name,
|
||||||
|
folderId: keyFolder?.id,
|
||||||
});
|
});
|
||||||
files.push(driveFile);
|
files.push(driveFile);
|
||||||
} else {
|
} else {
|
||||||
|
@ -316,27 +371,32 @@ export class ImportNotesProcessorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async processMastoToDb(job: Bull.Job<DbNoteImportToDbJobData>): Promise<void> {
|
public async processMastoToDb(job: Bull.Job<DbNoteWithParentImportToDbJobData>): Promise<void> {
|
||||||
const toot = job.data.target;
|
const toot = job.data.target;
|
||||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toot.directMessage) return;
|
||||||
|
|
||||||
const date = new Date(toot.object.published);
|
const date = new Date(toot.object.published);
|
||||||
let text = undefined;
|
let text = undefined;
|
||||||
const files: MiDriveFile[] = [];
|
const files: MiDriveFile[] = [];
|
||||||
let reply: MiNote | null = null;
|
let reply: MiNote | null = null;
|
||||||
|
|
||||||
if (toot.object.inReplyTo != null) {
|
if (toot.object.inReplyTo != null) {
|
||||||
|
const parentNote = job.data.note ? await this.notesRepository.findOneBy({ id: job.data.note }) : null;
|
||||||
|
if (parentNote) {
|
||||||
|
reply = parentNote;
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
reply = await this.apNoteService.resolveNote(toot.object.inReplyTo);
|
reply = await this.apNoteService.resolveNote(toot.object.inReplyTo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reply = null;
|
reply = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (toot.directMessage) return;
|
|
||||||
|
|
||||||
const hashtags = extractApHashtagObjects(toot.object.tag).map((x) => x.name).filter((x): x is string => x != null);
|
const hashtags = extractApHashtagObjects(toot.object.tag).map((x) => x.name).filter((x): x is string => x != null);
|
||||||
|
|
||||||
|
@ -357,31 +417,40 @@ export class ImportNotesProcessorService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.noteCreateService.import(user, { createdAt: date, text: text, files: files, apMentions: new Array(0), cw: toot.object.sensitive ? toot.object.summary : null, reply: reply });
|
const createdNote = await this.noteCreateService.import(user, { createdAt: date, text: text, files: files, apMentions: new Array(0), cw: toot.object.sensitive ? toot.object.summary : null, reply: reply });
|
||||||
|
if (toot.childNotes) this.queueService.createImportMastoToDbJob(user, toot.childNotes, createdNote.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async processPleroToDb(job: Bull.Job<DbNoteImportToDbJobData>): Promise<void> {
|
public async processPleroToDb(job: Bull.Job<DbNoteWithParentImportToDbJobData>): Promise<void> {
|
||||||
const post = job.data.target;
|
const post = job.data.target;
|
||||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (post.directMessage) return;
|
||||||
|
|
||||||
const date = new Date(post.object.published);
|
const date = new Date(post.object.published);
|
||||||
let text = undefined;
|
let text = undefined;
|
||||||
const files: MiDriveFile[] = [];
|
const files: MiDriveFile[] = [];
|
||||||
let reply: MiNote | null = null;
|
let reply: MiNote | null = null;
|
||||||
|
|
||||||
|
const folder = await this.driveFoldersRepository.findOneBy({ name: 'Imports', userId: job.data.user.id });
|
||||||
|
if (folder == null) return;
|
||||||
|
|
||||||
if (post.object.inReplyTo != null) {
|
if (post.object.inReplyTo != null) {
|
||||||
|
const parentNote = job.data.note ? await this.notesRepository.findOneBy({ id: job.data.note }) : null;
|
||||||
|
if (parentNote) {
|
||||||
|
reply = parentNote;
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
reply = await this.apNoteService.resolveNote(post.object.inReplyTo);
|
reply = await this.apNoteService.resolveNote(post.object.inReplyTo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reply = null;
|
reply = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (post.directMessage) return;
|
|
||||||
|
|
||||||
const hashtags = extractApHashtagObjects(post.object.tag).map((x) => x.name).filter((x): x is string => x != null);
|
const hashtags = extractApHashtagObjects(post.object.tag).map((x) => x.name).filter((x): x is string => x != null);
|
||||||
|
|
||||||
|
@ -392,12 +461,18 @@ export class ImportNotesProcessorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post.object.attachment && this.isIterable(post.object.attachment)) {
|
if (post.object.attachment && this.isIterable(post.object.attachment)) {
|
||||||
|
let pleroFolder = await this.driveFoldersRepository.findOneBy({ name: 'Pleroma', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
if (pleroFolder == null) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Pleroma', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
pleroFolder = await this.driveFoldersRepository.findOneBy({ name: 'Pleroma', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
}
|
||||||
|
|
||||||
for await (const file of post.object.attachment) {
|
for await (const file of post.object.attachment) {
|
||||||
const slashdex = file.url.lastIndexOf('/');
|
const slashdex = file.url.lastIndexOf('/');
|
||||||
const name = file.url.substring(slashdex + 1);
|
const name = file.url.substring(slashdex + 1);
|
||||||
const [filePath, cleanup] = await createTemp();
|
const [filePath, cleanup] = await createTemp();
|
||||||
|
|
||||||
const exists = await this.driveFilesRepository.findOneBy({ name: name, userId: user.id });
|
const exists = await this.driveFilesRepository.findOneBy({ name: name, userId: user.id }) ?? await this.driveFilesRepository.findOneBy({ name: name, userId: user.id, folderId: pleroFolder?.id });
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
try {
|
try {
|
||||||
|
@ -409,6 +484,7 @@ export class ImportNotesProcessorService {
|
||||||
user: user,
|
user: user,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
name: name,
|
name: name,
|
||||||
|
folderId: pleroFolder?.id,
|
||||||
});
|
});
|
||||||
files.push(driveFile);
|
files.push(driveFile);
|
||||||
} else {
|
} else {
|
||||||
|
@ -419,7 +495,8 @@ export class ImportNotesProcessorService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.noteCreateService.import(user, { createdAt: date, text: text, files: files, apMentions: new Array(0), cw: post.object.sensitive ? post.object.summary : null, reply: reply });
|
const createdNote = await this.noteCreateService.import(user, { createdAt: date, text: text, files: files, apMentions: new Array(0), cw: post.object.sensitive ? post.object.summary : null, reply: reply });
|
||||||
|
if (post.childNotes) this.queueService.createImportPleroToDbJob(user, post.childNotes, createdNote.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -468,13 +545,16 @@ export class ImportNotesProcessorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async processTwitterDb(job: Bull.Job<DbKeyNoteImportToDbJobData>): Promise<void> {
|
public async processTwitterDb(job: Bull.Job<DbNoteWithParentImportToDbJobData>): Promise<void> {
|
||||||
const tweet = job.data.target;
|
const tweet = job.data.target;
|
||||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const folder = await this.driveFoldersRepository.findOneBy({ name: 'Imports', userId: job.data.user.id });
|
||||||
|
if (folder == null) return;
|
||||||
|
|
||||||
const parentNote = job.data.note ? await this.notesRepository.findOneBy({ id: job.data.note }) : null;
|
const parentNote = job.data.note ? await this.notesRepository.findOneBy({ id: job.data.note }) : null;
|
||||||
|
|
||||||
async function replaceTwitterUrls(full_text: string, urls: any) {
|
async function replaceTwitterUrls(full_text: string, urls: any) {
|
||||||
|
@ -500,13 +580,19 @@ export class ImportNotesProcessorService {
|
||||||
const files: MiDriveFile[] = [];
|
const files: MiDriveFile[] = [];
|
||||||
|
|
||||||
if (tweet.extended_entities && this.isIterable(tweet.extended_entities.media)) {
|
if (tweet.extended_entities && this.isIterable(tweet.extended_entities.media)) {
|
||||||
|
let twitFolder = await this.driveFoldersRepository.findOneBy({ name: 'Twitter', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
if (twitFolder == null) {
|
||||||
|
await this.driveFoldersRepository.insert({ id: this.idService.gen(), name: 'Twitter', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
twitFolder = await this.driveFoldersRepository.findOneBy({ name: 'Twitter', userId: job.data.user.id, parentId: folder.id });
|
||||||
|
}
|
||||||
|
|
||||||
for await (const file of tweet.extended_entities.media) {
|
for await (const file of tweet.extended_entities.media) {
|
||||||
if (file.video_info) {
|
if (file.video_info) {
|
||||||
const [filePath, cleanup] = await createTemp();
|
const [filePath, cleanup] = await createTemp();
|
||||||
const slashdex = file.video_info.variants[0].url.lastIndexOf('/');
|
const slashdex = file.video_info.variants[0].url.lastIndexOf('/');
|
||||||
const name = file.video_info.variants[0].url.substring(slashdex + 1);
|
const name = file.video_info.variants[0].url.substring(slashdex + 1);
|
||||||
|
|
||||||
const exists = await this.driveFilesRepository.findOneBy({ name: name, userId: user.id });
|
const exists = await this.driveFilesRepository.findOneBy({ name: name, userId: user.id }) ?? await this.driveFilesRepository.findOneBy({ name: name, userId: user.id, folderId: twitFolder?.id });
|
||||||
|
|
||||||
const videos = file.video_info.variants.filter((x: any) => x.content_type === 'video/mp4');
|
const videos = file.video_info.variants.filter((x: any) => x.content_type === 'video/mp4');
|
||||||
|
|
||||||
|
@ -520,6 +606,7 @@ export class ImportNotesProcessorService {
|
||||||
user: user,
|
user: user,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
name: name,
|
name: name,
|
||||||
|
folderId: twitFolder?.id,
|
||||||
});
|
});
|
||||||
files.push(driveFile);
|
files.push(driveFile);
|
||||||
} else {
|
} else {
|
||||||
|
@ -545,6 +632,7 @@ export class ImportNotesProcessorService {
|
||||||
user: user,
|
user: user,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
name: name,
|
name: name,
|
||||||
|
folderId: twitFolder?.id,
|
||||||
});
|
});
|
||||||
files.push(driveFile);
|
files.push(driveFile);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -50,12 +50,12 @@ export type DbJobMap = {
|
||||||
exportUserLists: DbJobDataWithUser;
|
exportUserLists: DbJobDataWithUser;
|
||||||
importAntennas: DBAntennaImportJobData;
|
importAntennas: DBAntennaImportJobData;
|
||||||
importNotes: DbNoteImportJobData;
|
importNotes: DbNoteImportJobData;
|
||||||
importTweetsToDb: DbKeyNoteImportToDbJobData;
|
importTweetsToDb: DbNoteWithParentImportToDbJobData;
|
||||||
importIGToDb: DbNoteImportToDbJobData;
|
importIGToDb: DbNoteImportToDbJobData;
|
||||||
importFBToDb: DbNoteImportToDbJobData;
|
importFBToDb: DbNoteImportToDbJobData;
|
||||||
importMastoToDb: DbNoteImportToDbJobData;
|
importMastoToDb: DbNoteWithParentImportToDbJobData;
|
||||||
importPleroToDb: DbNoteImportToDbJobData;
|
importPleroToDb: DbNoteWithParentImportToDbJobData;
|
||||||
importKeyNotesToDb: DbKeyNoteImportToDbJobData;
|
importKeyNotesToDb: DbNoteWithParentImportToDbJobData;
|
||||||
importFollowing: DbUserImportJobData;
|
importFollowing: DbUserImportJobData;
|
||||||
importFollowingToDb: DbUserImportToDbJobData;
|
importFollowingToDb: DbUserImportToDbJobData;
|
||||||
importMuting: DbUserImportJobData;
|
importMuting: DbUserImportJobData;
|
||||||
|
@ -113,7 +113,7 @@ export type DbNoteImportToDbJobData = {
|
||||||
target: any;
|
target: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DbKeyNoteImportToDbJobData = {
|
export type DbNoteWithParentImportToDbJobData = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
target: any;
|
target: any;
|
||||||
note: MiNote['id'] | null;
|
note: MiNote['id'] | null;
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const meta = {
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
max: 5,
|
max: 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["notes"],
|
tags: ['notes'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
|
@ -23,99 +23,99 @@ export const meta = {
|
||||||
max: 300,
|
max: 300,
|
||||||
},
|
},
|
||||||
|
|
||||||
kind: "write:notes",
|
kind: 'write:notes',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: "object",
|
type: 'object',
|
||||||
optional: false,
|
optional: false,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
properties: {
|
properties: {
|
||||||
createdNote: {
|
createdNote: {
|
||||||
type: "object",
|
type: 'object',
|
||||||
optional: false,
|
optional: false,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
ref: "Note",
|
ref: 'Note',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchRenoteTarget: {
|
noSuchRenoteTarget: {
|
||||||
message: "No such renote target.",
|
message: 'No such renote target.',
|
||||||
code: "NO_SUCH_RENOTE_TARGET",
|
code: 'NO_SUCH_RENOTE_TARGET',
|
||||||
id: "b5c90186-4ab0-49c8-9bba-a1f76c282ba4",
|
id: 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotReRenote: {
|
cannotReRenote: {
|
||||||
message: "You can not Renote a pure Renote.",
|
message: 'You can not Renote a pure Renote.',
|
||||||
code: "CANNOT_RENOTE_TO_A_PURE_RENOTE",
|
code: 'CANNOT_RENOTE_TO_A_PURE_RENOTE',
|
||||||
id: "fd4cc33e-2a37-48dd-99cc-9b806eb2031a",
|
id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a',
|
||||||
},
|
},
|
||||||
|
|
||||||
noSuchReplyTarget: {
|
noSuchReplyTarget: {
|
||||||
message: "No such reply target.",
|
message: 'No such reply target.',
|
||||||
code: "NO_SUCH_REPLY_TARGET",
|
code: 'NO_SUCH_REPLY_TARGET',
|
||||||
id: "749ee0f6-d3da-459a-bf02-282e2da4292c",
|
id: '749ee0f6-d3da-459a-bf02-282e2da4292c',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotReplyToPureRenote: {
|
cannotReplyToPureRenote: {
|
||||||
message: "You can not reply to a pure Renote.",
|
message: 'You can not reply to a pure Renote.',
|
||||||
code: "CANNOT_REPLY_TO_A_PURE_RENOTE",
|
code: 'CANNOT_REPLY_TO_A_PURE_RENOTE',
|
||||||
id: "3ac74a84-8fd5-4bb0-870f-01804f82ce15",
|
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotCreateAlreadyExpiredPoll: {
|
cannotCreateAlreadyExpiredPoll: {
|
||||||
message: "Poll is already expired.",
|
message: 'Poll is already expired.',
|
||||||
code: "CANNOT_CREATE_ALREADY_EXPIRED_POLL",
|
code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
|
||||||
id: "04da457d-b083-4055-9082-955525eda5a5",
|
id: '04da457d-b083-4055-9082-955525eda5a5',
|
||||||
},
|
},
|
||||||
|
|
||||||
noSuchChannel: {
|
noSuchChannel: {
|
||||||
message: "No such channel.",
|
message: 'No such channel.',
|
||||||
code: "NO_SUCH_CHANNEL",
|
code: 'NO_SUCH_CHANNEL',
|
||||||
id: "b1653923-5453-4edc-b786-7c4f39bb0bbb",
|
id: 'b1653923-5453-4edc-b786-7c4f39bb0bbb',
|
||||||
},
|
},
|
||||||
|
|
||||||
youHaveBeenBlocked: {
|
youHaveBeenBlocked: {
|
||||||
message: "You have been blocked by this user.",
|
message: 'You have been blocked by this user.',
|
||||||
code: "YOU_HAVE_BEEN_BLOCKED",
|
code: 'YOU_HAVE_BEEN_BLOCKED',
|
||||||
id: "b390d7e1-8a5e-46ed-b625-06271cafd3d3",
|
id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3',
|
||||||
},
|
},
|
||||||
|
|
||||||
accountLocked: {
|
accountLocked: {
|
||||||
message: "You migrated. Your account is now locked.",
|
message: 'You migrated. Your account is now locked.',
|
||||||
code: "ACCOUNT_LOCKED",
|
code: 'ACCOUNT_LOCKED',
|
||||||
id: "d390d7e1-8a5e-46ed-b625-06271cafd3d3",
|
id: 'd390d7e1-8a5e-46ed-b625-06271cafd3d3',
|
||||||
},
|
},
|
||||||
|
|
||||||
needsEditId: {
|
needsEditId: {
|
||||||
message: "You need to specify `editId`.",
|
message: 'You need to specify `editId`.',
|
||||||
code: "NEEDS_EDIT_ID",
|
code: 'NEEDS_EDIT_ID',
|
||||||
id: "d697edc8-8c73-4de8-bded-35fd198b79e5",
|
id: 'd697edc8-8c73-4de8-bded-35fd198b79e5',
|
||||||
},
|
},
|
||||||
|
|
||||||
noSuchNote: {
|
noSuchNote: {
|
||||||
message: "No such note.",
|
message: 'No such note.',
|
||||||
code: "NO_SUCH_NOTE",
|
code: 'NO_SUCH_NOTE',
|
||||||
id: "eef6c173-3010-4a23-8674-7c4fcaeba719",
|
id: 'eef6c173-3010-4a23-8674-7c4fcaeba719',
|
||||||
},
|
},
|
||||||
|
|
||||||
youAreNotTheAuthor: {
|
youAreNotTheAuthor: {
|
||||||
message: "You are not the author of this note.",
|
message: 'You are not the author of this note.',
|
||||||
code: "YOU_ARE_NOT_THE_AUTHOR",
|
code: 'YOU_ARE_NOT_THE_AUTHOR',
|
||||||
id: "c6e61685-411d-43d0-b90a-a448d2539001",
|
id: 'c6e61685-411d-43d0-b90a-a448d2539001',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotPrivateRenote: {
|
cannotPrivateRenote: {
|
||||||
message: "You can not perform a private renote.",
|
message: 'You can not perform a private renote.',
|
||||||
code: "CANNOT_PRIVATE_RENOTE",
|
code: 'CANNOT_PRIVATE_RENOTE',
|
||||||
id: "19a50f1c-84fa-4e33-81d3-17834ccc0ad8",
|
id: '19a50f1c-84fa-4e33-81d3-17834ccc0ad8',
|
||||||
},
|
},
|
||||||
|
|
||||||
notLocalUser: {
|
notLocalUser: {
|
||||||
message: "You are not a local user.",
|
message: 'You are not a local user.',
|
||||||
code: "NOT_LOCAL_USER",
|
code: 'NOT_LOCAL_USER',
|
||||||
id: "b907f407-2aa0-4283-800b-a2c56290b822",
|
id: 'b907f407-2aa0-4283-800b-a2c56290b822',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotRenoteOutsideOfChannel: {
|
cannotRenoteOutsideOfChannel: {
|
||||||
|
@ -127,60 +127,63 @@ export const meta = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
type: "object",
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
editId: { type: "string", format: "misskey:id" },
|
editId: { type: 'string', format: 'misskey:id' },
|
||||||
visibility: { type: "string", enum: ['public', 'home', 'followers', 'specified'], default: "public" },
|
visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: 'public' },
|
||||||
visibleUserIds: {
|
visibleUserIds: {
|
||||||
type: "array",
|
type: 'array',
|
||||||
uniqueItems: true,
|
uniqueItems: true,
|
||||||
items: {
|
items: {
|
||||||
type: "string",
|
type: 'string',
|
||||||
format: "misskey:id",
|
format: 'misskey:id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
text: { type: "string", maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true },
|
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 250 },
|
||||||
cw: { type: "string", nullable: true, minLength: 1, maxLength: 250 },
|
localOnly: { type: 'boolean', default: false },
|
||||||
localOnly: { type: "boolean", default: false },
|
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
||||||
noExtractMentions: { type: "boolean", default: false },
|
noExtractMentions: { type: 'boolean', default: false },
|
||||||
noExtractHashtags: { type: "boolean", default: false },
|
noExtractHashtags: { type: 'boolean', default: false },
|
||||||
noExtractEmojis: { type: "boolean", default: false },
|
noExtractEmojis: { type: 'boolean', default: false },
|
||||||
|
replyId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
|
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
|
channelId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
|
text: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: MAX_NOTE_TEXT_LENGTH,
|
||||||
|
nullable: true,
|
||||||
|
},
|
||||||
fileIds: {
|
fileIds: {
|
||||||
type: "array",
|
type: 'array',
|
||||||
uniqueItems: true,
|
uniqueItems: true,
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: { type: "string", format: "misskey:id" },
|
items: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
mediaIds: {
|
mediaIds: {
|
||||||
deprecated: true,
|
type: 'array',
|
||||||
description:
|
|
||||||
"Use `fileIds` instead. If both are specified, this property is discarded.",
|
|
||||||
type: "array",
|
|
||||||
uniqueItems: true,
|
uniqueItems: true,
|
||||||
minItems: 1,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: { type: "string", format: "misskey:id" },
|
items: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
replyId: { type: "string", format: "misskey:id", nullable: true },
|
|
||||||
renoteId: { type: "string", format: "misskey:id", nullable: true },
|
|
||||||
channelId: { type: "string", format: "misskey:id", nullable: true },
|
|
||||||
poll: {
|
poll: {
|
||||||
type: "object",
|
type: 'object',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
properties: {
|
properties: {
|
||||||
choices: {
|
choices: {
|
||||||
type: "array",
|
type: 'array',
|
||||||
uniqueItems: true,
|
uniqueItems: true,
|
||||||
minItems: 2,
|
minItems: 2,
|
||||||
maxItems: 10,
|
maxItems: 10,
|
||||||
items: { type: "string", minLength: 1, maxLength: 50 },
|
items: { type: 'string', minLength: 1, maxLength: 50 },
|
||||||
},
|
},
|
||||||
multiple: { type: "boolean", default: false },
|
multiple: { type: 'boolean' },
|
||||||
expiresAt: { type: "integer", nullable: true },
|
expiresAt: { type: 'integer', nullable: true },
|
||||||
expiredAfter: { type: "integer", nullable: true, minimum: 1 },
|
expiredAfter: { type: 'integer', nullable: true, minimum: 1 },
|
||||||
},
|
},
|
||||||
required: ["choices"],
|
required: ['choices'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
anyOf: [
|
anyOf: [
|
||||||
|
@ -188,32 +191,32 @@ export const paramDef = {
|
||||||
// (re)note with text, files and poll are optional
|
// (re)note with text, files and poll are optional
|
||||||
properties: {
|
properties: {
|
||||||
text: {
|
text: {
|
||||||
type: "string",
|
type: 'string',
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
maxLength: MAX_NOTE_TEXT_LENGTH,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: ["text"],
|
required: ['text'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// (re)note with files, text and poll are optional
|
// (re)note with files, text and poll are optional
|
||||||
required: ["fileIds"],
|
required: ['fileIds'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// (re)note with files, text and poll are optional
|
// (re)note with files, text and poll are optional
|
||||||
required: ["mediaIds"],
|
required: ['mediaIds'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// (re)note with poll, text and files are optional
|
// (re)note with poll, text and files are optional
|
||||||
properties: {
|
properties: {
|
||||||
poll: { type: "object", nullable: false },
|
poll: { type: 'object', nullable: false },
|
||||||
},
|
},
|
||||||
required: ["poll"],
|
required: ['poll'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// pure renote
|
// pure renote
|
||||||
required: ["renoteId"],
|
required: ['renoteId'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -139,7 +139,9 @@ export class ClientServerService {
|
||||||
'type': 'image/png',
|
'type': 'image/png',
|
||||||
'purpose': 'maskable',
|
'purpose': 'maskable',
|
||||||
}, {
|
}, {
|
||||||
'src': '/static-assets/splash.png',
|
// 空文字列の場合右辺を使いたいため
|
||||||
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||||
|
'src': instance.app512IconUrl || '/static-assets/icons/512.png',
|
||||||
'sizes': '300x300',
|
'sizes': '300x300',
|
||||||
'type': 'image/png',
|
'type': 'image/png',
|
||||||
'purpose': 'any',
|
'purpose': 'any',
|
||||||
|
|
|
@ -39,9 +39,7 @@ export async function mainBoot() {
|
||||||
|
|
||||||
let reloadDialogShowing = false;
|
let reloadDialogShowing = false;
|
||||||
stream.on('_disconnected_', async () => {
|
stream.on('_disconnected_', async () => {
|
||||||
if (defaultStore.state.serverDisconnectedBehavior === 'reload') {
|
if (defaultStore.state.serverDisconnectedBehavior === 'dialog') {
|
||||||
location.reload();
|
|
||||||
} else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') {
|
|
||||||
if (reloadDialogShowing) return;
|
if (reloadDialogShowing) return;
|
||||||
reloadDialogShowing = true;
|
reloadDialogShowing = true;
|
||||||
const { canceled } = await confirm({
|
const { canceled } = await confirm({
|
||||||
|
|
|
@ -57,6 +57,48 @@ const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.root + .root {
|
||||||
|
position: relative;
|
||||||
|
margin-inline: -20px 0;
|
||||||
|
box-shadow: -4px 0 0 var(--panel), -15px 0 15px var(--panel);
|
||||||
|
overflow: clip;
|
||||||
|
isolation: isolate;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: var(--panel);
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: var(--panel);
|
||||||
|
z-index: -1;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 3em;
|
||||||
|
mask: linear-gradient(to right, #000 20%, rgba(0, 0, 0, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .root {
|
||||||
|
margin-inline: -10px 0;
|
||||||
|
padding-inline-end: 0;
|
||||||
|
box-shadow: -4px 0 0 var(--panel);
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
|
|
|
@ -127,9 +127,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
ref="quoteButton"
|
ref="quoteButton"
|
||||||
:class="$style.footerButton"
|
:class="$style.footerButton"
|
||||||
class="_button"
|
class="_button"
|
||||||
:style="quoted ? 'color: var(--accent) !important;' : ''"
|
|
||||||
v-on:click.stop
|
v-on:click.stop
|
||||||
@mousedown="quoted ? undoQuote(appearNote) : quote()"
|
@mousedown="quote()"
|
||||||
>
|
>
|
||||||
<i class="ph-quotes ph-bold ph-lg"></i>
|
<i class="ph-quotes ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -226,7 +225,10 @@ const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', nul
|
||||||
let note = $ref(deepClone(props.note));
|
let note = $ref(deepClone(props.note));
|
||||||
|
|
||||||
function noteclick(id: string) {
|
function noteclick(id: string) {
|
||||||
|
const selection = document.getSelection();
|
||||||
|
if (selection?.toString().length === 0) {
|
||||||
router.push(`/notes/${id}`);
|
router.push(`/notes/${id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// plugin
|
// plugin
|
||||||
|
@ -278,14 +280,13 @@ const isLong = shouldCollapsed(appearNote, urls ?? []);
|
||||||
const collapsed = ref(appearNote.cw == null && isLong);
|
const collapsed = ref(appearNote.cw == null && isLong);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const renoted = ref(false);
|
const renoted = ref(false);
|
||||||
const quoted = ref(false);
|
|
||||||
const muted = ref($i ? checkWordMute(appearNote, $i, $i.mutedWords) : false);
|
const muted = ref($i ? checkWordMute(appearNote, $i, $i.mutedWords) : false);
|
||||||
const translation = ref<any>(null);
|
const translation = ref<any>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
||||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || (appearNote.visibility === 'followers' && appearNote.userId === $i.id));
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || (appearNote.visibility === 'followers' && appearNote.userId === $i.id));
|
||||||
let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null)));
|
let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null)));
|
||||||
const defaultLike = computed(() => defaultStore.state.like !== '❤️' ? defaultStore.state.like : null);
|
const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null);
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
'r': () => reply(true),
|
'r': () => reply(true),
|
||||||
|
@ -364,15 +365,6 @@ if (!props.mock) {
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
renoted.value = res.length > 0;
|
renoted.value = res.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
os.api("notes/renotes", {
|
|
||||||
noteId: appearNote.id,
|
|
||||||
userId: $i.id,
|
|
||||||
limit: 1,
|
|
||||||
quote: true,
|
|
||||||
}).then((res) => {
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +459,6 @@ function quote() {
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
os.toast(i18n.ts.quoted);
|
os.toast(i18n.ts.quoted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -490,7 +481,6 @@ function quote() {
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
os.toast(i18n.ts.quoted);
|
os.toast(i18n.ts.quoted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -603,26 +593,6 @@ function undoRenote(note) : void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undoQuote(note) : void {
|
|
||||||
if (props.mock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
os.api("notes/unrenote", {
|
|
||||||
noteId: note.id,
|
|
||||||
quote: true
|
|
||||||
});
|
|
||||||
os.toast(i18n.ts.rmquote);
|
|
||||||
quoted.value = false;
|
|
||||||
|
|
||||||
const el = quoteButton.value as HTMLElement | null | undefined;
|
|
||||||
if (el) {
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onContextmenu(ev: MouseEvent): void {
|
function onContextmenu(ev: MouseEvent): void {
|
||||||
if (props.mock) {
|
if (props.mock) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -137,8 +137,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
ref="quoteButton"
|
ref="quoteButton"
|
||||||
class="_button"
|
class="_button"
|
||||||
:class="$style.noteFooterButton"
|
:class="$style.noteFooterButton"
|
||||||
:style="quoted ? 'color: var(--accent) !important;' : ''"
|
@mousedown="quote()"
|
||||||
@mousedown="quoted ? undoQuote() : quote()"
|
|
||||||
>
|
>
|
||||||
<i class="ph-quotes ph-bold ph-lg"></i>
|
<i class="ph-quotes ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -310,7 +309,6 @@ const isMyRenote = $i && ($i.id === note.userId);
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const renoted = ref(false);
|
const renoted = ref(false);
|
||||||
const quoted = ref(false);
|
|
||||||
const muted = ref($i ? checkWordMute(appearNote, $i, $i.mutedWords) : false);
|
const muted = ref($i ? checkWordMute(appearNote, $i, $i.mutedWords) : false);
|
||||||
const translation = ref(null);
|
const translation = ref(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
|
@ -323,7 +321,7 @@ const conversation = ref<Misskey.entities.Note[]>([]);
|
||||||
const replies = ref<Misskey.entities.Note[]>([]);
|
const replies = ref<Misskey.entities.Note[]>([]);
|
||||||
const quotes = ref<Misskey.entities.Note[]>([]);
|
const quotes = ref<Misskey.entities.Note[]>([]);
|
||||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id);
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id);
|
||||||
const defaultLike = computed(() => defaultStore.state.like !== '❤️' ? defaultStore.state.like : null);
|
const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null);
|
||||||
|
|
||||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||||
|
@ -337,15 +335,6 @@ if ($i) {
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
renoted.value = res.length > 0;
|
renoted.value = res.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
os.api("notes/renotes", {
|
|
||||||
noteId: appearNote.id,
|
|
||||||
userId: $i.id,
|
|
||||||
limit: 1,
|
|
||||||
quote: true,
|
|
||||||
}).then((res) => {
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
|
@ -511,7 +500,6 @@ function quote() {
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
os.toast(i18n.ts.quoted);
|
os.toast(i18n.ts.quoted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -534,7 +522,6 @@ function quote() {
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
os.toast(i18n.ts.quoted);
|
os.toast(i18n.ts.quoted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -625,23 +612,6 @@ function undoRenote() : void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undoQuote() : void {
|
|
||||||
os.api("notes/unrenote", {
|
|
||||||
noteId: appearNote.id,
|
|
||||||
quote: true
|
|
||||||
});
|
|
||||||
os.toast(i18n.ts.rmquote);
|
|
||||||
quoted.value = false;
|
|
||||||
|
|
||||||
const el = quoteButton.value as HTMLElement | null | undefined;
|
|
||||||
if (el) {
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onContextmenu(ev: MouseEvent): void {
|
function onContextmenu(ev: MouseEvent): void {
|
||||||
const isLink = (el: HTMLElement) => {
|
const isLink = (el: HTMLElement) => {
|
||||||
if (el.tagName === 'A') return true;
|
if (el.tagName === 'A') return true;
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div>
|
<div>
|
||||||
<p v-if="note.cw != null" :class="$style.cw">
|
<p v-if="note.cw != null" :class="$style.cw">
|
||||||
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/>
|
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/>
|
||||||
<MkCwButton v-model="showContent" :note="note"/>
|
<MkCwButton v-model="showContent" :note="note" v-on:click.stop/>
|
||||||
</p>
|
</p>
|
||||||
<div v-show="note.cw == null || showContent">
|
<div v-show="note.cw == null || showContent">
|
||||||
<MkSubNoteContent :hideFiles="hideFiles" :class="$style.text" :note="note"/>
|
<MkSubNoteContent :hideFiles="hideFiles" :class="$style.text" :note="note"/>
|
||||||
|
|
|
@ -41,8 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
ref="quoteButton"
|
ref="quoteButton"
|
||||||
class="_button"
|
class="_button"
|
||||||
:class="$style.noteFooterButton"
|
:class="$style.noteFooterButton"
|
||||||
:style="quoted ? 'color: var(--accent) !important;' : ''"
|
@mousedown="quote()"
|
||||||
@mousedown="quoted ? undoQuote() : quote()"
|
|
||||||
>
|
>
|
||||||
<i class="ph-quotes ph-bold ph-lg"></i>
|
<i class="ph-quotes ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -125,7 +124,6 @@ const translation = ref<any>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const renoted = ref(false);
|
const renoted = ref(false);
|
||||||
const quoted = ref(false);
|
|
||||||
const reactButton = shallowRef<HTMLElement>();
|
const reactButton = shallowRef<HTMLElement>();
|
||||||
const renoteButton = shallowRef<HTMLElement>();
|
const renoteButton = shallowRef<HTMLElement>();
|
||||||
const quoteButton = shallowRef<HTMLElement>();
|
const quoteButton = shallowRef<HTMLElement>();
|
||||||
|
@ -133,7 +131,7 @@ const menuButton = shallowRef<HTMLElement>();
|
||||||
const likeButton = shallowRef<HTMLElement>();
|
const likeButton = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
let appearNote = $computed(() => isRenote ? props.note.renote as Misskey.entities.Note : props.note);
|
let appearNote = $computed(() => isRenote ? props.note.renote as Misskey.entities.Note : props.note);
|
||||||
const defaultLike = computed(() => defaultStore.state.like !== '❤️' ? defaultStore.state.like : null);
|
const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null);
|
||||||
|
|
||||||
const isRenote = (
|
const isRenote = (
|
||||||
props.note.renote != null &&
|
props.note.renote != null &&
|
||||||
|
@ -156,15 +154,6 @@ if ($i) {
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
renoted.value = res.length > 0;
|
renoted.value = res.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
os.api("notes/renotes", {
|
|
||||||
noteId: appearNote.id,
|
|
||||||
userId: $i.id,
|
|
||||||
limit: 1,
|
|
||||||
quote: true,
|
|
||||||
}).then((res) => {
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
|
@ -255,23 +244,6 @@ function undoRenote() : void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undoQuote() : void {
|
|
||||||
os.api("notes/unrenote", {
|
|
||||||
noteId: appearNote.id,
|
|
||||||
quote: true
|
|
||||||
});
|
|
||||||
os.toast(i18n.ts.rmquote);
|
|
||||||
quoted.value = false;
|
|
||||||
|
|
||||||
const el = quoteButton.value as HTMLElement | null | undefined;
|
|
||||||
if (el) {
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let showContent = $ref(false);
|
let showContent = $ref(false);
|
||||||
|
|
||||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||||
|
@ -342,7 +314,6 @@ function quote() {
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
os.toast(i18n.ts.quoted);
|
os.toast(i18n.ts.quoted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -365,7 +336,6 @@ function quote() {
|
||||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
quoted.value = res.length > 0;
|
|
||||||
os.toast(i18n.ts.quoted);
|
os.toast(i18n.ts.quoted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</ul>
|
</ul>
|
||||||
<p v-if="!readOnly" :class="$style.info">
|
<p v-if="!readOnly" :class="$style.info">
|
||||||
<span>{{ i18n.t('_poll.totalVotes', { n: total }) }}</span>
|
<span>{{ i18n.t('_poll.totalVotes', { n: total }) }}</span>
|
||||||
|
<span v-if="note.poll.multiple"> · </span>
|
||||||
|
<span v-if="note.poll.multiple">{{ i18n.ts._poll.multiple }}</span>
|
||||||
<span> · </span>
|
<span> · </span>
|
||||||
<a v-if="!closed && !isVoted" style="color: inherit;" @click="showResult = !showResult">{{ showResult ? i18n.ts._poll.vote : i18n.ts._poll.showResult }}</a>
|
<a v-if="!closed && !isVoted" style="color: inherit;" @click="showResult = !showResult">{{ showResult ? i18n.ts._poll.vote : i18n.ts._poll.showResult }}</a>
|
||||||
<span v-if="isVoted">{{ i18n.ts._poll.voted }}</span>
|
<span v-if="isVoted">{{ i18n.ts._poll.voted }}</span>
|
||||||
|
@ -78,12 +80,19 @@ const vote = async (id) => {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
|
|
||||||
if (props.readOnly || closed.value || isVoted.value) return;
|
if (props.readOnly || closed.value || isVoted.value) return;
|
||||||
|
if (!props.note.poll.multiple) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.t('voteConfirm', { choice: props.note.poll.choices[id].text }),
|
text: i18n.t('voteConfirm', { choice: props.note.poll.choices[id].text }),
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
} else {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'question',
|
||||||
|
text: i18n.t('voteConfirmMulti', { choice: props.note.poll.choices[id].text }),
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
}
|
||||||
|
|
||||||
await os.api('notes/polls/vote', {
|
await os.api('notes/polls/vote', {
|
||||||
noteId: props.note.id,
|
noteId: props.note.id,
|
||||||
|
|
|
@ -931,8 +931,8 @@ onMounted(() => {
|
||||||
poll = {
|
poll = {
|
||||||
choices: init.poll.choices.map(x => x.text),
|
choices: init.poll.choices.map(x => x.text),
|
||||||
multiple: init.poll.multiple,
|
multiple: init.poll.multiple,
|
||||||
expiresAt: init.poll.expiresAt,
|
expiresAt: init.poll.expiresAt ? new Date(init.poll.expiresAt).getTime().toString() : null,
|
||||||
expiredAfter: init.poll.expiredAfter,
|
expiredAfter: init.poll.expiredAfter ? new Date(init.poll.expiredAfter).getTime().toString() : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
visibility = init.visibility;
|
visibility = init.visibility;
|
||||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkLoading v-if="translating" mini/>
|
<MkLoading v-if="translating" mini/>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
||||||
<Mfm :text="translation.text" :author="note.user" :nyaize="'account'" :emojiUrls="note.emojis"/>
|
<Mfm :text="translation.text" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`" v-on:click.stop>RN: ...</MkA>
|
<MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`" v-on:click.stop>RN: ...</MkA>
|
||||||
|
@ -63,7 +63,10 @@ const props = defineProps<{
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
function noteclick(id: string) {
|
function noteclick(id: string) {
|
||||||
|
const selection = document.getSelection();
|
||||||
|
if (selection?.toString().length === 0) {
|
||||||
router.push(`/notes/${id}`);
|
router.push(`/notes/${id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsed = $computed(() => props.note.text ? mfm.parse(props.note.text) : null);
|
const parsed = $computed(() => props.note.text ? mfm.parse(props.note.text) : null);
|
||||||
|
|
|
@ -28,9 +28,20 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.username"><MkAcct :user="user"/></div>
|
<div :class="$style.username"><MkAcct :user="user"/></div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.description">
|
<div :class="$style.description">
|
||||||
<Mfm v-if="user.description" :class="$style.mfm" :text="user.description" :author="user"/>
|
<Mfm v-if="user.description" :nyaize="false" :class="$style.mfm" :text="user.description" :author="user"/>
|
||||||
<div v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</div>
|
<div v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="user.fields.length > 0" :class="$style.fields">
|
||||||
|
<dl v-for="(field, i) in user.fields" :key="i" :class="$style.field">
|
||||||
|
<dt :class="$style.fieldname">
|
||||||
|
<Mfm :text="field.name" :nyaize="false" :plain="true" :colored="false"/>
|
||||||
|
</dt>
|
||||||
|
<dd :class="$style.fieldvalue">
|
||||||
|
<Mfm :text="field.value" :nyaize="false" :author="user" :colored="false"/>
|
||||||
|
<i v-if="user.verifiedLinks.includes(field.value)" v-tooltip:dialog="i18n.ts.verifiedLink" class="ph-seal-check ph-bold ph-lg" :class="$style.verifiedLink"></i>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
<div :class="$style.status">
|
<div :class="$style.status">
|
||||||
<div :class="$style.statusItem">
|
<div :class="$style.statusItem">
|
||||||
<div :class="$style.statusItemLabel">{{ i18n.ts.notes }}</div>
|
<div :class="$style.statusItemLabel">{{ i18n.ts.notes }}</div>
|
||||||
|
@ -221,6 +232,48 @@ onMounted(() => {
|
||||||
border-bottom: solid 1px var(--divider);
|
border-bottom: solid 1px var(--divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fields {
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding: 16px;
|
||||||
|
border-top: solid 1px var(--divider);
|
||||||
|
border-bottom: solid 1px var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(span) {
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldvalue {
|
||||||
|
width: 70%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-wrap: nowrap;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldname {
|
||||||
|
width: 100px;
|
||||||
|
max-height: 45px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
padding-inline-end: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.mfm {
|
.mfm {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: 5;
|
-webkit-line-clamp: 5;
|
||||||
|
|
|
@ -65,6 +65,13 @@ const props = defineProps<{
|
||||||
edit: boolean;
|
edit: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
// This will not be available for now as I don't think this is needed
|
||||||
|
// const notesSearchAvailable = (($i == null && instance.policies.canSearchNotes) || ($i != null && $i.policies.canSearchNotes));
|
||||||
|
/* if (!notesSearchAvailable) {
|
||||||
|
const wid = widgetDefs.findIndex(widget => widget === 'search');
|
||||||
|
widgetDefs.splice(wid, 1);
|
||||||
|
} */
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'updateWidgets', widgets: Widget[]): void;
|
(ev: 'updateWidgets', widgets: Widget[]): void;
|
||||||
(ev: 'addWidget', widget: Widget): void;
|
(ev: 'addWidget', widget: Widget): void;
|
||||||
|
|
30
packages/frontend/src/components/SkSearchResultWindow.vue
Normal file
30
packages/frontend/src/components/SkSearchResultWindow.vue
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<MkWindow ref="window" :initialWidth="600" :initialHeight="450" :canResize="true" @closed="emit('closed')">
|
||||||
|
<template #header>
|
||||||
|
<i class="ph-magnifying-glass ph-bold ph-lg" style="margin-right: 0.5em;"></i>
|
||||||
|
<b>Result</b>
|
||||||
|
</template>
|
||||||
|
<MkNotes :key="props.noteKey" :pagination="props.notePagination"/>
|
||||||
|
</MkWindow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { } from 'vue';
|
||||||
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
|
import MkWindow from '@/components/MkWindow.vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
noteKey: string | number | symbol | undefined;
|
||||||
|
notePagination: Paging;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(ev: 'closed'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
|
||||||
|
</style>
|
|
@ -82,7 +82,13 @@ export default function(props: MfmProps) {
|
||||||
res.push(t);
|
res.push(t);
|
||||||
}
|
}
|
||||||
res.shift();
|
res.shift();
|
||||||
|
|
||||||
|
// Don't wrap whitespaces in a span
|
||||||
|
if (text === ' ') {
|
||||||
return res;
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h('span', res);
|
||||||
} else {
|
} else {
|
||||||
return [text.replace(/\n/g, ' ')];
|
return [text.replace(/\n/g, ' ')];
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,7 @@ onUnmounted(() => {
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.animate {
|
&.animate {
|
||||||
|
|
|
@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<FromSlot>
|
<FromSlot>
|
||||||
<template #label>Default like emoji</template>
|
<template #label>{{ i18n.ts.defaultLike }}</template>
|
||||||
<MkCustomEmoji v-if="defaultLike.startsWith(':')" style="max-height: 3em; font-size: 1.1em;" :useOriginalSize="false" :class="$style.reaction" :name="defaultLike" :normal="true" :noStyle="true"/>
|
<MkCustomEmoji v-if="defaultLike.startsWith(':')" style="max-height: 3em; font-size: 1.1em;" :useOriginalSize="false" :class="$style.reaction" :name="defaultLike" :normal="true" :noStyle="true"/>
|
||||||
<MkEmoji v-else :emoji="defaultLike" style="max-height: 3em; font-size: 1.1em;" :normal="true" :noStyle="true"/>
|
<MkEmoji v-else :emoji="defaultLike" style="max-height: 3em; font-size: 1.1em;" :normal="true" :noStyle="true"/>
|
||||||
<MkButton rounded :small="true" @click="chooseNewLike"><i class="ph-smiley ph-bold ph-lg"></i> Change</MkButton>
|
<MkButton rounded :small="true" @click="chooseNewLike"><i class="ph-smiley ph-bold ph-lg"></i> Change</MkButton>
|
||||||
|
|
|
@ -166,7 +166,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<MkSelect v-model="serverDisconnectedBehavior">
|
<MkSelect v-model="serverDisconnectedBehavior">
|
||||||
<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
|
<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
|
||||||
<option value="reload">{{ i18n.ts._serverDisconnectedBehavior.reload }}</option>
|
|
||||||
<option value="dialog">{{ i18n.ts._serverDisconnectedBehavior.dialog }}</option>
|
<option value="dialog">{{ i18n.ts._serverDisconnectedBehavior.dialog }}</option>
|
||||||
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
|
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
|
||||||
<option value="disabled">{{ i18n.ts._serverDisconnectedBehavior.disabled }}</option>
|
<option value="disabled">{{ i18n.ts._serverDisconnectedBehavior.disabled }}</option>
|
||||||
|
|
|
@ -24,9 +24,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</FromSlot>
|
</FromSlot>
|
||||||
|
|
||||||
<FromSlot>
|
<FromSlot>
|
||||||
<template #label>Default like emoji</template>
|
<template #label>{{ i18n.ts.defaultLike }}</template>
|
||||||
<MkCustomEmoji v-if="like.startsWith(':')" style="max-height: 3em; font-size: 1.1em;" :useOriginalSize="false" :class="$style.reaction" :name="like" :normal="true" :noStyle="true"/>
|
<MkCustomEmoji v-if="like && like.startsWith(':')" style="max-height: 3em; font-size: 1.1em;" :useOriginalSize="false" :class="$style.reaction" :name="like" :normal="true" :noStyle="true"/>
|
||||||
<MkEmoji v-else :emoji="like" style="max-height: 3em; font-size: 1.1em;" :normal="true" :noStyle="true"/>
|
<MkEmoji v-else-if="like && !like.startsWith(':')" :emoji="like" style="max-height: 3em; font-size: 1.1em;" :normal="true" :noStyle="true"/>
|
||||||
|
<span v-else-if="!like">{{ i18n.ts.notSet }}</span>
|
||||||
<div class="_buttons" style="padding-top: 8px;">
|
<div class="_buttons" style="padding-top: 8px;">
|
||||||
<MkButton rounded :small="true" inline @click="chooseNewLike"><i class="ph-smiley ph-bold ph-lg"></i> Change</MkButton>
|
<MkButton rounded :small="true" inline @click="chooseNewLike"><i class="ph-smiley ph-bold ph-lg"></i> Change</MkButton>
|
||||||
<MkButton rounded :small="true" inline @click="resetLike"><i class="ph-arrow-clockwise ph-bold ph-lg"></i> Reset</MkButton>
|
<MkButton rounded :small="true" inline @click="resetLike"><i class="ph-arrow-clockwise ph-bold ph-lg"></i> Reset</MkButton>
|
||||||
|
@ -82,6 +83,7 @@ import { defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
|
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
|
|
||||||
let reactions = $ref(deepClone(defaultStore.state.reactions));
|
let reactions = $ref(deepClone(defaultStore.state.reactions));
|
||||||
const like = $computed(defaultStore.makeGetterSetter('like'));
|
const like = $computed(defaultStore.makeGetterSetter('like'));
|
||||||
|
@ -91,6 +93,16 @@ const reactionPickerWidth = $computed(defaultStore.makeGetterSetter('reactionPic
|
||||||
const reactionPickerHeight = $computed(defaultStore.makeGetterSetter('reactionPickerHeight'));
|
const reactionPickerHeight = $computed(defaultStore.makeGetterSetter('reactionPickerHeight'));
|
||||||
const reactionPickerUseDrawerForMobile = $computed(defaultStore.makeGetterSetter('reactionPickerUseDrawerForMobile'));
|
const reactionPickerUseDrawerForMobile = $computed(defaultStore.makeGetterSetter('reactionPickerUseDrawerForMobile'));
|
||||||
|
|
||||||
|
async function reloadAsk() {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'info',
|
||||||
|
text: i18n.ts.reloadToApplySetting,
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
unisonReload();
|
||||||
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
defaultStore.set('reactions', reactions);
|
defaultStore.set('reactions', reactions);
|
||||||
}
|
}
|
||||||
|
@ -134,13 +146,15 @@ function chooseEmoji(ev: MouseEvent) {
|
||||||
function chooseNewLike(ev: MouseEvent) {
|
function chooseNewLike(ev: MouseEvent) {
|
||||||
os.pickEmoji(ev.currentTarget ?? ev.target, {
|
os.pickEmoji(ev.currentTarget ?? ev.target, {
|
||||||
showPinned: false,
|
showPinned: false,
|
||||||
}).then(emoji => {
|
}).then(async emoji => {
|
||||||
defaultStore.set('like', emoji as string);
|
defaultStore.set('like', emoji as string);
|
||||||
|
await reloadAsk();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetLike() {
|
async function resetLike() {
|
||||||
defaultStore.set('like', '❤️');
|
defaultStore.set('like', null);
|
||||||
|
await reloadAsk();
|
||||||
}
|
}
|
||||||
|
|
||||||
watch($$(reactions), () => {
|
watch($$(reactions), () => {
|
||||||
|
|
|
@ -176,7 +176,13 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router
|
||||||
const canonical = user.host === null ? `@${user.username}` : `@${user.username}@${toUnicode(user.host)}`;
|
const canonical = user.host === null ? `@${user.username}` : `@${user.username}@${toUnicode(user.host)}`;
|
||||||
copyToClipboard(`${url}/${canonical}`);
|
copyToClipboard(`${url}/${canonical}`);
|
||||||
},
|
},
|
||||||
}, {
|
}, ...(user.host ? [{
|
||||||
|
icon: 'ph-share ph-bold ph-lg',
|
||||||
|
text: i18n.ts.openRemoteProfile,
|
||||||
|
action: () => {
|
||||||
|
open(`${user.uri}`, '_blank');
|
||||||
|
},
|
||||||
|
}] : []), {
|
||||||
icon: 'ph-envelope ph-bold ph-lg',
|
icon: 'ph-envelope ph-bold ph-lg',
|
||||||
text: i18n.ts.sendMessage,
|
text: i18n.ts.sendMessage,
|
||||||
action: () => {
|
action: () => {
|
||||||
|
|
|
@ -112,7 +112,7 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
},
|
},
|
||||||
like: {
|
like: {
|
||||||
where: 'account',
|
where: 'account',
|
||||||
default: '❤️',
|
default: null as string | null,
|
||||||
},
|
},
|
||||||
mutedAds: {
|
mutedAds: {
|
||||||
where: 'account',
|
where: 'account',
|
||||||
|
@ -188,7 +188,7 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
},
|
},
|
||||||
serverDisconnectedBehavior: {
|
serverDisconnectedBehavior: {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
default: 'quiet' as 'quiet' | 'reload' | 'dialog' | 'disabled',
|
default: 'disabled' as 'quiet' | 'dialog' | 'disabled',
|
||||||
},
|
},
|
||||||
nsfw: {
|
nsfw: {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
|
|
|
@ -109,7 +109,8 @@ watch(defaultStore.reactiveState.menuDisplay, () => {
|
||||||
$nav-icon-only-width: 78px; // TODO: どこかに集約したい
|
$nav-icon-only-width: 78px; // TODO: どこかに集約したい
|
||||||
$avatar-size: 32px;
|
$avatar-size: 32px;
|
||||||
$avatar-margin: 8px;
|
$avatar-margin: 8px;
|
||||||
|
position: sticky;
|
||||||
|
top: 16px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 260px;
|
width: 260px;
|
||||||
|
|
|
@ -253,9 +253,13 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
> .widgets {
|
> .widgets {
|
||||||
//--panelBorder: none;
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
padding-bottom: calc(var(--margin) + env(safe-area-inset-bottom, 0px));
|
height: 100%;
|
||||||
|
padding-top: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
@media (max-width: $widgets-hide-threshold) {
|
@media (max-width: $widgets-hide-threshold) {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -324,7 +324,7 @@ $widgets-hide-threshold: 1090px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: unset;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
155
packages/frontend/src/widgets/WidgetSearch.vue
Normal file
155
packages/frontend/src/widgets/WidgetSearch.vue
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<MkContainer :showHeader="widgetProps.showHeader" class="skw-search">
|
||||||
|
<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @keydown="onInputKeydown">
|
||||||
|
<template #suffix>
|
||||||
|
<button style="border: none; background: none; margin-right: 0.5em; z-index: 2; pointer-events: auto; position: relative; margin-top: 0 auto;" @click="options"><i class="ph-funnel ph-bold ph-lg"></i></button>
|
||||||
|
<button style="border: none; background: none; z-index: 2; pointer-events: auto; position: relative; margin: 0 auto;" @click="search"><i class="ph-magnifying-glass ph-bold ph-lg"></i></button>
|
||||||
|
</template>
|
||||||
|
</MkInput>
|
||||||
|
</MkContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, defineAsyncComponent, onMounted } from 'vue';
|
||||||
|
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
|
||||||
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
import MkContainer from '@/components/MkContainer.vue';
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
import { useRouter } from '@/router.js';
|
||||||
|
import { GetFormResultType } from '@/scripts/form.js';
|
||||||
|
|
||||||
|
const name = 'search';
|
||||||
|
|
||||||
|
const widgetPropsDef = {
|
||||||
|
showHeader: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
|
||||||
|
|
||||||
|
const props = defineProps<WidgetComponentProps<WidgetProps>>();
|
||||||
|
const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
|
||||||
|
|
||||||
|
const { widgetProps, configure } = useWidgetPropsManager(name,
|
||||||
|
widgetPropsDef,
|
||||||
|
props,
|
||||||
|
emit,
|
||||||
|
);
|
||||||
|
|
||||||
|
function onInputKeydown(evt: KeyboardEvent) {
|
||||||
|
if (evt.key === 'Enter') {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
search();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
let key = $ref(0);
|
||||||
|
let searchQuery = $ref('');
|
||||||
|
let notePagination = $ref();
|
||||||
|
let searchOrigin = $ref('combined');
|
||||||
|
let user = $ref(null);
|
||||||
|
let isLocalOnly = $ref(false);
|
||||||
|
let order = $ref(true);
|
||||||
|
let filetype = $ref(null);
|
||||||
|
|
||||||
|
function options(ev) {
|
||||||
|
os.popupMenu([{
|
||||||
|
type: 'parent',
|
||||||
|
text: 'With File',
|
||||||
|
icon: 'ph-file ph-bold ph-lg',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'ph-image ph-bold ph-lg',
|
||||||
|
text: 'With Images',
|
||||||
|
action: () => {
|
||||||
|
filetype = 'image';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'ph-music-notes-simple ph-bold ph-lg',
|
||||||
|
text: 'With Audios',
|
||||||
|
action: () => {
|
||||||
|
filetype = 'audio';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'ph-video ph-bold ph-lg',
|
||||||
|
text: 'With Videos',
|
||||||
|
action: () => {
|
||||||
|
filetype = 'video';
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
}], ev.currentTarget ?? ev.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectUser() {
|
||||||
|
os.selectUser().then(_user => {
|
||||||
|
user = _user;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function search() {
|
||||||
|
const query = searchQuery.toString().trim();
|
||||||
|
|
||||||
|
if (query == null || query === '') return;
|
||||||
|
|
||||||
|
if (query.startsWith('https://')) {
|
||||||
|
const promise = os.api('ap/show', {
|
||||||
|
uri: query,
|
||||||
|
});
|
||||||
|
|
||||||
|
os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
|
||||||
|
|
||||||
|
const res = await promise;
|
||||||
|
|
||||||
|
if (res.type === 'User') {
|
||||||
|
router.push(`/@${res.object.username}@${res.object.host}`);
|
||||||
|
} else if (res.type === 'Note') {
|
||||||
|
router.push(`/notes/${res.object.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notePagination = {
|
||||||
|
endpoint: 'notes/search',
|
||||||
|
limit: 10,
|
||||||
|
params: {
|
||||||
|
query: searchQuery,
|
||||||
|
userId: user ? user.id : null,
|
||||||
|
order: order ? 'desc' : 'asc',
|
||||||
|
filetype: filetype,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLocalOnly) notePagination.params.host = '.';
|
||||||
|
|
||||||
|
key++;
|
||||||
|
|
||||||
|
os.popup(defineAsyncComponent(() => import('@/components/SkSearchResultWindow.vue')), {
|
||||||
|
noteKey: key,
|
||||||
|
notePagination: notePagination,
|
||||||
|
}, {
|
||||||
|
}, 'closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose<WidgetComponentExpose>({
|
||||||
|
name,
|
||||||
|
configure,
|
||||||
|
id: props.widget ? props.widget.id : null,
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -33,6 +33,7 @@ export default function(app: App) {
|
||||||
app.component('WidgetAichan', defineAsyncComponent(() => import('./WidgetAichan.vue')));
|
app.component('WidgetAichan', defineAsyncComponent(() => import('./WidgetAichan.vue')));
|
||||||
app.component('WidgetUserList', defineAsyncComponent(() => import('./WidgetUserList.vue')));
|
app.component('WidgetUserList', defineAsyncComponent(() => import('./WidgetUserList.vue')));
|
||||||
app.component('WidgetClicker', defineAsyncComponent(() => import('./WidgetClicker.vue')));
|
app.component('WidgetClicker', defineAsyncComponent(() => import('./WidgetClicker.vue')));
|
||||||
|
app.component('WidgetSearch', defineAsyncComponent(() => import('./WidgetSearch.vue')));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const widgets = [
|
export const widgets = [
|
||||||
|
@ -63,4 +64,5 @@ export const widgets = [
|
||||||
'aichan',
|
'aichan',
|
||||||
'userList',
|
'userList',
|
||||||
'clicker',
|
'clicker',
|
||||||
|
'search',
|
||||||
];
|
];
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
"@types/parse-link-header": "^2.0.3",
|
"@types/parse-link-header": "^2.0.3",
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/ws": "^8.5.10",
|
||||||
"axios": "1.5.0",
|
"axios": "1.6.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"https-proxy-agent": "^7.0.2",
|
"https-proxy-agent": "^7.0.2",
|
||||||
|
|
|
@ -217,6 +217,7 @@ export type Note = {
|
||||||
clippedCount?: number;
|
clippedCount?: number;
|
||||||
poll?: {
|
poll?: {
|
||||||
expiresAt: DateString | null;
|
expiresAt: DateString | null;
|
||||||
|
expiredAfter: DateString | null;
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
choices: {
|
choices: {
|
||||||
isVoted: boolean;
|
isVoted: boolean;
|
||||||
|
|
145
pnpm-lock.yaml
145
pnpm-lock.yaml
|
@ -1034,8 +1034,8 @@ importers:
|
||||||
specifier: ^8.5.10
|
specifier: ^8.5.10
|
||||||
version: 8.5.10
|
version: 8.5.10
|
||||||
axios:
|
axios:
|
||||||
specifier: 1.5.0
|
specifier: 1.6.0
|
||||||
version: 1.5.0
|
version: 1.6.0
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.10
|
specifier: ^1.11.10
|
||||||
version: 1.11.10
|
version: 1.11.10
|
||||||
|
@ -2285,15 +2285,6 @@ packages:
|
||||||
'@babel/helper-plugin-utils': 7.22.5
|
'@babel/helper-plugin-utils': 7.22.5
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.11):
|
|
||||||
resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
|
|
||||||
peerDependencies:
|
|
||||||
'@babel/core': ^7.0.0-0
|
|
||||||
dependencies:
|
|
||||||
'@babel/core': 7.22.11
|
|
||||||
'@babel/helper-plugin-utils': 7.22.5
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.3):
|
/@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.3):
|
||||||
resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
|
resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -7294,7 +7285,7 @@ packages:
|
||||||
ts-dedent: 2.2.0
|
ts-dedent: 2.2.0
|
||||||
type-fest: 2.19.0
|
type-fest: 2.19.0
|
||||||
vue: 3.3.8(typescript@5.2.2)
|
vue: 3.3.8(typescript@5.2.2)
|
||||||
vue-component-type-helpers: 1.8.22
|
vue-component-type-helpers: 1.8.24
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -7940,10 +7931,6 @@ packages:
|
||||||
'@types/unist': 2.0.6
|
'@types/unist': 2.0.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/http-cache-semantics@4.0.1:
|
|
||||||
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/http-cache-semantics@4.0.4:
|
/@types/http-cache-semantics@4.0.4:
|
||||||
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
||||||
|
|
||||||
|
@ -9198,7 +9185,7 @@ packages:
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
delegates: 1.0.0
|
delegates: 1.0.0
|
||||||
readable-stream: 3.6.0
|
readable-stream: 3.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/arg@5.0.2:
|
/arg@5.0.2:
|
||||||
|
@ -9470,8 +9457,8 @@ packages:
|
||||||
- debug
|
- debug
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/axios@1.5.0:
|
/axios@1.6.0:
|
||||||
resolution: {integrity: sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==}
|
resolution: {integrity: sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.3(debug@4.3.4)
|
follow-redirects: 1.15.3(debug@4.3.4)
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
|
@ -9501,24 +9488,6 @@ packages:
|
||||||
'@babel/core': 7.22.11
|
'@babel/core': 7.22.11
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/babel-jest@29.7.0(@babel/core@7.22.11):
|
|
||||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
'@babel/core': ^7.8.0
|
|
||||||
dependencies:
|
|
||||||
'@babel/core': 7.22.11
|
|
||||||
'@jest/transform': 29.7.0
|
|
||||||
'@types/babel__core': 7.20.0
|
|
||||||
babel-plugin-istanbul: 6.1.1
|
|
||||||
babel-preset-jest: 29.6.3(@babel/core@7.22.11)
|
|
||||||
chalk: 4.1.2
|
|
||||||
graceful-fs: 4.2.11
|
|
||||||
slash: 3.0.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/babel-jest@29.7.0(@babel/core@7.23.3):
|
/babel-jest@29.7.0(@babel/core@7.23.3):
|
||||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -9596,26 +9565,6 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.11):
|
|
||||||
resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
|
|
||||||
peerDependencies:
|
|
||||||
'@babel/core': ^7.0.0
|
|
||||||
dependencies:
|
|
||||||
'@babel/core': 7.22.11
|
|
||||||
'@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11)
|
|
||||||
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.11)
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.3):
|
/babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.3):
|
||||||
resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
|
resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -9636,17 +9585,6 @@ packages:
|
||||||
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.3)
|
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.3)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/babel-preset-jest@29.6.3(@babel/core@7.22.11):
|
|
||||||
resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
|
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
'@babel/core': ^7.0.0
|
|
||||||
dependencies:
|
|
||||||
'@babel/core': 7.22.11
|
|
||||||
babel-plugin-jest-hoist: 29.6.3
|
|
||||||
babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.11)
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/babel-preset-jest@29.6.3(@babel/core@7.23.3):
|
/babel-preset-jest@29.6.3(@babel/core@7.23.3):
|
||||||
resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
|
resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -9725,7 +9663,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer: 5.7.1
|
buffer: 5.7.1
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 3.6.0
|
readable-stream: 3.6.2
|
||||||
|
|
||||||
/blob-util@2.0.2:
|
/blob-util@2.0.2:
|
||||||
resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
|
resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
|
||||||
|
@ -9992,10 +9930,10 @@ packages:
|
||||||
resolution: {integrity: sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==}
|
resolution: {integrity: sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==}
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/http-cache-semantics': 4.0.1
|
'@types/http-cache-semantics': 4.0.4
|
||||||
get-stream: 6.0.1
|
get-stream: 6.0.1
|
||||||
http-cache-semantics: 4.1.1
|
http-cache-semantics: 4.1.1
|
||||||
keyv: 4.5.2
|
keyv: 4.5.4
|
||||||
mimic-response: 4.0.0
|
mimic-response: 4.0.0
|
||||||
normalize-url: 8.0.0
|
normalize-url: 8.0.0
|
||||||
responselike: 3.0.0
|
responselike: 3.0.0
|
||||||
|
@ -10504,7 +10442,7 @@ packages:
|
||||||
crc-32: 1.2.2
|
crc-32: 1.2.2
|
||||||
crc32-stream: 5.0.0
|
crc32-stream: 5.0.0
|
||||||
normalize-path: 3.0.0
|
normalize-path: 3.0.0
|
||||||
readable-stream: 3.6.0
|
readable-stream: 3.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/compressible@2.0.18:
|
/compressible@2.0.18:
|
||||||
|
@ -10635,28 +10573,9 @@ packages:
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
crc-32: 1.2.2
|
crc-32: 1.2.2
|
||||||
readable-stream: 3.6.0
|
readable-stream: 3.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/create-jest@29.7.0:
|
|
||||||
resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
|
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
'@jest/types': 29.6.3
|
|
||||||
chalk: 4.1.2
|
|
||||||
exit: 0.1.2
|
|
||||||
graceful-fs: 4.2.11
|
|
||||||
jest-config: 29.7.0(@types/node@20.9.4)
|
|
||||||
jest-util: 29.7.0
|
|
||||||
prompts: 2.4.2
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@types/node'
|
|
||||||
- babel-plugin-macros
|
|
||||||
- supports-color
|
|
||||||
- ts-node
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/create-jest@29.7.0(@types/node@20.9.1):
|
/create-jest@29.7.0(@types/node@20.9.1):
|
||||||
resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
|
resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -11091,6 +11010,7 @@ packages:
|
||||||
/deepmerge@4.2.2:
|
/deepmerge@4.2.2:
|
||||||
resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
|
resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/deepmerge@4.3.1:
|
/deepmerge@4.3.1:
|
||||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
|
@ -11314,7 +11234,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
end-of-stream: 1.4.4
|
end-of-stream: 1.4.4
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 2.3.7
|
readable-stream: 2.3.8
|
||||||
stream-shift: 1.0.1
|
stream-shift: 1.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -13951,10 +13871,10 @@ packages:
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
create-jest: 29.7.0
|
create-jest: 29.7.0(@types/node@20.9.1)
|
||||||
exit: 0.1.2
|
exit: 0.1.2
|
||||||
import-local: 3.1.0
|
import-local: 3.1.0
|
||||||
jest-config: 29.7.0(@types/node@20.9.4)
|
jest-config: 29.7.0(@types/node@20.9.1)
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
jest-validate: 29.7.0
|
jest-validate: 29.7.0
|
||||||
yargs: 17.7.2
|
yargs: 17.7.2
|
||||||
|
@ -14005,14 +13925,14 @@ packages:
|
||||||
ts-node:
|
ts-node:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.22.11
|
'@babel/core': 7.23.3
|
||||||
'@jest/test-sequencer': 29.7.0
|
'@jest/test-sequencer': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 20.9.1
|
'@types/node': 20.9.1
|
||||||
babel-jest: 29.7.0(@babel/core@7.22.11)
|
babel-jest: 29.7.0(@babel/core@7.23.3)
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
ci-info: 3.7.1
|
ci-info: 3.9.0
|
||||||
deepmerge: 4.2.2
|
deepmerge: 4.3.1
|
||||||
glob: 7.2.3
|
glob: 7.2.3
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
jest-circus: 29.7.0
|
jest-circus: 29.7.0
|
||||||
|
@ -14741,12 +14661,6 @@ packages:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/keyv@4.5.2:
|
|
||||||
resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==}
|
|
||||||
dependencies:
|
|
||||||
json-buffer: 3.0.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/keyv@4.5.4:
|
/keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -14800,7 +14714,7 @@ packages:
|
||||||
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
|
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
|
||||||
engines: {node: '>= 0.6.3'}
|
engines: {node: '>= 0.6.3'}
|
||||||
dependencies:
|
dependencies:
|
||||||
readable-stream: 2.3.7
|
readable-stream: 2.3.8
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/leven@3.1.0:
|
/leven@3.1.0:
|
||||||
|
@ -17504,17 +17418,6 @@ packages:
|
||||||
type-fest: 0.6.0
|
type-fest: 0.6.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/readable-stream@2.3.7:
|
|
||||||
resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==}
|
|
||||||
dependencies:
|
|
||||||
core-util-is: 1.0.3
|
|
||||||
inherits: 2.0.4
|
|
||||||
isarray: 1.0.0
|
|
||||||
process-nextick-args: 2.0.1
|
|
||||||
safe-buffer: 5.1.2
|
|
||||||
string_decoder: 1.1.1
|
|
||||||
util-deprecate: 1.0.2
|
|
||||||
|
|
||||||
/readable-stream@2.3.8:
|
/readable-stream@2.3.8:
|
||||||
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -17525,7 +17428,6 @@ packages:
|
||||||
safe-buffer: 5.1.2
|
safe-buffer: 5.1.2
|
||||||
string_decoder: 1.1.1
|
string_decoder: 1.1.1
|
||||||
util-deprecate: 1.0.2
|
util-deprecate: 1.0.2
|
||||||
dev: true
|
|
||||||
|
|
||||||
/readable-stream@3.6.0:
|
/readable-stream@3.6.0:
|
||||||
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
|
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
|
||||||
|
@ -17534,6 +17436,7 @@ packages:
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
string_decoder: 1.3.0
|
string_decoder: 1.3.0
|
||||||
util-deprecate: 1.0.2
|
util-deprecate: 1.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/readable-stream@3.6.2:
|
/readable-stream@3.6.2:
|
||||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||||
|
@ -18995,7 +18898,7 @@ packages:
|
||||||
/through2@2.0.5:
|
/through2@2.0.5:
|
||||||
resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
|
resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
readable-stream: 2.3.7
|
readable-stream: 2.3.8
|
||||||
xtend: 4.0.2
|
xtend: 4.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -19956,8 +19859,8 @@ packages:
|
||||||
/vscode-textmate@8.0.0:
|
/vscode-textmate@8.0.0:
|
||||||
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
||||||
|
|
||||||
/vue-component-type-helpers@1.8.22:
|
/vue-component-type-helpers@1.8.24:
|
||||||
resolution: {integrity: sha512-LK3wJHs3vJxHG292C8cnsRusgyC5SEZDCzDCD01mdE/AoREFMl2tzLRuzwyuEsOIz13tqgBcnvysN3Lxsa14Fw==}
|
resolution: {integrity: sha512-lqWs/7fdRXoSBAlbouHBX+LNuaY6gI9xWW34m/ZIz9zVPYHEyw0b2/zaCBwlKx0NtKTeF/6pOpvrxVkh7nhIYg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vue-component-type-helpers@1.8.4:
|
/vue-component-type-helpers@1.8.4:
|
||||||
|
|
Loading…
Reference in a new issue