changelog conflict

This commit is contained in:
Shpuld Shpuldson 2021-02-22 18:11:27 +02:00
commit 485f4b899c
17 changed files with 235 additions and 26 deletions

View file

@ -7,11 +7,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
- Button to remove uploaded media in post status form is now properly placed and sized. - Button to remove uploaded media in post status form is now properly placed and sized.
- Fixed shoutbox not working in mobile layout - Fixed shoutbox not working in mobile layout
- Fixed some UI jumpiness when opening images particularly in chat view
### Changed ### Changed
- Display 'people voted' instead of 'votes' for multi-choice polls - Display 'people voted' instead of 'votes' for multi-choice polls
- Changed the "Timelines" link in side panel to toggle show all timeline options inside the panel - Changed the "Timelines" link in side panel to toggle show all timeline options inside the panel
- Renamed "Timeline" to "Home Timeline" to be more clear - Renamed "Timeline" to "Home Timeline" to be more clear
- Optimized chat to not get horrible performance after keeping the same chat open for a long time
### Added
- Added reason field for registration when approval is required
>>>>>>> develop
## [2.2.3] - 2021-01-18 ## [2.2.3] - 2021-01-18
### Added ### Added

View file

@ -586,6 +586,7 @@ nav {
color: var(--faint, $fallback--faint); color: var(--faint, $fallback--faint);
box-shadow: 0px 0px 4px rgba(0,0,0,.6); box-shadow: 0px 0px 4px rgba(0,0,0,.6);
box-shadow: var(--topBarShadow); box-shadow: var(--topBarShadow);
box-sizing: border-box;
} }
.fade-enter-active, .fade-leave-active { .fade-enter-active, .fade-leave-active {
@ -878,6 +879,11 @@ nav {
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
// Get rid of scrollbar on body as scrolling happens on different element
body {
overflow: hidden;
}
// Ensures the fixed position of the mobile browser bars on scroll up / down events. // Ensures the fixed position of the mobile browser bars on scroll up / down events.
// Prevents the mobile browser bars from overlapping or hiding the message posting form. // Prevents the mobile browser bars from overlapping or hiding the message posting form.
@media all and (max-width: 800px) { @media all and (max-width: 800px) {

View file

@ -51,6 +51,7 @@ const getInstanceConfig = async ({ store }) => {
const vapidPublicKey = data.pleroma.vapid_public_key const vapidPublicKey = data.pleroma.vapid_public_key
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit }) store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
if (vapidPublicKey) { if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey }) store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })

View file

@ -234,6 +234,13 @@ const Chat = {
const scrollable = this.$refs.scrollable const scrollable = this.$refs.scrollable
return scrollable && scrollable.scrollTop <= 0 return scrollable && scrollable.scrollTop <= 0
}, },
cullOlderCheck () {
window.setTimeout(() => {
if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) {
this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId)
}
}, 5000)
},
handleScroll: _.throttle(function () { handleScroll: _.throttle(function () {
if (!this.currentChat) { return } if (!this.currentChat) { return }
@ -241,6 +248,7 @@ const Chat = {
this.fetchChat({ maxId: this.currentChatMessageService.minId }) this.fetchChat({ maxId: this.currentChatMessageService.minId })
} else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { } else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) {
this.jumpToBottomButtonVisible = false this.jumpToBottomButtonVisible = false
this.cullOlderCheck()
if (this.newMessageCount > 0) { if (this.newMessageCount > 0) {
// Use a delay before marking as read to prevent situation where new messages // Use a delay before marking as read to prevent situation where new messages
// arrive just as you're leaving the view and messages that you didn't actually // arrive just as you're leaving the view and messages that you didn't actually

View file

@ -73,11 +73,21 @@
} }
} }
@keyframes media-fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal-image { .modal-image {
max-width: 90%; max-width: 90%;
max-height: 90%; max-height: 90%;
box-shadow: 0px 5px 15px 0 rgba(0, 0, 0, 0.5); box-shadow: 0px 5px 15px 0 rgba(0, 0, 0, 0.5);
image-orientation: from-image; // NOTE: only FF supports this image-orientation: from-image; // NOTE: only FF supports this
animation: 0.1s cubic-bezier(0.7, 0, 1, 0.6) media-fadein;
} }
.modal-view-button-arrow { .modal-view-button-arrow {

View file

@ -151,6 +151,7 @@
border: none; border: none;
box-shadow: none; box-shadow: none;
background-color: transparent; background-color: transparent;
padding-right: 0.75em;
} }
} }

