mirror of
https://github.com/Troplo/Colubrina.git
synced 2024-11-22 19:27:55 +11:00
1.0.11
This commit is contained in:
parent
7d0141d2bf
commit
970c0021c3
12 changed files with 1831 additions and 83 deletions
4
frontend/.gitignore
vendored
4
frontend/.gitignore
vendored
|
@ -20,4 +20,6 @@ pnpm-debug.log*
|
|||
|
||||
backend/node_modules
|
||||
backend/config/config.json
|
||||
backend/.env
|
||||
backend/.env
|
||||
#Electron-builder output
|
||||
/dist_electron
|
|
@ -1,15 +1,18 @@
|
|||
{
|
||||
"name": "colubrina-chat",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"private": true,
|
||||
"author": "Troplo <troplo@troplo.com>",
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"postinstall": "patch-package"
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"postinstall": "patch-package && electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.17.10",
|
||||
"@mdi/js": "^6.6.95",
|
||||
|
@ -62,11 +65,14 @@
|
|||
"@vue/cli-service": "~4.5.15",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"dotenv-webpack": "^7.1.0",
|
||||
"electron": "^13.0.0",
|
||||
"electron-devtools-installer": "^3.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"material-design-icons-iconfont": "^6.5.0",
|
||||
"sass": "~1.32.0",
|
||||
"sass-loader": "^10.0.0",
|
||||
"vue-cli-plugin-electron-builder": "~2.1.1",
|
||||
"vue-cli-plugin-vuetify": "~2.4.7",
|
||||
"vue-template-babel-compiler": "^1.1.3",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
|
@ -74,6 +80,7 @@
|
|||
"webpack-auto-inject-version-next": "1.2.4",
|
||||
"webpack-bundle-analyzer": "^4.5.0"
|
||||
},
|
||||
"license": "GPL-3.0",
|
||||
"resolutions": {
|
||||
"node-ipc": "git+https://git.troplo.com/Troplo/node-ipc",
|
||||
"selfsigned": "^2.0.1",
|
||||
|
|
|
@ -729,8 +729,22 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
Vue.axios.defaults.headers.common["X-Colubrina"] = true
|
||||
Vue.axios.defaults.headers.common["Authorization"] =
|
||||
localStorage.getItem("session")
|
||||
console.log(localStorage.getItem("instance"))
|
||||
if (process.env.IS_ELECTRON) {
|
||||
this.axios.defaults.baseURL = localStorage.getItem("instance")
|
||||
this.$store.state.baseURL = localStorage.getItem("instance")
|
||||
}
|
||||
if (localStorage.getItem("customHeaders")) {
|
||||
console.log(JSON.parse(localStorage.getItem("customHeaders")))
|
||||
for (let header in JSON.parse(localStorage.getItem("customHeaders"))) {
|
||||
Vue.axios.defaults.headers[header] = JSON.parse(
|
||||
localStorage.getItem("customHeaders")
|
||||
)[header]
|
||||
}
|
||||
}
|
||||
if (this.$vuetify.breakpoint.mobile) {
|
||||
this.$store.state.drawer = false
|
||||
}
|
||||
|
|
82
frontend/src/background.js
Normal file
82
frontend/src/background.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
"use strict"
|
||||
|
||||
import { app, protocol, BrowserWindow } from "electron"
|
||||
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"
|
||||
import installExtension, { VUEJS_DEVTOOLS } from "electron-devtools-installer"
|
||||
const isDevelopment = process.env.NODE_ENV !== "production"
|
||||
|
||||
// Scheme must be registered before the app is ready
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: "app", privileges: { secure: true, standard: true } }
|
||||
])
|
||||
|
||||
async function createWindow() {
|
||||
// Create the browser window.
|
||||
const win = new BrowserWindow({
|
||||
width: 1400,
|
||||
height: 1000,
|
||||
webPreferences: {
|
||||
// Use pluginOptions.nodeIntegration, leave this alone
|
||||
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
|
||||
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||
preload: "window-preload.js",
|
||||
webSecurity: false
|
||||
}
|
||||
})
|
||||
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
// Load the url of the dev server if in development mode
|
||||
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
|
||||
if (!process.env.IS_TEST) win.webContents.openDevTools()
|
||||
} else {
|
||||
createProtocol("app")
|
||||
// Load the index.html when not in development
|
||||
win.loadURL("app://./index.html")
|
||||
}
|
||||
}
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on("window-all-closed", () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on("activate", () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on("ready", async () => {
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
// Install Vue Devtools
|
||||
try {
|
||||
await installExtension(VUEJS_DEVTOOLS)
|
||||
} catch (e) {
|
||||
console.error("Vue Devtools failed to install:", e.toString())
|
||||
}
|
||||
}
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
if (isDevelopment) {
|
||||
if (process.platform === "win32") {
|
||||
process.on("message", (data) => {
|
||||
if (data === "graceful-exit") {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
process.on("SIGTERM", () => {
|
||||
app.quit()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -67,14 +67,22 @@
|
|||
@click:close="remove(data.item)"
|
||||
>
|
||||
<v-avatar left v-if="data.item.avatar">
|
||||
<v-img :src="'/usercontent/' + data.item.avatar"></v-img>
|
||||
<v-img
|
||||
:src="
|
||||
$store.state.baseURL + '/usercontent/' + data.item.avatar
|
||||
"
|
||||
></v-img>
|
||||
</v-avatar>
|
||||
@{{ data.item.username }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<template v-slot:item="data">
|
||||
<v-avatar left v-if="data.item.avatar" class="mr-3 mb-2 mt-2">
|
||||
<v-img :src="'/usercontent/' + data.item.avatar"></v-img>
|
||||
<v-img
|
||||
:src="
|
||||
$store.state.baseURL + '/usercontent/' + data.item.avatar
|
||||
"
|
||||
></v-img>
|
||||
</v-avatar>
|
||||
<v-avatar left v-else class="mr-3 mb-2 mt-2">
|
||||
<v-icon>mdi-account</v-icon>
|
||||
|
@ -142,7 +150,9 @@
|
|||
>
|
||||
<v-list-item-avatar :color="$vuetify.theme.themes.dark.primary">
|
||||
<v-img
|
||||
:src="'/usercontent/' + user.user.avatar"
|
||||
:src="
|
||||
$store.state.baseURL + '/usercontent/' + user.user.avatar
|
||||
"
|
||||
v-if="user.user.avatar"
|
||||
/>
|
||||
<v-icon v-else> mdi-account </v-icon>
|
||||
|
@ -249,14 +259,22 @@
|
|||
@click:close="remove(data.item)"
|
||||
>
|
||||
<v-avatar left v-if="data.item.avatar">
|
||||
<v-img :src="'/usercontent/' + data.item.avatar"></v-img>
|
||||
<v-img
|
||||
:src="
|
||||
$store.state.baseURL + '/usercontent/' + data.item.avatar
|
||||
"
|
||||
></v-img>
|
||||
</v-avatar>
|
||||
@{{ data.item.username }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<template v-slot:item="data">
|
||||
<v-avatar left v-if="data.item.avatar" class="mr-3 mb-2 mt-2">
|
||||
<v-img :src="'/usercontent/' + data.item.avatar"></v-img>
|
||||
<v-img
|
||||
:src="
|
||||
$store.state.baseURL + '/usercontent/' + data.item.avatar
|
||||
"
|
||||
></v-img>
|
||||
</v-avatar>
|
||||
<v-avatar left v-else class="mr-3 mb-2 mt-2">
|
||||
<v-icon>mdi-account</v-icon>
|
||||
|
@ -527,7 +545,11 @@
|
|||
>
|
||||
<v-img
|
||||
v-if="$store.state.user.avatar"
|
||||
:src="'/usercontent/' + $store.state.user.avatar"
|
||||
:src="
|
||||
$store.state.baseURL +
|
||||
'/usercontent/' +
|
||||
$store.state.user.avatar
|
||||
"
|
||||
/>
|
||||
<v-icon v-else> mdi-account </v-icon>
|
||||
</v-list-item-avatar>
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
@click="setImagePreview(embed)"
|
||||
contain
|
||||
:aspect-ratio="16 / 9"
|
||||
:src="embed.mediaProxyLink"
|
||||
:src="$store.state.baseURL + embed.mediaProxyLink"
|
||||
>
|
||||
<template v-slot:placeholder>
|
||||
<v-row
|
||||
|
|
|
@ -175,7 +175,7 @@ const routes = [
|
|||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: "history",
|
||||
mode: process.env.IS_ELECTRON ? "hash" : "history",
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
})
|
||||
|
|
|
@ -855,6 +855,7 @@ export default {
|
|||
},
|
||||
props: ["chat", "loading", "items"],
|
||||
data: () => ({
|
||||
interval: null,
|
||||
pins: [],
|
||||
pinsLoading: true,
|
||||
reachedTop: false,
|
||||
|
@ -1361,7 +1362,7 @@ export default {
|
|||
document
|
||||
.getElementById("message-list")
|
||||
.addEventListener("scroll", this.scrollEvent)
|
||||
setInterval(() => {
|
||||
this.interval = setInterval(() => {
|
||||
this.typing()
|
||||
if (
|
||||
document.hasFocus() &&
|
||||
|
@ -1494,6 +1495,7 @@ export default {
|
|||
destroyed() {
|
||||
document.removeEventListener("keypress", this.focusKey)
|
||||
document.removeEventListener("scroll", this.scrollEvent)
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
:color="$vuetify.theme.themes.dark.primary"
|
||||
>
|
||||
<v-img
|
||||
:src="'/usercontent/' + user.avatar"
|
||||
:src="
|
||||
$store.state.baseURL + '/usercontent//' + user.avatar
|
||||
"
|
||||
v-if="user.avatar"
|
||||
/>
|
||||
<v-icon v-else> mdi-account </v-icon>
|
||||
|
@ -102,7 +104,11 @@
|
|||
:color="$vuetify.theme.themes.dark.primary"
|
||||
>
|
||||
<v-img
|
||||
:src="'/usercontent/' + friend.user2.avatar"
|
||||
:src="
|
||||
$store.state.baseURL +
|
||||
'/usercontent//' +
|
||||
friend.user2.avatar
|
||||
"
|
||||
v-if="friend.user2.avatar"
|
||||
/>
|
||||
<v-icon v-else> mdi-account </v-icon>
|
||||
|
@ -152,7 +158,11 @@
|
|||
:color="$vuetify.theme.themes.dark.primary"
|
||||
>
|
||||
<v-img
|
||||
:src="'/usercontent/' + friend.user2.avatar"
|
||||
:src="
|
||||
$store.state.baseURL +
|
||||
'/usercontent//' +
|
||||
friend.user2.avatar
|
||||
"
|
||||
v-if="friend.user2.avatar"
|
||||
/>
|
||||
<v-icon v-else> mdi-account </v-icon>
|
||||
|
@ -195,7 +205,11 @@
|
|||
:color="$vuetify.theme.themes.dark.primary"
|
||||
>
|
||||
<v-img
|
||||
:src="'/usercontent/' + friend.user2.avatar"
|
||||
:src="
|
||||
$store.state.baseURL +
|
||||
'/usercontent//' +
|
||||
friend.user2.avatar
|
||||
"
|
||||
v-if="friend.user2.avatar"
|
||||
/>
|
||||
<v-icon v-else> mdi-account </v-icon>
|
||||
|
|
|
@ -33,6 +33,29 @@
|
|||
<span class="troplo-title">{{ $store.state.site.name }}</span
|
||||
><small style="font-size: 15px">beta</small>
|
||||
</p>
|
||||
<v-text-field
|
||||
@keyup.enter="doLogin()"
|
||||
class="rounded-xl"
|
||||
v-model="instance"
|
||||
v-if="isElectron()"
|
||||
label="Instance URL"
|
||||
placeholder="https://colubrina.troplo.com"
|
||||
type="email"
|
||||
></v-text-field>
|
||||
<small style="float: right" v-if="isElectron()">{{
|
||||
instanceString
|
||||
}}</small
|
||||
><br v-if="isElectron()" />
|
||||
<v-text-field
|
||||
@keyup.enter="doLogin()"
|
||||
class="rounded-xl"
|
||||
v-model="customHeaders[header.name]"
|
||||
v-for="header in $store.state.site.customHeaders"
|
||||
:key="header.name"
|
||||
:label="header.friendlyName"
|
||||
:placeholder="header.placeholder"
|
||||
type="email"
|
||||
></v-text-field>
|
||||
<v-text-field
|
||||
@keyup.enter="doLogin()"
|
||||
class="rounded-xl"
|
||||
|
@ -93,20 +116,30 @@ export default {
|
|||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
instanceString: "",
|
||||
rememberMe: true,
|
||||
username: "",
|
||||
password: "",
|
||||
totp: "",
|
||||
totpDialog: false,
|
||||
loading: false
|
||||
loading: false,
|
||||
instance: "https://colubrina.troplo.com",
|
||||
customHeaders: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isElectron() {
|
||||
return process.env.IS_ELECTRON
|
||||
},
|
||||
viewport() {
|
||||
return window.innerHeight
|
||||
},
|
||||
doLogin() {
|
||||
this.loading = true
|
||||
localStorage.setItem("customHeaders", JSON.stringify(this.customHeaders))
|
||||
for (let header in this.customHeaders) {
|
||||
Vue.axios.defaults.headers[header] = this.customHeaders[header]
|
||||
}
|
||||
this.axios
|
||||
.post("/api/v1/user/login", {
|
||||
password: this.password,
|
||||
|
@ -115,9 +148,12 @@ export default {
|
|||
totp: this.totp
|
||||
})
|
||||
.then(async (res) => {
|
||||
localStorage.setItem("session", res.data.session)
|
||||
Vue.axios.defaults.headers.common["Authorization"] = res.data.session
|
||||
this.$store.commit("setToken", res.data.session)
|
||||
const session =
|
||||
res.data.session || res.data.bcToken || res.data.cookieToken
|
||||
|
||||
localStorage.setItem("session", session)
|
||||
Vue.axios.defaults.headers.common["Authorization"] = session
|
||||
this.$store.commit("setToken", session)
|
||||
await this.$store.dispatch("getUserInfo")
|
||||
this.$store.dispatch("getChats")
|
||||
this.loading = false
|
||||
|
@ -144,12 +180,33 @@ export default {
|
|||
this.loading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
testInstance() {
|
||||
if (this.isElectron()) {
|
||||
this.axios
|
||||
.get(this.instance + "/api/v1/state")
|
||||
.then((res) => {
|
||||
this.instanceString = res.data.name + " v" + res.data.latestVersion
|
||||
this.axios.defaults.baseURL = this.instance
|
||||
localStorage.setItem("instance", this.instance)
|
||||
this.$store.dispatch("getState")
|
||||
})
|
||||
.catch(() => {
|
||||
this.instanceString = "Error connecting to instance"
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$store.state.user?.id) {
|
||||
this.$router.push("/")
|
||||
}
|
||||
this.testInstance()
|
||||
},
|
||||
watch: {
|
||||
instance() {
|
||||
this.testInstance()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
1
frontend/src/window-preload.js
Normal file
1
frontend/src/window-preload.js
Normal file
|
@ -0,0 +1 @@
|
|||
Object.defineProperty(window, "isElectron", { get: () => true })
|
1671
frontend/yarn.lock
1671
frontend/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue