Compare commits

...

33 Commits

Author SHA1 Message Date
f00f5cbed1 10.29.0 2018-10-20 15:51:47 +09:00
c4e8cabae9 ファイル作成APIにforceオプションを実装 2018-10-20 15:50:13 +09:00
1729d05e8c Localized mark all as read message (#2956)
* Localized read-all message

* Fixed some weirdness:   src/client/app/init.ts

* Unfucked server api stuff (sorry lol):   src/server/api/endpoints/i/read_all_unread_notes.ts

* Clean up
2018-10-20 15:46:01 +09:00
770fb46ca7 Improve usability 2018-10-20 15:41:27 +09:00
a3c4e54bc0 🎨 2018-10-20 15:37:17 +09:00
b8a77fbada Show image info in tooltip 2018-10-20 15:21:24 +09:00
c2663529c1 Localized BSoD messages. (#2953)
* Added VSCode workspace files to :   .gitignore

* Localized Blue Screen of Death:   locales/ja-JP.yml
Localized Blue Screen of Death:   src/client/app/init.ts
2018-10-20 11:57:23 +09:00
9df74a02b6 Fix bug 2018-10-20 11:24:02 +09:00
71c9964e19 Fix bug and clean up 2018-10-20 11:19:27 +09:00
ae2e47f6a9 Merge pull request #2950 from syuilo/l10n_develop
New Crowdin translations
2018-10-20 09:45:44 +09:00
1524d35f66 New translations ja-JP.yml (English) 2018-10-20 09:41:11 +09:00
845be966a0 10.28.0 2018-10-20 09:39:56 +09:00
80818d79eb Fix bug 2018-10-20 09:38:36 +09:00
cb9b3c00dd Use router-link instead of a to improve usability 2018-10-20 09:34:34 +09:00
b3997fb5df New translations ja-JP.yml (Norwegian) 2018-10-20 09:33:07 +09:00
09dde6b78a New translations ja-JP.yml (Dutch) 2018-10-20 09:32:57 +09:00
3345d3ab35 New translations ja-JP.yml (Japanese, Kansai) 2018-10-20 09:32:51 +09:00
366be7bbdd New translations ja-JP.yml (Spanish) 2018-10-20 09:32:47 +09:00
7008ea66f8 New translations ja-JP.yml (Russian) 2018-10-20 09:32:43 +09:00
70f881e989 New translations ja-JP.yml (Portuguese) 2018-10-20 09:32:38 +09:00
94d2355089 New translations ja-JP.yml (Polish) 2018-10-20 09:32:33 +09:00
dfbe48b25b New translations ja-JP.yml (Korean) 2018-10-20 09:32:29 +09:00
931cb38b54 New translations ja-JP.yml (Italian) 2018-10-20 09:32:23 +09:00
e5fd34f94e New translations ja-JP.yml (German) 2018-10-20 09:32:17 +09:00
c638d7eb48 New translations ja-JP.yml (French) 2018-10-20 09:32:12 +09:00
7e96384618 New translations ja-JP.yml (English) 2018-10-20 09:32:08 +09:00
829cb99f5b New translations ja-JP.yml (Chinese Simplified) 2018-10-20 09:32:04 +09:00
1f93c99304 New translations ja-JP.yml (Catalan) 2018-10-20 09:32:00 +09:00
dbb7c756cd Fix bug 2018-10-20 09:31:56 +09:00
13f381710c Validate param 2018-10-20 09:31:52 +09:00
70897c0e9a 🎨 2018-10-20 09:28:48 +09:00
f51d1c5264 Fix test 2018-10-20 09:14:16 +09:00
70d0937aab Fix #2949 2018-10-20 09:03:04 +09:00
31 changed files with 163 additions and 44 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@ api-docs.json
/redis
/mongo
/elasticsearch
*.code-workspace

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "Animationen der Benutzeroberfläche reduzieren"
this-setting-is-this-device-only: "Nur auf diesem Gerät"
do-not-use-in-production: 'Dies ist eine Entwicklungsversion. Nicht in einer Produktionsumgebung verwenden.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Unentschieden"
my-turn: "Du bist am Zug"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "Reduce motion in UI"
this-setting-is-this-device-only: "Only for this device"
do-not-use-in-production: 'As this is for development, do not use this in production.'
error:
title: 'Something happened :('
retry: 'Retry'
reversi:
drawn: "Draw"
my-turn: "Your turn"
@ -747,7 +750,7 @@ desktop/views/components/settings.vue:
api-via-stream-desc: "API request is performed via the WebSocket connection instead of native fetch API (for better performance). This setting is stored in the browser."
deck-nav: "デッキ内ナビゲーション"
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
deck-default: "デッキをデフォルトのUIにする"
deck-default: "Use Deck as default UI"
display: "Design and display"
customize: "Customize home layout"
wallpaper: "Wallpaper"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'Esto está en desarrollo, no usarlo para producción.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Empatado"
my-turn: "Mi turno"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "Réduire les animations dans linterface utilisateur"
this-setting-is-this-device-only: "Uniquement sur cet appareil"
do-not-use-in-production: 'Il sagit dune version de développement. Ne pas utiliser dans un environnement de production.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Partie nulle"
my-turn: "Cest votre tour"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -25,6 +25,15 @@ common:
application-authorization: "アプリの連携"
close: "閉じる"
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
BSoD:
fatal-error: ":( 致命的な問題が発生しました。"
update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。"
error-code: "エラーコード"
browser-version: "ブラウザ バージョン"
client-version: "クライアント バージョン"
email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。"
thanks: "Thank you for using Misskey."
got-it: "わかった"
customization-tips:
title: "カスタマイズのヒント"
@ -124,6 +133,10 @@ common:
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UI、動き過ぎや、静かにしてや"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: '開発ビルドや。本番環境で使わんといて!知らんで!'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "おあいこ"
my-turn: "あんさんのターンや"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "이 장치만"
do-not-use-in-production: '이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "무승부"
my-turn: "당신의 차례입니다"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Remis"
my-turn: "Twoja kolej"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Empatado"
my-turn: "Seu turno"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.27.0",
"clientVersion": "1.0.10768",
"version": "10.29.0",
"clientVersion": "1.0.10801",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,

View File

@ -114,10 +114,9 @@ export default Vue.component('misskey-flavored-markdown', {
}
case 'mention': {
return (createElement as any)('a', {
return (createElement as any)('router-link', {
attrs: {
href: `${url}/${token.canonical}`,
target: '_blank',
to: `/${token.canonical}`,
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
style: 'color:var(--mfmMention);'
},
@ -129,10 +128,9 @@ export default Vue.component('misskey-flavored-markdown', {
}
case 'hashtag': {
return [createElement('a', {
return [createElement('router-link', {
attrs: {
href: `${url}/tags/${encodeURIComponent(token.hashtag)}`,
target: '_blank',
to: `/tags/${encodeURIComponent(token.hashtag)}`,
style: 'color:var(--mfmHashtag);'
}
}, token.content)];

View File

@ -4,9 +4,9 @@
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
<div v-if="!fetching && requestInitPromise != null">
<p>%i18n:@error%</p>
<button @click="resolveInitPromise">%i18n:@retry%</button>
<div v-if="!fetching && requestInitPromise != null" class="error">
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>
</div>
<div class="placeholder" v-if="fetching">
@ -215,6 +215,13 @@ export default Vue.extend({
> *
transition transform .3s ease, opacity .3s ease
> .error
max-width 300px
margin 0 auto
padding 16px
text-align center
color var(--text)
> .placeholder
padding 32px
opacity 0.3

View File

@ -47,14 +47,16 @@ export default Vue.extend({
mounted() {
if (this.connection) this.connection.close();
this.connection = (this as any).os.stream.connectToChannel('hashtag', this.tagTl.query);
this.connection = (this as any).os.stream.connectToChannel('hashtag', {
q: this.tagTl.query
});
this.connection.on('note', this.onNote);
this.fetch();
},
beforeDestroy() {
this.connection.close();
this.connection.dispose();
},
methods: {

View File

@ -8,9 +8,9 @@
</template>
</div>
<div v-if="!fetching && requestInitPromise != null">
<p>%i18n:@error%</p>
<button @click="resolveInitPromise">%i18n:@retry%</button>
<div v-if="!fetching && requestInitPromise != null" class="error">
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>
</div>
<!-- トランジションを有効にするとなぜかメモリリークする -->
@ -226,6 +226,13 @@ export default Vue.extend({
> *
transition transform .3s ease, opacity .3s ease
> .error
max-width 300px
margin 0 auto
padding 16px
text-align center
color var(--text)
> .placeholder
padding 16px
opacity 0.3

View File

@ -8,6 +8,7 @@
<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
<header :style="bannerStyle">
<div>
<button class="menu" @click="menu" ref="menu">%fa:ellipsis-h%</button>
<mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" class="follow"/>
<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
<span class="name">{{ user | userName }}</span>
@ -26,7 +27,12 @@
</div>
</div>
<div class="images" v-if="images.length > 0">
<router-link v-for="image in images" :style="`background-image: url(${image.thumbnailUrl})`" :key="`${image.id}:${image._note.id}`" :to="image._note | notePage"></router-link>
<router-link v-for="image in images"
:style="`background-image: url(${image.thumbnailUrl})`"
:key="`${image.id}:${image._note.id}`"
:to="image._note | notePage"
:title="`${image.name}\n${(new Date(image.createdAt)).toLocaleString()}`"
></router-link>
</div>
<div class="tl">
<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/>
@ -41,6 +47,9 @@ import parseAcct from '../../../../../../misc/acct/parse';
import XColumn from './deck.column.vue';
import XNotes from './deck.notes.vue';
import XNote from '../../components/note.vue';
import Menu from '../../../../common/views/components/menu.vue';
import MkUserListsWindow from '../../components/user-lists-window.vue';
import Ok from '../../../../common/views/components/ok.vue';
import { concat } from '../../../../../../prelude/array';
const fetchLimit = 10;
@ -161,6 +170,30 @@ export default Vue.extend({
return promise;
},
menu() {
let menu = [{
icon: '%fa:list%',
text: '%i18n:@push-to-a-list%',
action: () => {
const w = (this as any).os.new(MkUserListsWindow);
w.$once('choosen', async list => {
w.close();
await (this as any).api('users/lists/push', {
listId: list.id,
userId: this.user.id
});
(this as any).os.new(Ok);
});
}
}];
this.os.new(Menu, {
source: this.$refs.menu,
compact: false,
items: menu
});
}
}
});
</script>
@ -191,6 +224,14 @@ export default Vue.extend({
color #fff
text-align center
> .menu
position absolute
top 8px
left 8px
padding 8px
font-size 16px
text-shadow 0 0 8px #000
> .follow
position absolute
top 16px

View File

@ -9,11 +9,11 @@
</p>
</div>
<div class="action-form">
<button class="mute ui" @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id">
<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id">
<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
</button>
<button class="mute ui" @click="list">%fa:list% %i18n:@push-to-a-list%</button>
</ui-button>
<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button>
</div>
</div>
</template>

View File

@ -216,15 +216,15 @@ function panic(e) {
document.documentElement.style.background = '#1269e2';
document.body.innerHTML =
'<div id="error">'
+ '<h1>:( 致命的な問題が発生しました。</h1>'
+ '<p>お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。</p>'
+ '<h1>%i18n.common.BSoD.fatal-error%</h1>'
+ '<p>%i18n.common.BSoD.update-browser-os%</p>'
+ '<hr>'
+ `<p>エラーコード: ${e.toString()}</p>`
+ `<p>ブラウザ バージョン: ${navigator.userAgent}</p>`
+ `<p>クライアント バージョン: ${version}</p>`
+ `<p>%i18n.common.BSoD.error-code%: ${e.toString()}</p>`
+ `<p>%i18n.common.BSoD.browser-version%: ${navigator.userAgent}</p>`
+ `<p>%i18n.common.BSoD.client-version%: ${version}</p>`
+ '<hr>'
+ '<p>問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。</p>'
+ '<p>Thank you for using Misskey.</p>'
+ '<p>%i18n.common.BSoD.email-support%</p>'
+ '<p>%i18n.common.BSoD.thanks%</p>'
+ '</div>';
// TODO: Report the bug

View File

@ -244,10 +244,10 @@ export default class MiOS extends EventEmitter {
this.store.dispatch('login', me);
fetched();
} else {
this.initStream();
// Finish init
callback();
this.initStream();
}
});
}

View File

@ -9,9 +9,9 @@ export type TextElementHashtag = {
};
export default function(text: string, i: number) {
if (!(/^\s#[^\s\.,]+/.test(text) || (i == 0 && /^#[^\s\.,]+/.test(text)))) return null;
if (!(/^\s#[^\s\.,!\?]+/.test(text) || (i == 0 && /^#[^\s\.,!\?]+/.test(text)))) return null;
const isHead = text.startsWith('#');
const hashtag = text.match(/^\s?#[^\s\.,]+/)[0];
const hashtag = text.match(/^\s?#[^\s\.,!\?]+/)[0];
const res: any[] = !isHead ? [{
type: 'text',
content: text[0]

View File

@ -31,19 +31,23 @@ export const meta = {
}
}),
isSensitive: $.bool.optional.nullable.note({
default: null,
isSensitive: $.bool.optional.note({
default: false,
desc: {
'ja-JP': 'このメディアが「閲覧注意」(NSFW)かどうか',
'en-US': 'Whether this media is NSFW'
}
}),
force: $.bool.optional.note({
default: false,
desc: {
'ja-JP': 'true にすると、同じハッシュを持つファイルが既にアップロードされていても強制的にファイルを作成します。',
}
})
}
};
/**
* Create a file
*/
export default async (file: any, params: any, user: ILocalUser): Promise<any> => {
if (file == null) {
throw 'file is required';
@ -76,7 +80,7 @@ export default async (file: any, params: any, user: ILocalUser): Promise<any> =>
try {
// Create file
const driveFile = await create(user, file.path, name, null, ps.folderId, false, false, null, null, ps.isSensitive);
const driveFile = await create(user, file.path, name, null, ps.folderId, ps.force, false, null, null, ps.isSensitive);
cleanup();

View File

@ -4,7 +4,8 @@ import NoteUnread from '../../../../models/note-unread';
export const meta = {
desc: {
'ja-JP': '未読の投稿をすべて既読にします。'
'ja-JP': '未読の投稿をすべて既読にします。',
'en-US': 'Mark all messages as read.'
},
requireCredential: true,

View File

@ -15,6 +15,8 @@ export default class extends Channel {
const q: Array<string[]> = params.q;
if (q == null) return;
// Subscribe stream
this.subscriber.on('hashtag', async note => {
const matched = q.some(tags => tags.every(tag => note.tags.map((t: string) => t.toLowerCase()).includes(tag.toLowerCase())));

View File

@ -1,6 +1,5 @@
import autobind from 'autobind-decorator';
import * as websocket from 'websocket';
import * as debug from 'debug';
import User, { IUser } from '../../../models/user';
import readNotification from '../common/read-notification';
@ -12,8 +11,6 @@ import Channel from './channel';
import channels from './channels';
import { EventEmitter } from 'events';
const log = debug('misskey');
/**
* Main stream connection
*/
@ -147,7 +144,6 @@ export default class Connection {
@autobind
private onChannelConnectRequested(payload: any) {
const { channel, id, params, pong } = payload;
log(`CH CONNECT: ${id} ${channel} by @${this.user.username}`);
this.connectChannel(id, params, channel, pong);
}
@ -157,7 +153,6 @@ export default class Connection {
@autobind
private onChannelDisconnectRequested(payload: any) {
const { id } = payload;
log(`CH DISCONNECT: ${id} by @${this.user.username}`);
this.disconnectChannel(id);
}

View File

@ -122,6 +122,12 @@ describe('Text', () => {
{ type: 'hashtag', content: '#piyo', hashtag: 'piyo' },
{ type: 'text', content: '.' }
], tokens2);
const tokens3 = analyze('#Foo!');
assert.deepEqual([
{ type: 'hashtag', content: '#Foo', hashtag: 'Foo' },
{ type: 'text', content: '!' },
], tokens3);
});
it('quote', () => {