View file

@ -10,7 +10,8 @@ const registration = {
fullname: '', fullname: '',
username: '', username: '',
password: '', password: '',
confirm: '' confirm: '',
reason: ''
}, },
captcha: {} captcha: {}
}), }),
@ -24,7 +25,8 @@ const registration = {
confirm: { confirm: {
required, required,
sameAsPassword: sameAs('password') sameAsPassword: sameAs('password')
} },
reason: { required: requiredIf(() => this.accountApprovalRequired) }
} }
} }
}, },
@ -38,7 +40,10 @@ const registration = {
computed: { computed: {
token () { return this.$route.params.token }, token () { return this.$route.params.token },
bioPlaceholder () { bioPlaceholder () {
return this.$t('registration.bio_placeholder').replace(/\s*\n\s*/g, ' \n') return this.replaceNewlines(this.$t('registration.bio_placeholder'))
},
reasonPlaceholder () {
return this.replaceNewlines(this.$t('registration.reason_placeholder'))
}, },
...mapState({ ...mapState({
registrationOpen: (state) => state.instance.registrationOpen, registrationOpen: (state) => state.instance.registrationOpen,
@ -46,7 +51,8 @@ const registration = {
isPending: (state) => state.users.signUpPending, isPending: (state) => state.users.signUpPending,
serverValidationErrors: (state) => state.users.signUpErrors, serverValidationErrors: (state) => state.users.signUpErrors,
termsOfService: (state) => state.instance.tos, termsOfService: (state) => state.instance.tos,
accountActivationRequired: (state) => state.instance.accountActivationRequired accountActivationRequired: (state) => state.instance.accountActivationRequired,
accountApprovalRequired: (state) => state.instance.accountApprovalRequired
}) })
}, },
methods: { methods: {
@ -73,6 +79,9 @@ const registration = {
}, },
setCaptcha () { setCaptcha () {
this.getCaptcha().then(cpt => { this.captcha = cpt }) this.getCaptcha().then(cpt => { this.captcha = cpt })
},
replaceNewlines (str) {
return str.replace(/\s*\n\s*/g, ' \n')
} }
} }
} }

View file

@ -162,6 +162,23 @@
</ul> </ul>
</div> </div>
<div
v-if="accountApprovalRequired"
class="form-group"
>
<label
class="form--label"
for="reason"
>{{ $t('registration.reason') }}</label>
<textarea
id="reason"
v-model="user.reason"
:disabled="isPending"
class="form-control"
:placeholder="reasonPlaceholder"
/>
</div>
<div <div
v-if="captcha.type != 'none'" v-if="captcha.type != 'none'"
id="captcha-group" id="captcha-group"

View file

