mirror of
https://github.com/Troplo/Colubrina.git
synced 2024-11-22 19:27:55 +11:00
1.0.6
This commit is contained in:
parent
d80c7a76e6
commit
3d7df1c98a
13 changed files with 224 additions and 103 deletions
|
@ -5,3 +5,4 @@ NOTIFICATION=
|
||||||
NOTIFICATION_TYPE=info
|
NOTIFICATION_TYPE=info
|
||||||
SITE_NAME=Colubrina
|
SITE_NAME=Colubrina
|
||||||
ALLOW_REGISTRATIONS=true
|
ALLOW_REGISTRATIONS=true
|
||||||
|
PUBLIC_USERS=false
|
|
@ -30,7 +30,8 @@ app.get("/api/v1/state", async (req, res) => {
|
||||||
notificationType: process.env.NOTIFICATION_TYPE,
|
notificationType: process.env.NOTIFICATION_TYPE,
|
||||||
latestVersion: require("../frontend/package.json").version,
|
latestVersion: require("../frontend/package.json").version,
|
||||||
name: process.env.SITE_NAME,
|
name: process.env.SITE_NAME,
|
||||||
allowRegistrations: JSON.parse(process.env.ALLOW_REGISTRATIONS)
|
allowRegistrations: process.env.ALLOW_REGISTRATIONS === "true",
|
||||||
|
publicUsers: process.env.PUBLIC_USERS === "true"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -348,22 +348,26 @@ router.get("/mutual/:id/groups", auth, async (req, res, next) => {
|
||||||
|
|
||||||
router.get("/users", auth, async (req, res, next) => {
|
router.get("/users", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const users = await User.findAll({
|
if (process.env.PUBLIC_USERS === "true") {
|
||||||
attributes: [
|
const users = await User.findAll({
|
||||||
"id",
|
attributes: [
|
||||||
"username",
|
"id",
|
||||||
"name",
|
"username",
|
||||||
"avatar",
|
"name",
|
||||||
"createdAt",
|
"avatar",
|
||||||
"updatedAt",
|
"createdAt",
|
||||||
"status",
|
"updatedAt",
|
||||||
"admin"
|
"status",
|
||||||
],
|
"admin"
|
||||||
where: {
|
],
|
||||||
banned: false
|
where: {
|
||||||
}
|
banned: false
|
||||||
})
|
}
|
||||||
res.json(users)
|
})
|
||||||
|
res.json(users)
|
||||||
|
} else {
|
||||||
|
res.json([])
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
next(err)
|
next(err)
|
||||||
}
|
}
|
||||||
|
@ -1361,9 +1365,26 @@ router.get("/:id/messages", auth, async (req, res, next) => {
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
if (chat) {
|
if (chat) {
|
||||||
|
let or
|
||||||
|
if (parseInt(req.query.offset)) {
|
||||||
|
or = {
|
||||||
|
[Op.or]: [
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
[Op.lt]: parseInt(req.query.offset)
|
||||||
|
? parseInt(req.query.offset)
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
or = {}
|
||||||
|
}
|
||||||
const messages = await Message.findAll({
|
const messages = await Message.findAll({
|
||||||
where: {
|
where: {
|
||||||
chatId: chat.chat.id
|
chatId: chat.chat.id,
|
||||||
|
...or
|
||||||
},
|
},
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
|
@ -1422,7 +1443,6 @@ router.get("/:id/messages", auth, async (req, res, next) => {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
offset: parseInt(req.query.offset) || 0,
|
|
||||||
order: [["id", "DESC"]],
|
order: [["id", "DESC"]],
|
||||||
limit: 50
|
limit: 50
|
||||||
})
|
})
|
||||||
|
|
|
@ -192,7 +192,7 @@ router.post("/register", async (req, res, next) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (!JSON.parse(process.env.ALLOW_REGISTRATIONS)) {
|
if (process.env.ALLOW_REGISTRATIONS !== "true") {
|
||||||
throw Errors.registrationsDisabled
|
throw Errors.registrationsDisabled
|
||||||
}
|
}
|
||||||
if (req.body.password.length < 8) {
|
if (req.body.password.length < 8) {
|
||||||
|
|
40
cli/index.js
40
cli/index.js
|
@ -6,7 +6,7 @@ const { Sequelize } = require("sequelize")
|
||||||
const argon2 = require("argon2")
|
const argon2 = require("argon2")
|
||||||
const axios = require("axios")
|
const axios = require("axios")
|
||||||
const os = require("os")
|
const os = require("os")
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require("child_process")
|
||||||
|
|
||||||
console.log("Troplo/Colubrina CLI")
|
console.log("Troplo/Colubrina CLI")
|
||||||
console.log("Colubrina version", require("../frontend/package.json").version)
|
console.log("Colubrina version", require("../frontend/package.json").version)
|
||||||
|
@ -15,12 +15,19 @@ async function checkForUpdates() {
|
||||||
await axios
|
await axios
|
||||||
.get("https://services.troplo.com/api/v1/state", {
|
.get("https://services.troplo.com/api/v1/state", {
|
||||||
headers: {
|
headers: {
|
||||||
"X-Troplo-Project": "colubrina"
|
"X-Troplo-Project": "colubrina",
|
||||||
|
"X-Troplo-Project-Version": require("../frontend/package.json")
|
||||||
|
.version
|
||||||
},
|
},
|
||||||
timeout: 1000
|
timeout: 1000
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (require("../frontend/package.json").version !== res.data.latestVersion) {
|
if (res.data.warning) {
|
||||||
|
console.log(res.data.warning)
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
require("../frontend/package.json").version !== res.data.latestVersion
|
||||||
|
) {
|
||||||
console.log("A new version of Colubrina is available!")
|
console.log("A new version of Colubrina is available!")
|
||||||
console.log("Latest version:", res.data.latestVersion)
|
console.log("Latest version:", res.data.latestVersion)
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,7 +146,7 @@ async function dbSetup() {
|
||||||
}
|
}
|
||||||
async function runMigrations() {
|
async function runMigrations() {
|
||||||
console.log("Running migrations")
|
console.log("Running migrations")
|
||||||
execSync("cd ../backend && sequelize db:migrate", () => {
|
execSync("cd ../backend && sequelize db:migrate", () => {
|
||||||
console.log("Migrations applied")
|
console.log("Migrations applied")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -218,6 +225,12 @@ async function configureDotEnv() {
|
||||||
default: false
|
default: false
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
setEnvValue(
|
||||||
|
"PUBLIC_USERS",
|
||||||
|
await input.text("Show instance users publicly", {
|
||||||
|
default: false
|
||||||
|
})
|
||||||
|
)
|
||||||
setEnvValue("NOTIFICATION", "")
|
setEnvValue("NOTIFICATION", "")
|
||||||
setEnvValue("NOTIFICATION_TYPE", "info")
|
setEnvValue("NOTIFICATION_TYPE", "info")
|
||||||
setEnvValue("RELEASE", "stable")
|
setEnvValue("RELEASE", "stable")
|
||||||
|
@ -240,8 +253,8 @@ async function init() {
|
||||||
execSync("cd ../backend && yarn install --frozen-lockfile", () => {
|
execSync("cd ../backend && yarn install --frozen-lockfile", () => {
|
||||||
console.log("yarn install complete (backend)")
|
console.log("yarn install complete (backend)")
|
||||||
})
|
})
|
||||||
execSync("cd ../frontend && yarn install --frozen-lockfile", () => {
|
execSync("cd ../frontend && yarn install --frozen-lockfile", () => {
|
||||||
console.log("yarn install complete (frontend)")
|
console.log("yarn install complete (frontend)")
|
||||||
})
|
})
|
||||||
if (fs.existsSync(path.join(__dirname, "../backend/.env"))) {
|
if (fs.existsSync(path.join(__dirname, "../backend/.env"))) {
|
||||||
const option = await input.confirm(".env already exists, overwrite?", {
|
const option = await input.confirm(".env already exists, overwrite?", {
|
||||||
|
@ -253,7 +266,9 @@ async function init() {
|
||||||
} else {
|
} else {
|
||||||
await configureDotEnv()
|
await configureDotEnv()
|
||||||
}
|
}
|
||||||
if (fs.existsSync(path.join(__dirname, "../backend/config/config.json"))) {
|
if (
|
||||||
|
fs.existsSync(path.join(__dirname, "../backend/config/config.json"))
|
||||||
|
) {
|
||||||
const option = await input.select(
|
const option = await input.select(
|
||||||
`config/config.json already exists. Do you want to overwrite it?`,
|
`config/config.json already exists. Do you want to overwrite it?`,
|
||||||
["Yes", "No"]
|
["Yes", "No"]
|
||||||
|
@ -315,11 +330,14 @@ async function init() {
|
||||||
await runMigrations()
|
await runMigrations()
|
||||||
} else if (option === "Check for updates") {
|
} else if (option === "Check for updates") {
|
||||||
await checkForUpdates()
|
await checkForUpdates()
|
||||||
} else if(option === "Build frontend for production") {
|
} else if (option === "Build frontend for production") {
|
||||||
console.log("Building...")
|
console.log("Building...")
|
||||||
execSync("cd ../frontend && yarn install --frozen-lockfile && yarn build", () => {
|
execSync(
|
||||||
console.log("yarn build complete")
|
"cd ../frontend && yarn install --frozen-lockfile && yarn build",
|
||||||
})
|
() => {
|
||||||
|
console.log("yarn build complete")
|
||||||
|
}
|
||||||
|
)
|
||||||
} else if (option === "Exit") {
|
} else if (option === "Exit") {
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "colubrina-chat",
|
"name": "colubrina-chat",
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Troplo <troplo@troplo.com>",
|
"author": "Troplo <troplo@troplo.com>",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
|
|
@ -386,8 +386,9 @@
|
||||||
{{ $store.state.site.name }} QuickSwitcher
|
{{ $store.state.site.name }} QuickSwitcher
|
||||||
</v-toolbar-title>
|
</v-toolbar-title>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-container>
|
<v-container v-if="$store.state.modals.search">
|
||||||
<v-autocomplete
|
<v-autocomplete
|
||||||
|
@keydown.enter="handleEnter"
|
||||||
auto-select-first
|
auto-select-first
|
||||||
v-model="search"
|
v-model="search"
|
||||||
:items="$store.state.quickSwitchCache"
|
:items="$store.state.quickSwitchCache"
|
||||||
|
@ -405,7 +406,10 @@
|
||||||
<v-main>
|
<v-main>
|
||||||
<Header></Header>
|
<Header></Header>
|
||||||
<v-container
|
<v-container
|
||||||
v-if="$store.state.site.latestVersion > $store.state.versioning.version"
|
v-if="
|
||||||
|
$store.state.site.latestVersion > $store.state.versioning.version &&
|
||||||
|
$store.state.site.release !== 'dev'
|
||||||
|
"
|
||||||
id="update-notify-banner"
|
id="update-notify-banner"
|
||||||
>
|
>
|
||||||
<v-alert class="mx-4 rounded-xl" type="info" text dismissible>
|
<v-alert class="mx-4 rounded-xl" type="info" text dismissible>
|
||||||
|
@ -506,6 +510,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleEnter() {
|
||||||
|
if (
|
||||||
|
!this.searchInput &&
|
||||||
|
this.$store.state.lastRoute &&
|
||||||
|
this.$store.state.lastRoute !== this.$route.path
|
||||||
|
) {
|
||||||
|
this.$router.push(this.$store.state.lastRoute)
|
||||||
|
this.$store.state.modals.search = false
|
||||||
|
}
|
||||||
|
},
|
||||||
registerSocket() {
|
registerSocket() {
|
||||||
if (!this.$store.state.wsRegistered) {
|
if (!this.$store.state.wsRegistered) {
|
||||||
this.$store.state.wsRegistered = true
|
this.$store.state.wsRegistered = true
|
||||||
|
@ -797,8 +811,9 @@ export default {
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
},
|
},
|
||||||
$route(to) {
|
$route(to, from) {
|
||||||
document.title = to.name + " - " + this.$store.state.site.name
|
document.title = to.name + " - " + this.$store.state.site.name
|
||||||
|
this.$store.state.lastRoute = from.path
|
||||||
},
|
},
|
||||||
search() {
|
search() {
|
||||||
if (this.search) {
|
if (this.search) {
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
@keydown.enter.exact.prevent="handleMessage()"
|
@keydown.enter.exact.prevent="handleMessage()"
|
||||||
v-model="message"
|
v-model="message"
|
||||||
@paste="handlePaste"
|
@paste="handlePaste"
|
||||||
@change="handleChange"
|
|
||||||
rows="1"
|
rows="1"
|
||||||
single-line
|
single-line
|
||||||
dense
|
dense
|
||||||
|
@ -112,7 +111,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleEditMessage() {
|
handleEditMessage() {
|
||||||
if(!this.message?.length) {
|
if (!this.message?.length) {
|
||||||
this.editLastMessage()
|
this.editLastMessage()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -283,6 +282,11 @@ export default {
|
||||||
if (this.edit) {
|
if (this.edit) {
|
||||||
this.message = this.edit.content
|
this.message = this.edit.content
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
message() {
|
||||||
|
this.handleChange()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -669,7 +669,8 @@ export default {
|
||||||
"endEdit",
|
"endEdit",
|
||||||
"autoScroll",
|
"autoScroll",
|
||||||
"index",
|
"index",
|
||||||
"show"
|
"show",
|
||||||
|
"setImagePreview"
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
CommsInput
|
CommsInput
|
||||||
|
|
|
@ -92,6 +92,10 @@ Vue.directive("markdown", {
|
||||||
el.innerHTML = md.render(el.innerHTML)
|
el.innerHTML = md.render(el.innerHTML)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
console.log("Colubrina is running in development mode.")
|
||||||
|
Vue.config.performance = true
|
||||||
|
}
|
||||||
new Vue({
|
new Vue({
|
||||||
router,
|
router,
|
||||||
store,
|
store,
|
||||||
|
|
|
@ -29,6 +29,7 @@ export default new Vuex.Store({
|
||||||
selectedChat: null,
|
selectedChat: null,
|
||||||
chats: [],
|
chats: [],
|
||||||
baseURL: process.env.VUE_APP_BASE_URL,
|
baseURL: process.env.VUE_APP_BASE_URL,
|
||||||
|
lastRoute: null,
|
||||||
versioning: {
|
versioning: {
|
||||||
date: process.env.VUE_APP_BUILD_DATE,
|
date: process.env.VUE_APP_BUILD_DATE,
|
||||||
version: process.env.VUE_APP_VERSION,
|
version: process.env.VUE_APP_VERSION,
|
||||||
|
|
|
@ -126,38 +126,37 @@
|
||||||
elevation="0"
|
elevation="0"
|
||||||
>
|
>
|
||||||
<v-card-text class="flex-grow-1 overflow-y-auto" id="message-list">
|
<v-card-text class="flex-grow-1 overflow-y-auto" id="message-list">
|
||||||
<v-list two-line color="card" ref="message-list">
|
<v-card-title v-if="reachedTop">
|
||||||
<v-card-title v-if="reachedTop">
|
Welcome to the start of
|
||||||
Welcome to the start of
|
{{
|
||||||
{{
|
$store.state.selectedChat?.chat?.type === "direct"
|
||||||
$store.state.selectedChat?.chat?.type === "direct"
|
? getDirectRecipient($store.state.selectedChat).username
|
||||||
? getDirectRecipient($store.state.selectedChat).username
|
: $store.state.selectedChat?.chat?.name
|
||||||
: $store.state.selectedChat?.chat?.name
|
}}
|
||||||
}}
|
</v-card-title>
|
||||||
</v-card-title>
|
<v-progress-circular
|
||||||
<v-progress-circular
|
v-if="loadingMessages"
|
||||||
v-if="loadingMessages"
|
indeterminate
|
||||||
indeterminate
|
size="64"
|
||||||
size="128"
|
style="display: block; width: 100px; margin: 0 auto"
|
||||||
class="justify-center"
|
></v-progress-circular>
|
||||||
></v-progress-circular>
|
<template v-for="(message, index) in messages">
|
||||||
<template v-for="(message, index) in messages">
|
<Message
|
||||||
<Message
|
:key="message.keyId"
|
||||||
:key="message.keyId"
|
:message="message"
|
||||||
:message="message"
|
:jump-to-message="jumpToMessage"
|
||||||
:jump-to-message="jumpToMessage"
|
:edit="edit"
|
||||||
:edit="edit"
|
:focus-input="focusInput"
|
||||||
:focus-input="focusInput"
|
:replying="setReply"
|
||||||
:replying="setReply"
|
:get-name="getName"
|
||||||
:get-name="getName"
|
:end-edit="endEdit"
|
||||||
:end-edit="endEdit"
|
:auto-scroll="autoScroll"
|
||||||
:auto-scroll="autoScroll"
|
:chat="chat"
|
||||||
:chat="chat"
|
:index="index"
|
||||||
:index="index"
|
:show="show"
|
||||||
:show="show"
|
:set-image-preview="setImagePreview"
|
||||||
></Message>
|
></Message>
|
||||||
</template>
|
</template>
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-toolbar
|
<v-toolbar
|
||||||
|
@ -167,7 +166,6 @@
|
||||||
color="card"
|
color="card"
|
||||||
v-if="replying"
|
v-if="replying"
|
||||||
style="cursor: pointer; overflow: hidden"
|
style="cursor: pointer; overflow: hidden"
|
||||||
class="mb-2"
|
|
||||||
>
|
>
|
||||||
<v-icon class="mr-2">mdi-reply</v-icon>
|
<v-icon class="mr-2">mdi-reply</v-icon>
|
||||||
<v-avatar size="24" class="mr-2">
|
<v-avatar size="24" class="mr-2">
|
||||||
|
@ -194,17 +192,29 @@
|
||||||
<v-icon> mdi-close </v-icon>
|
<v-icon> mdi-close </v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-toolbar
|
<v-fade-transition v-model="avoidAutoScroll">
|
||||||
height="29"
|
<v-toolbar
|
||||||
color="transparent"
|
height="22"
|
||||||
elevation="0"
|
color="toolbar"
|
||||||
style="margin-bottom: -12px; padding-top: 0"
|
elevation="0"
|
||||||
>
|
style="
|
||||||
<p v-if="usersTyping.length" style="float: left">
|
border-radius: 20px 20px 0 0;
|
||||||
{{ usersTyping.map((user) => getName(user)).join(", ") }}
|
cursor: pointer;
|
||||||
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
|
z-index: 50;
|
||||||
</p>
|
position: relative;
|
||||||
</v-toolbar>
|
top: -30px;
|
||||||
|
margin-bottom: -27px;
|
||||||
|
"
|
||||||
|
width="100%"
|
||||||
|
@click="forceBottom"
|
||||||
|
v-if="avoidAutoScroll"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<v-icon size="16px"> mdi-arrow-down </v-icon>
|
||||||
|
Jump to bottom...
|
||||||
|
</div>
|
||||||
|
</v-toolbar>
|
||||||
|
</v-fade-transition>
|
||||||
<CommsInput
|
<CommsInput
|
||||||
:chat="chat"
|
:chat="chat"
|
||||||
:replying="replying"
|
:replying="replying"
|
||||||
|
@ -212,6 +222,27 @@
|
||||||
:autoScroll="autoScroll"
|
:autoScroll="autoScroll"
|
||||||
:endSend="endSend"
|
:endSend="endSend"
|
||||||
></CommsInput>
|
></CommsInput>
|
||||||
|
<v-fade-transition v-model="usersTyping.length">
|
||||||
|
<v-toolbar
|
||||||
|
height="22"
|
||||||
|
elevation="0"
|
||||||
|
style="
|
||||||
|
border-radius: 0 0 20px 20px;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: -2px;
|
||||||
|
margin-top: -20px;
|
||||||
|
bottom: -14px;
|
||||||
|
"
|
||||||
|
width="100%"
|
||||||
|
color="toolbar"
|
||||||
|
v-if="usersTyping.length"
|
||||||
|
>
|
||||||
|
<div style="overflow: hidden">
|
||||||
|
{{ usersTyping.map((user) => getName(user)).join(", ") }}
|
||||||
|
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
|
||||||
|
</div>
|
||||||
|
</v-toolbar>
|
||||||
|
</v-fade-transition>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
@ -812,6 +843,10 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
forceBottom() {
|
||||||
|
this.avoidAutoScroll = false
|
||||||
|
this.autoScroll()
|
||||||
|
},
|
||||||
getDirectRecipient(item) {
|
getDirectRecipient(item) {
|
||||||
let user = item.chat.users.find(
|
let user = item.chat.users.find(
|
||||||
(user) => user.id !== this.$store.state.user.id
|
(user) => user.id !== this.$store.state.user.id
|
||||||
|
@ -841,7 +876,9 @@ export default {
|
||||||
},
|
},
|
||||||
async scrollEvent(e) {
|
async scrollEvent(e) {
|
||||||
this.avoidAutoScroll =
|
this.avoidAutoScroll =
|
||||||
e.target.scrollTop + e.target.offsetHeight !== e.target.scrollHeight
|
e.target.scrollHeight -
|
||||||
|
Math.round(e.target.scrollTop + e.target.offsetHeight) >
|
||||||
|
50
|
||||||
if (
|
if (
|
||||||
e.target.scrollTop === 0 &&
|
e.target.scrollTop === 0 &&
|
||||||
!this.rateLimit &&
|
!this.rateLimit &&
|
||||||
|
@ -1077,26 +1114,32 @@ export default {
|
||||||
this.edit.id = ""
|
this.edit.id = ""
|
||||||
this.focusInput()
|
this.focusInput()
|
||||||
},
|
},
|
||||||
autoScroll() {
|
autoScroll(smooth = false) {
|
||||||
if (!this.avoidAutoScroll) {
|
if (!this.avoidAutoScroll) {
|
||||||
this.$nextTick(() => {
|
try {
|
||||||
try {
|
const lastIndex = this.messages.length - 1
|
||||||
const lastIndex = this.messages.length - 1
|
const lastMessage = document.querySelector(`#message-${lastIndex}`)
|
||||||
const lastMessage = document.querySelector(`#message-${lastIndex}`)
|
if (smooth) {
|
||||||
|
lastMessage.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "nearest",
|
||||||
|
inline: "start"
|
||||||
|
})
|
||||||
|
} else {
|
||||||
lastMessage.scrollIntoView()
|
lastMessage.scrollIntoView()
|
||||||
this.autoScrollRetry = 0
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Could not auto scroll, retrying...")
|
|
||||||
if (this.autoScrollRetry < 20) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.autoScroll()
|
|
||||||
}, 50)
|
|
||||||
this.autoScrollRetry++
|
|
||||||
} else {
|
|
||||||
console.log("Could not auto scroll, retry limit reached")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
this.autoScrollRetry = 0
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Could not auto scroll, retrying...")
|
||||||
|
if (this.autoScrollRetry < 20) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.autoScroll()
|
||||||
|
}, 50)
|
||||||
|
this.autoScrollRetry++
|
||||||
|
} else {
|
||||||
|
console.log("Could not auto scroll, retry limit reached")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getMessages() {
|
getMessages() {
|
||||||
|
@ -1107,7 +1150,7 @@ export default {
|
||||||
"/api/v1/communications/" +
|
"/api/v1/communications/" +
|
||||||
this.$route.params.id +
|
this.$route.params.id +
|
||||||
"/messages?limit=50&offset=" +
|
"/messages?limit=50&offset=" +
|
||||||
this.offset
|
this.messages[0]?.id || 0
|
||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (!res.data.length) {
|
if (!res.data.length) {
|
||||||
|
@ -1132,9 +1175,15 @@ export default {
|
||||||
"/read"
|
"/read"
|
||||||
)
|
)
|
||||||
this.markAsRead()
|
this.markAsRead()
|
||||||
|
},
|
||||||
|
focusKey() {
|
||||||
|
if (document.activeElement.tagName === "BODY") {
|
||||||
|
this.focusInput()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
document.addEventListener("keypress", this.focusKey)
|
||||||
document
|
document
|
||||||
.getElementById("message-list")
|
.getElementById("message-list")
|
||||||
.addEventListener("scroll", this.scrollEvent)
|
.addEventListener("scroll", this.scrollEvent)
|
||||||
|
@ -1231,6 +1280,10 @@ export default {
|
||||||
this.offset = 0
|
this.offset = 0
|
||||||
this.getMessages()
|
this.getMessages()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
document.removeEventListener("keypress", this.focusKey)
|
||||||
|
document.removeEventListener("scroll", this.scrollEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<v-toolbar-title> Users </v-toolbar-title>
|
<v-toolbar-title> Users </v-toolbar-title>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-card color="card" elevation="0">
|
<v-card color="card" elevation="0">
|
||||||
<v-list color="card">
|
<v-list color="card" v-if="$store.state.site.publicUsers">
|
||||||
<v-list-item v-for="user in users" :key="user.id">
|
<v-list-item v-for="user in users" :key="user.id">
|
||||||
<v-list-item-avatar
|
<v-list-item-avatar
|
||||||
@click="userProfile(user)"
|
@click="userProfile(user)"
|
||||||
|
@ -68,6 +68,9 @@
|
||||||
</v-list-item-action>
|
</v-list-item-action>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
|
<v-card-title v-else
|
||||||
|
>Public users are not enabled on this instance.</v-card-title
|
||||||
|
>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
|
|
Loading…
Reference in a new issue