SocketIO based chat client as PoC for backend/frontend communication
The chat client itself is just a throwaway project. The SocketIO system will be used to send realtime updates about jobs, tasks, and workers to the web frontend.
This commit is contained in:
parent
2964f37dce
commit
96023932da
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@
|
|||||||
|
|
||||||
/flamenco-worker.yaml
|
/flamenco-worker.yaml
|
||||||
/flamenco-worker-credentials.yaml
|
/flamenco-worker-credentials.yaml
|
||||||
|
node_modules/
|
||||||
|
1
Makefile
1
Makefile
@ -31,6 +31,7 @@ with-deps:
|
|||||||
application: ${RESOURCES} generate
|
application: ${RESOURCES} generate
|
||||||
go build -v ${BUILD_FLAGS} ${PKG}/cmd/flamenco-manager-poc
|
go build -v ${BUILD_FLAGS} ${PKG}/cmd/flamenco-manager-poc
|
||||||
go build -v ${BUILD_FLAGS} ${PKG}/cmd/flamenco-worker-poc
|
go build -v ${BUILD_FLAGS} ${PKG}/cmd/flamenco-worker-poc
|
||||||
|
go build -v ${BUILD_FLAGS} ${PKG}/cmd/socketio-poc
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
go generate ${PKG}/...
|
go generate ${PKG}/...
|
||||||
|
18
README.md
18
README.md
@ -4,13 +4,27 @@ This repository contains a proof of concept of a next-generation Flamenco implem
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
1. Install [Go 1.17 or newer](https://go.dev/).
|
1. Install [Go 1.17 or newer](https://go.dev/) and Node 16 (see below)
|
||||||
2. Set the environment variable `GOPATH` to where you want Go to put its packages. Defaults to `$HOME/go` if not set. Run `go env GOPATH` if you're not sure.
|
2. Set the environment variable `GOPATH` to where you want Go to put its packages. Defaults to `$HOME/go` if not set. Run `go env GOPATH` if you're not sure.
|
||||||
3. Ensure `$GOPATH/bin` is included in your `$PATH` environment variable.
|
3. Ensure `$GOPATH/bin` is included in your `$PATH` environment variable.
|
||||||
4. Run `make with-deps` to install build-time dependencies and build the application. Subsequent builds can just run `make` without arguments.
|
4. Magically build the web frontend (still under development, no concrete steps documentable quite yet)
|
||||||
|
5. Run `make with-deps` to install build-time dependencies and build the application. Subsequent builds can just run `make` without arguments.
|
||||||
|
|
||||||
You should now have two executables: `flamenco-manager-poc` and `flamenco-worker-poc`.
|
You should now have two executables: `flamenco-manager-poc` and `flamenco-worker-poc`.
|
||||||
|
|
||||||
|
|
||||||
|
## Node / Web UI
|
||||||
|
|
||||||
|
The web UI is built with Vue, Bootstrap, and Socket.IO for communication with the backend.
|
||||||
|
|
||||||
|
NodeJS is used to collect all of those and build the frontend files. It's recommended to install Node v16 via Snap:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo snap install node --classic --channel=16
|
||||||
|
```
|
||||||
|
|
||||||
|
This also gives you the Yarn package manager, which can be used to install web dependencies and build the frontend files.
|
||||||
|
|
||||||
## Swagger UI
|
## Swagger UI
|
||||||
|
|
||||||
Flamenco Manager has a SwaggerUI interface at http://localhost:8080/api/swagger-ui/
|
Flamenco Manager has a SwaggerUI interface at http://localhost:8080/api/swagger-ui/
|
||||||
|
115
cmd/socketio-poc/main.go
Normal file
115
cmd/socketio-poc/main.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/labstack/echo/v4/middleware"
|
||||||
|
"github.com/mattn/go-colorable"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/ziflex/lecho/v3"
|
||||||
|
"gitlab.com/blender/flamenco-ng-poc/internal/appinfo"
|
||||||
|
|
||||||
|
gosocketio "github.com/graarh/golang-socketio"
|
||||||
|
"github.com/graarh/golang-socketio/transport"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func socketIOServer() *gosocketio.Server {
|
||||||
|
sio := gosocketio.NewServer(transport.GetDefaultWebsocketTransport())
|
||||||
|
log.Info().Msg("initialising SocketIO")
|
||||||
|
|
||||||
|
// socket connection
|
||||||
|
sio.On(gosocketio.OnConnection, func(c *gosocketio.Channel) {
|
||||||
|
log.Info().Str("clientID", c.Id()).Msg("connected")
|
||||||
|
c.Join("Room")
|
||||||
|
})
|
||||||
|
|
||||||
|
// socket disconnection
|
||||||
|
sio.On(gosocketio.OnDisconnection, func(c *gosocketio.Channel) {
|
||||||
|
log.Info().Str("clientID", c.Id()).Msg("disconnected")
|
||||||
|
c.Leave("Room")
|
||||||
|
})
|
||||||
|
|
||||||
|
sio.On(gosocketio.OnError, func(c *gosocketio.Channel) {
|
||||||
|
log.Warn().Interface("c", *c).Msg("socketio error")
|
||||||
|
})
|
||||||
|
|
||||||
|
// chat socket
|
||||||
|
sio.On("/chat", func(c *gosocketio.Channel, message Message) string {
|
||||||
|
log.Info().Str("clientID", c.Id()).
|
||||||
|
Str("text", message.Text).
|
||||||
|
Str("name", message.Name).
|
||||||
|
Msg("message received")
|
||||||
|
c.BroadcastTo("Room", "/message", message.Text)
|
||||||
|
return "message sent successfully."
|
||||||
|
})
|
||||||
|
|
||||||
|
return sio
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRoutes(router *echo.Echo, server *gosocketio.Server) {
|
||||||
|
cors := middleware.CORSWithConfig(middleware.CORSConfig{
|
||||||
|
AllowOrigins: []string{"http://localhost:8080/", "http://localhost:8081/"},
|
||||||
|
|
||||||
|
// List taken from https://www.bacancytechnology.com/blog/real-time-chat-application-using-socketio-golang-vuejs/
|
||||||
|
AllowHeaders: []string{
|
||||||
|
echo.HeaderAccept,
|
||||||
|
echo.HeaderAcceptEncoding,
|
||||||
|
echo.HeaderAccessControlAllowOrigin,
|
||||||
|
echo.HeaderAccessControlRequestHeaders,
|
||||||
|
echo.HeaderAccessControlRequestMethod,
|
||||||
|
echo.HeaderAuthorization,
|
||||||
|
echo.HeaderContentLength,
|
||||||
|
echo.HeaderContentType,
|
||||||
|
echo.HeaderOrigin,
|
||||||
|
echo.HeaderXCSRFToken,
|
||||||
|
echo.HeaderXRequestedWith,
|
||||||
|
"Cache-Control",
|
||||||
|
"Connection",
|
||||||
|
"Host",
|
||||||
|
"Referer",
|
||||||
|
"User-Agent",
|
||||||
|
"X-header",
|
||||||
|
},
|
||||||
|
AllowMethods: []string{"POST", "GET", "OPTIONS", "PUT", "DELETE"},
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Any("/socket.io/", echo.WrapHandler(server), cors)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
output := zerolog.ConsoleWriter{Out: colorable.NewColorableStdout(), TimeFormat: time.RFC3339}
|
||||||
|
log.Logger = log.Output(output)
|
||||||
|
log.Info().Str("version", appinfo.ApplicationVersion).Msgf("starting Socket.IO PoC %v", appinfo.ApplicationName)
|
||||||
|
|
||||||
|
socketio := socketIOServer()
|
||||||
|
|
||||||
|
e := echo.New()
|
||||||
|
e.HideBanner = true
|
||||||
|
e.HidePort = true
|
||||||
|
|
||||||
|
// Hook Zerolog onto Echo:
|
||||||
|
e.Use(lecho.Middleware(lecho.Config{
|
||||||
|
Logger: lecho.From(log.Logger),
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Ensure panics when serving a web request won't bring down the server.
|
||||||
|
e.Use(middleware.Recover())
|
||||||
|
|
||||||
|
addRoutes(e, socketio)
|
||||||
|
|
||||||
|
listen := ":8081"
|
||||||
|
log.Info().Str("listen", listen).Msg("server starting")
|
||||||
|
log.Info().Msg("Run `yarn serve` from the 'web' dir to run the frontend server")
|
||||||
|
|
||||||
|
// Start the web server.
|
||||||
|
finalErr := e.Start(listen)
|
||||||
|
log.Warn().Err(finalErr).Msg("shutting down")
|
||||||
|
}
|
4
go.mod
4
go.mod
@ -10,6 +10,10 @@ require (
|
|||||||
github.com/getkin/kin-openapi v0.88.0
|
github.com/getkin/kin-openapi v0.88.0
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/gorilla/handlers v1.5.1
|
||||||
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
github.com/graarh/golang-socketio v0.0.0-20170510162725-2c44953b9b5f
|
||||||
github.com/jackc/pgproto3/v2 v2.0.7 // indirect
|
github.com/jackc/pgproto3/v2 v2.0.7 // indirect
|
||||||
github.com/labstack/echo/v4 v4.6.1
|
github.com/labstack/echo/v4 v4.6.1
|
||||||
github.com/lib/pq v1.10.0 // indirect
|
github.com/lib/pq v1.10.0 // indirect
|
||||||
|
8
go.sum
8
go.sum
@ -23,6 +23,8 @@ github.com/dop251/goja v0.0.0-20211217115348-3f9136fa235d h1:XT7Qdmcuwgsgz4GXejX
|
|||||||
github.com/dop251/goja v0.0.0-20211217115348-3f9136fa235d/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
github.com/dop251/goja v0.0.0-20211217115348-3f9136fa235d/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7 h1:tYwu/z8Y0NkkzGEh3z21mSWggMg4LwLRFucLS7TjARg=
|
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7 h1:tYwu/z8Y0NkkzGEh3z21mSWggMg4LwLRFucLS7TjARg=
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
|
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
|
||||||
|
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||||
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/getkin/kin-openapi v0.80.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
github.com/getkin/kin-openapi v0.80.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||||
github.com/getkin/kin-openapi v0.88.0 h1:BjJ2JERWJbYE1o1RGEj/5LmR5qw7ecfl3O3su4ImR+0=
|
github.com/getkin/kin-openapi v0.88.0 h1:BjJ2JERWJbYE1o1RGEj/5LmR5qw7ecfl3O3su4ImR+0=
|
||||||
github.com/getkin/kin-openapi v0.88.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
github.com/getkin/kin-openapi v0.88.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||||
@ -61,8 +63,14 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
|||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||||
|
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/graarh/golang-socketio v0.0.0-20170510162725-2c44953b9b5f h1:utzdm9zUvVWGRtIpkdE4+36n+Gv60kNb7mFvgGxLElY=
|
||||||
|
github.com/graarh/golang-socketio v0.0.0-20170510162725-2c44953b9b5f/go.mod h1:8gudiNCFh3ZfvInknmoXzPeV17FSH+X2J5k2cUPIwnA=
|
||||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
|
53
web/package.json
Normal file
53
web/package.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "flamenco-manager-web-frontend",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"private": true,
|
||||||
|
"author": {
|
||||||
|
"name": "Sybren Stüvel"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bootstrap-vue": "^2.21.2",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"socket.io-client": "2.4.0",
|
||||||
|
"vue": "^2.6.11"
|
||||||
|
},
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"type": "GPL-3.0",
|
||||||
|
"url": "https://opensource.org/licenses/GPL-3.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
68
web/src/App.vue
Normal file
68
web/src/App.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<chat-navbar></chat-navbar>
|
||||||
|
<br />
|
||||||
|
<chat-chatbox
|
||||||
|
@sendMessage="sendMessage"
|
||||||
|
:chatHistory="messages"
|
||||||
|
></chat-chatbox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import io from "socket.io-client";
|
||||||
|
import ChatNavbar from "./components/ChatNavbar.vue";
|
||||||
|
import ChatChatbox from "./components/ChatChatbox.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
components: {
|
||||||
|
ChatNavbar,
|
||||||
|
ChatChatbox,
|
||||||
|
},
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
socket: null,
|
||||||
|
serverUrl: process.env.VUE_APP_SOCKET_URL || "ws://localhost:8081",
|
||||||
|
messages: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
this.connectToWebsocket();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
connectToWebsocket() {
|
||||||
|
console.log("connecting to WS", this.serverUrl);
|
||||||
|
this.socket = io(this.serverUrl, {
|
||||||
|
transports: ["websocket"],
|
||||||
|
});
|
||||||
|
this.socket.on("/message", (message) => {
|
||||||
|
console.log("message received: ", message);
|
||||||
|
this.messages.push(message);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sendMessage(message) {
|
||||||
|
const payload = { name: "Nikita", text: message };
|
||||||
|
console.log("sending:", payload);
|
||||||
|
this.socket.emit("/chat", payload);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app,
|
||||||
|
.card {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
61
web/src/components/ChatChatbox.vue
Normal file
61
web/src/components/ChatChatbox.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<b-container>
|
||||||
|
<b-card>
|
||||||
|
<div class="chatbox">
|
||||||
|
<b-row
|
||||||
|
class="no-gutters"
|
||||||
|
align-h="start"
|
||||||
|
v-for="(message, inx) in chatHistory"
|
||||||
|
:key="inx"
|
||||||
|
>
|
||||||
|
<b-col class="no-gutters" cols="8">
|
||||||
|
<div>
|
||||||
|
<p class="received-chat">{{ message }}</p>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</div>
|
||||||
|
<ChatMessageBox @sendMessage="(msg) => $emit('sendMessage', msg)" />
|
||||||
|
</b-card>
|
||||||
|
</b-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ChatMessageBox from "./ChatMessagebox.vue";
|
||||||
|
export default {
|
||||||
|
emits: ["sendMessage"],
|
||||||
|
props: ["chatHistory"],
|
||||||
|
components: {
|
||||||
|
ChatMessageBox,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.container {
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
}
|
||||||
|
.chatbox {
|
||||||
|
padding: 10px;
|
||||||
|
height: calc(100% - 35px);
|
||||||
|
overflow-y: auto;
|
||||||
|
/* background-image: url("https://i0.wp.com/www.tortugacreative.com/wp-content/uploads/social-media-background-dark-2.png?ssl=1"); */
|
||||||
|
}
|
||||||
|
.sender-name {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
.chat {
|
||||||
|
background-color: lightgreen;
|
||||||
|
padding: 10px;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
.received-chat {
|
||||||
|
background-color: lightblue;
|
||||||
|
padding: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
17
web/src/components/ChatHeader.vue
Normal file
17
web/src/components/ChatHeader.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<b-card title="Chat-App">
|
||||||
|
<b-form>
|
||||||
|
<label class="sr-only" for="inline-form-input-username">Username</label>
|
||||||
|
<b-input-group prepend="@" class="mb-2 mr-sm-2 mb-sm-0">
|
||||||
|
<b-form-input
|
||||||
|
id="inline-form-input-username"
|
||||||
|
placeholder="Username"
|
||||||
|
v-model.trim="username"
|
||||||
|
></b-form-input>
|
||||||
|
<b-button @click="joinRoom">Join</b-button>
|
||||||
|
</b-input-group>
|
||||||
|
</b-form>
|
||||||
|
</b-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
38
web/src/components/ChatMessagebox.vue
Normal file
38
web/src/components/ChatMessagebox.vue
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<b-input-group class="mb-2 mr-sm-2 mb-sm-0">
|
||||||
|
<b-form-input
|
||||||
|
placeholder="type here.."
|
||||||
|
v-model.trim="newMsg"
|
||||||
|
@keyup.enter="sendMessage"
|
||||||
|
></b-form-input>
|
||||||
|
<b-button
|
||||||
|
size="md"
|
||||||
|
variant="primary"
|
||||||
|
class="mb-2"
|
||||||
|
@click="sendMessage"
|
||||||
|
:disabled="!newMsg"
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</b-button>
|
||||||
|
</b-input-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ["sendMessage"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
newMsg: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sendMessage() {
|
||||||
|
if (!this.newMsg) return;
|
||||||
|
console.log("emitting message to send:", this.newMsg);
|
||||||
|
|
||||||
|
this.$emit("sendMessage", this.newMsg);
|
||||||
|
this.newMsg = "";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
5
web/src/components/ChatNavbar.vue
Normal file
5
web/src/components/ChatNavbar.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<b-navbar toggleable type="dark" variant="dark">
|
||||||
|
<b-navbar-brand href="#">Chat Application</b-navbar-brand>
|
||||||
|
</b-navbar>
|
||||||
|
</template>
|
31
web/src/main.js
Normal file
31
web/src/main.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import {
|
||||||
|
FormInputPlugin,
|
||||||
|
NavbarPlugin,
|
||||||
|
LayoutPlugin,
|
||||||
|
IconsPlugin,
|
||||||
|
BCard,
|
||||||
|
BInputGroup,
|
||||||
|
BButton,
|
||||||
|
} from "bootstrap-vue";
|
||||||
|
|
||||||
|
import "bootstrap/dist/css/bootstrap.css";
|
||||||
|
import "bootstrap-vue/dist/bootstrap-vue.css";
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
Vue.use(FormInputPlugin);
|
||||||
|
Vue.use(NavbarPlugin);
|
||||||
|
Vue.use(LayoutPlugin);
|
||||||
|
Vue.component("b-card", BCard);
|
||||||
|
Vue.component("b-input-group", BInputGroup);
|
||||||
|
Vue.component("b-button", BButton);
|
||||||
|
Vue.use(IconsPlugin);
|
||||||
|
|
||||||
|
var app = new Vue({
|
||||||
|
render: h => h(App),
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.$mount("#app");
|
BIN
web/static/favicon.ico
Normal file
BIN
web/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
17
web/static/index.html
Normal file
17
web/static/index.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
8801
web/yarn.lock
Normal file
8801
web/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user