@ -229,6 +229,8 @@
"username_placeholder": "e.g. lain", "username_placeholder": "e.g. lain",
"fullname_placeholder": "e.g. Lain Iwakura", "fullname_placeholder": "e.g. Lain Iwakura",
"bio_placeholder": "e.g.\nHi, I'm Lain.\nIm an anime girl living in suburban Japan. You may know me from the Wired.", "bio_placeholder": "e.g.\nHi, I'm Lain.\nIm an anime girl living in suburban Japan. You may know me from the Wired.",
"reason": "Reason to register",
"reason_placeholder": "This instance approves registrations manually.\nLet the administration know why you want to register.",
"validations": { "validations": {
"username_required": "cannot be left blank", "username_required": "cannot be left blank",
"fullname_required": "cannot be left blank", "fullname_required": "cannot be left blank",

View file

@ -35,7 +35,11 @@
"retry": "Reprovi", "retry": "Reprovi",
"error_retry": "Bonvolu reprovi", "error_retry": "Bonvolu reprovi",
"loading": "Enlegante…", "loading": "Enlegante…",
"peek": "Antaŭmontri" "peek": "Antaŭmontri",
"role": {
"moderator": "Reguligisto",
"admin": "Administranto"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "Tondi bildon", "crop_picture": "Tondi bildon",
@ -365,7 +369,8 @@
"post": "Afiŝoj/Priskriboj de uzantoj", "post": "Afiŝoj/Priskriboj de uzantoj",
"alert_neutral": "Neŭtrala", "alert_neutral": "Neŭtrala",
"alert_warning": "Averto", "alert_warning": "Averto",
"toggled": "Ŝaltita" "toggled": "Ŝaltita",
"wallpaper": "Fonbildo"
}, },
"radii": { "radii": {
"_tab_label": "Rondeco" "_tab_label": "Rondeco"
@ -516,7 +521,9 @@
"mute_import_error": "Eraris enporto de silentigoj", "mute_import_error": "Eraris enporto de silentigoj",
"mute_import": "Enporto de silentigoj", "mute_import": "Enporto de silentigoj",
"mute_export_button": "Elportu viajn silentigojn al CSV-dosiero", "mute_export_button": "Elportu viajn silentigojn al CSV-dosiero",
"mute_export": "Elporto de silentigoj" "mute_export": "Elporto de silentigoj",
"hide_wallpaper": "Kaŝi fonbildon de nodo",
"setting_changed": "Agordo malsamas de la implicita"
}, },
"timeline": { "timeline": {
"collapse": "Maletendi", "collapse": "Maletendi",
@ -586,7 +593,8 @@
"show_repeats": "Montri ripetojn", "show_repeats": "Montri ripetojn",
"hide_repeats": "Kaŝi ripetojn", "hide_repeats": "Kaŝi ripetojn",
"unsubscribe": "Ne ricevi sciigojn", "unsubscribe": "Ne ricevi sciigojn",
"subscribe": "Ricevi sciigojn" "subscribe": "Ricevi sciigojn",
"bot": "Roboto"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Historio de uzanto", "timeline_title": "Historio de uzanto",
@ -612,7 +620,8 @@
"error": { "error": {
"base": "Alŝuto malsukcesis.", "base": "Alŝuto malsukcesis.",
"file_too_big": "Dosiero estas tro granda [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "file_too_big": "Dosiero estas tro granda [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Reprovu pli poste" "default": "Reprovu pli poste",
"message": "Malsukcesis alŝuto: {0}"
}, },
"file_size_units": { "file_size_units": {
"B": "B", "B": "B",
@ -645,7 +654,9 @@
"votes": "voĉoj", "votes": "voĉoj",
"option": "Elekteblo", "option": "Elekteblo",
"add_option": "Aldoni elekteblon", "add_option": "Aldoni elekteblon",
"add_poll": "Aldoni enketon" "add_poll": "Aldoni enketon",
"votes_count": "{count} voĉdono | {count} voĉdonoj",
"people_voted_count": "{count} persono voĉdonis | {count} personoj voĉdonis"
}, },
"importer": { "importer": {
"error": "Eraris enporto de ĉi tiu dosiero.", "error": "Eraris enporto de ĉi tiu dosiero.",
@ -732,7 +743,9 @@
"repeats": "Ripetoj", "repeats": "Ripetoj",
"favorites": "Ŝatoj", "favorites": "Ŝatoj",
"status_deleted": "Ĉi tiu afiŝo foriĝis", "status_deleted": "Ĉi tiu afiŝo foriĝis",
"nsfw": "Konsterna" "nsfw": "Konsterna",
"expand": "Etendi",
"external_source": "Ekstera fonto"
}, },
"time": { "time": {
"years_short": "{0}j", "years_short": "{0}j",

View file

@ -584,7 +584,9 @@
"fullname_placeholder": "es. Lupo Lucio", "fullname_placeholder": "es. Lupo Lucio",
"username_placeholder": "es. mister_wolf", "username_placeholder": "es. mister_wolf",
"new_captcha": "Clicca l'immagine per avere un altro captcha", "new_captcha": "Clicca l'immagine per avere un altro captcha",
"captcha": "CAPTCHA" "captcha": "CAPTCHA",
"reason_placeholder": "L'amministratore esamina ciascuna richiesta.\nFornisci il motivo della tua iscrizione.",
"reason": "Motivo dell'iscrizione"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Sequenza dell'Utente", "timeline_title": "Sequenza dell'Utente",

View file

@ -201,7 +201,9 @@
"password_required": "必須", "password_required": "必須",
"password_confirmation_required": "必須", "password_confirmation_required": "必須",
"password_confirmation_match": "パスワードが違います" "password_confirmation_match": "パスワードが違います"
} },
"reason_placeholder": "このインスタンスは、新規登録を手動で受け付けています。\n登録したい理由を、インスタンスの管理者に教えてください。",
"reason": "登録するための目的"
}, },
"selectable_list": { "selectable_list": {
"select_all": "すべて選択" "select_all": "すべて選択"

View file

@ -35,7 +35,11 @@
"retry": "다시 시도하십시오", "retry": "다시 시도하십시오",
"error_retry": "다시 시도하십시오", "error_retry": "다시 시도하십시오",
"generic_error": "잘못되었습니다", "generic_error": "잘못되었습니다",
"more": "더 보기" "more": "더 보기",
"role": {
"moderator": "중재자",
"admin": "관리자"
}
}, },
"login": { "login": {
"login": "로그인", "login": "로그인",
@ -85,7 +89,8 @@
"repeated_you": "당신의 게시물을 리핏", "repeated_you": "당신의 게시물을 리핏",
"no_more_notifications": "알림이 없습니다", "no_more_notifications": "알림이 없습니다",
"migrated_to": "이사했습니다", "migrated_to": "이사했습니다",
"reacted_with": "{0} 로 반응했습니다" "reacted_with": "{0} 로 반응했습니다",
"error": "알림 불러오기 실패: {0}"
}, },
"post_status": { "post_status": {
"new_status": "새 게시물 게시", "new_status": "새 게시물 게시",
@ -93,7 +98,10 @@
"account_not_locked_warning_link": "잠김", "account_not_locked_warning_link": "잠김",
"attachments_sensitive": "첨부물을 민감함으로 설정", "attachments_sensitive": "첨부물을 민감함으로 설정",
"content_type": { "content_type": {
"text/plain": "평문" "text/plain": "평문",
"text/bbcode": "BBCode",
"text/markdown": "Markdown",
"text/html": "HTML"
}, },
"content_warning": "주제 (필수 아님)", "content_warning": "주제 (필수 아님)",
"default": "인천공항에 도착했습니다.", "default": "인천공항에 도착했습니다.",
@ -106,7 +114,13 @@
"unlisted": "비공개 - 공개 타임라인에 게시 안 함" "unlisted": "비공개 - 공개 타임라인에 게시 안 함"
}, },
"preview_empty": "아무것도 없습니다", "preview_empty": "아무것도 없습니다",
"preview": "미리보기" "preview": "미리보기",
"scope_notice": {
"public": "이 글은 누구나 볼 수 있습니다"
},
"media_description_error": "파일을 올리지 못하였습니다. 다시한번 시도하여 주십시오",
"empty_status_error": "글을 입력하십시오",
"media_description": "첨부파일 설명"
}, },
"registration": { "registration": {
"bio": "소개", "bio": "소개",
@ -288,7 +302,16 @@
"borders": "테두리", "borders": "테두리",
"buttons": "버튼", "buttons": "버튼",
"inputs": "입력칸", "inputs": "입력칸",
"faint_text": "흐려진 텍스트" "faint_text": "흐려진 텍스트",
"chat": {
"border": "경계선",
"outgoing": "송신",
"incoming": "수신"
},
"selectedMenu": "선택된 메뉴 요소",
"selectedPost": "선택된 글",
"icons": "아이콘",
"alert_warning": "경고"
}, },
"radii": { "radii": {
"_tab_label": "둥글기" "_tab_label": "둥글기"
@ -364,9 +387,25 @@
"generate_new_recovery_codes": "새로운 복구 코드를 작성", "generate_new_recovery_codes": "새로운 복구 코드를 작성",
"title": "2단계인증", "title": "2단계인증",
"confirm_and_enable": "OTP 확인과 활성화", "confirm_and_enable": "OTP 확인과 활성화",
"setup_otp": "OTP 설치" "setup_otp": "OTP 설치",
"otp": "OTP"
}, },
"security": "보안" "security": "보안",
"emoji_reactions_on_timeline": "이모지 반응을 타임라인으로 표시",
"avatar_size_instruction": "크기를 150x150 이상으로 설정할 것을 추장합니다.",
"blocks_tab": "차단",
"notification_setting_privacy": "보안",
"user_mutes": "사용자",
"notification_visibility_emoji_reactions": "반응",
"profile_fields": {
"value": "내용"
},
"mutes_and_blocks": "침묵과 차단",
"chatMessageRadius": "챗 메시지",
"change_email": "전자메일 주소 바꾸기",
"changed_email": "메일주소가 갱신되었습니다!",
"bot": "이 계정은 bot입니다",
"mutes_tab": "침묵"
}, },
"timeline": { "timeline": {
"collapse": "접기", "collapse": "접기",
@ -445,7 +484,11 @@
"votes": "표", "votes": "표",
"vote": "투표", "vote": "투표",
"type": "투표 형식", "type": "투표 형식",
"expiry": "투표 기간" "expiry": "투표 기간",
"votes_count": "{count} 표 | {count} 표",
"people_voted_count": "{count} 명 투표 | {count} 명 투표",
"option": "선택지",
"add_option": "선택지 추가"
}, },
"media_modal": { "media_modal": {
"next": "다음", "next": "다음",
@ -500,5 +543,44 @@
}, },
"federation": "연합" "federation": "연합"
} }
},
"shoutbox": {
"title": "Shoutbox"
},
"time": {
"years_short": "{0} 년",
"year_short": "{0} 년",
"years": "{0} 년",
"year": "{0} 년",
"weeks_short": "{0} 주일",
"week_short": "{0} 주일",
"weeks": "{0} 주일",
"week": "{0} 주일",
"seconds_short": "{0} 초",
"second_short": "{0} 초",
"seconds": "{0} 초",
"second": "{0} 초",
"now_short": "방금",
"now": "방끔",
"months_short": "{0} 달 전",
"month_short": "{0} 달 전",
"months": "{0} 달 전",
"month": "{0} 달 전",
"minutes_short": "{0} 분",
"minute_short": "{0} 분",
"minutes": "{0} 분",
"minute": "{0} 분",
"in_past": "{0} 전",
"hours_short": "{0} 시간",
"hour_short": "{0} 시간",
"hours": "{0} 시간",
"hour": "{0} 시간",
"days_short": "{0} 일",
"day_short": "{0} 일",
"days": "{0} 일",
"day": "{0} 일"
},
"remote_user_resolver": {
"error": "찾을 수 없습니다."
} }
} }

View file

@ -39,7 +39,11 @@
"close": "关闭", "close": "关闭",
"retry": "重试", "retry": "重试",
"error_retry": "请重试", "error_retry": "请重试",
"loading": "载入中…" "loading": "载入中…",
"role": {
"moderator": "监察员",
"admin": "管理员"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "裁剪图片", "crop_picture": "裁剪图片",
@ -120,7 +124,9 @@
"expiry": "投票期限", "expiry": "投票期限",
"expires_in": "投票于 {0} 后结束", "expires_in": "投票于 {0} 后结束",
"expired": "投票 {0} 前已结束", "expired": "投票 {0} 前已结束",
"not_enough_options": "投票的选项太少" "not_enough_options": "投票的选项太少",
"votes_count": "{count} 票 | {count} 票",
"people_voted_count": "{count} 人已投票 | {count} 人已投票"
}, },
"stickers": { "stickers": {
"add_sticker": "添加贴纸" "add_sticker": "添加贴纸"
@ -183,7 +189,9 @@
"password_required": "不能留空", "password_required": "不能留空",
"password_confirmation_required": "不能留空", "password_confirmation_required": "不能留空",
"password_confirmation_match": "密码不一致" "password_confirmation_match": "密码不一致"
} },
"reason_placeholder": "此实例的注册需要手动批准。\n请让管理员知道您为什么想要注册。",
"reason": "注册理由"
}, },
"selectable_list": { "selectable_list": {
"select_all": "选择全部" "select_all": "选择全部"
@ -552,7 +560,8 @@
"mute_import": "隐藏名单导入", "mute_import": "隐藏名单导入",
"mute_export_button": "导出你的隐藏名单到一个 csv 文件", "mute_export_button": "导出你的隐藏名单到一个 csv 文件",
"mute_export": "隐藏名单导出", "mute_export": "隐藏名单导出",
"hide_wallpaper": "隐藏实例壁纸" "hide_wallpaper": "隐藏实例壁纸",
"setting_changed": "与默认设置不同"
}, },
"time": { "time": {
"day": "{0} 天", "day": "{0} 天",
@ -683,7 +692,8 @@
"show_repeats": "显示转发", "show_repeats": "显示转发",
"hide_repeats": "隐藏转发", "hide_repeats": "隐藏转发",
"message": "消息", "message": "消息",
"mention": "提及" "mention": "提及",
"bot": "机器人"
}, },
"user_profile": { "user_profile": {
"timeline_title": "用户时间线", "timeline_title": "用户时间线",

View file

@ -115,6 +115,9 @@ const chats = {
}, },
handleMessageError ({ commit }, value) { handleMessageError ({ commit }, value) {
commit('handleMessageError', { commit, ...value }) commit('handleMessageError', { commit, ...value })
},
cullOlderMessages ({ commit }, chatId) {
commit('cullOlderMessages', chatId)
} }
}, },
mutations: { mutations: {
@ -227,6 +230,9 @@ const chats = {
handleMessageError (state, { chatId, fakeId, isRetry }) { handleMessageError (state, { chatId, fakeId, isRetry }) {
const chatMessageService = state.openedChatMessageServices[chatId] const chatMessageService = state.openedChatMessageServices[chatId]
chatService.handleMessageError(chatMessageService, fakeId, isRetry) chatService.handleMessageError(chatMessageService, fakeId, isRetry)
},
cullOlderMessages (state, chatId) {
chatService.cullOlderMessages(state.openedChatMessageServices[chatId])
} }
} }
} }

View file

@ -48,6 +48,22 @@ const deleteMessage = (storage, messageId) => {
} }
} }
const cullOlderMessages = (storage) => {
const maxIndex = storage.messages.length
const minIndex = maxIndex - 50
if (maxIndex <= 50) return
storage.messages = _.sortBy(storage.messages, ['id'])
storage.minId = storage.messages[minIndex].id
for (const message of storage.messages) {
if (message.id < storage.minId) {
delete storage.idIndex[message.id]
delete storage.idempotencyKeyIndex[message.idempotency_key]
}
}
storage.messages = storage.messages.slice(minIndex, maxIndex)
}
const handleMessageError = (storage, fakeId, isRetry) => { const handleMessageError = (storage, fakeId, isRetry) => {
if (!storage) { return } if (!storage) { return }
const fakeMessage = storage.idIndex[fakeId] const fakeMessage = storage.idIndex[fakeId]
@ -201,6 +217,7 @@ const ChatService = {
empty, empty,
getView, getView,
deleteMessage, deleteMessage,
cullOlderMessages,
resetNewMessageCount, resetNewMessageCount,
clear, clear,
handleMessageError handleMessageError

View file

@ -88,4 +88,21 @@ describe('chatService', () => {
expect(view.map(i => i.type)).to.eql(['date', 'message', 'message', 'date', 'message']) expect(view.map(i => i.type)).to.eql(['date', 'message', 'message', 'date', 'message'])
}) })
}) })
describe('.cullOlderMessages', () => {
it('keeps 50 newest messages and idIndex matches', () => {
const chat = chatService.empty()
for (let i = 100; i > 0; i--) {
// Use decimal values with toFixed to hack together constant length predictable strings
chatService.add(chat, { messages: [{ ...message1, id: 'a' + (i / 1000).toFixed(3), idempotency_key: i }] })
}
chatService.cullOlderMessages(chat)
expect(chat.messages.length).to.eql(50)
expect(chat.messages[0].id).to.eql('a0.051')
expect(chat.minId).to.eql('a0.051')
expect(chat.messages[49].id).to.eql('a0.100')
expect(Object.keys(chat.idIndex).length).to.eql(50)
})
})
}) })