├── .assets ├── 1.gif ├── 2.gif └── df_powered_by.svg ├── .github └── workflows │ └── go.yml ├── .vscode ├── extensions.json └── tasks.json ├── LICENSE ├── README.md └── application ├── .dockerignore ├── Dockerfile ├── backend ├── .env example ├── .gitignore ├── app │ ├── agent │ │ ├── agent.go │ │ └── agent_test.go │ ├── containerdb │ │ ├── containerdb.go │ │ └── containerdb_test.go │ ├── daemon │ │ ├── daemon.go │ │ └── daemon_test.go │ ├── db │ │ ├── db.go │ │ └── db_test.go │ ├── routes │ │ ├── routes.go │ │ └── routes_test.go │ ├── statistics │ │ ├── statistics.go │ │ └── statistics_test.go │ ├── streamer │ │ ├── streamer.go │ │ └── streamer_test.go │ ├── userdb │ │ ├── userdb.go │ │ └── userdb_test.go │ ├── util │ │ ├── util.go │ │ └── util_test.go │ └── vars │ │ └── vars.go ├── go.mod ├── go.sum └── main.go ├── build.sh ├── frontend ├── .gitignore ├── .storybook │ ├── main.cjs │ ├── preview-head.html │ └── preview.cjs ├── generate_font.js ├── index.html ├── jsconfig.json ├── package-lock.json ├── package.json ├── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── favicon_package_v0.16.zip │ ├── mstile-150x150.png │ ├── safari-pinned-tab.svg │ └── site.webmanifest ├── src │ ├── App.svelte │ ├── Stores │ │ └── stores.js │ ├── Theme.scss │ ├── Views │ │ ├── Login │ │ │ ├── Login.scss │ │ │ └── Login.svelte │ │ ├── Logs │ │ │ ├── Loader.svelte │ │ │ ├── LogStringHeader.svelte │ │ │ ├── LogsView.scss │ │ │ ├── LogsViewHeder │ │ │ │ └── LogsViewHeder.svelte │ │ │ ├── NewLogsV2.svelte │ │ │ ├── Spiner.svelte │ │ │ └── functions.js │ │ ├── Main │ │ │ ├── Main.scss │ │ │ ├── Main.svelte │ │ │ └── SettingsController.svelte │ │ └── ServiceSettings │ │ │ ├── Acess.svelte │ │ │ ├── General.svelte │ │ │ ├── ServiceSettings.scss │ │ │ ├── ServiceSettings.svelte │ │ │ └── ServiceSettingsLeft.svelte │ ├── assets │ │ ├── logo │ │ │ ├── logs.svg │ │ │ └── logs2.svg │ │ └── res │ │ │ ├── font │ │ │ ├── Alert.svg │ │ │ ├── Archive.svg │ │ │ ├── ArrowRight.svg │ │ │ ├── Break.svg │ │ │ ├── Burger.svg │ │ │ ├── Chart.svg │ │ │ ├── Clean.svg │ │ │ ├── Clock.svg │ │ │ ├── Close.svg │ │ │ ├── Colums.svg │ │ │ ├── Combine.svg │ │ │ ├── Copy.svg │ │ │ ├── Cut.svg │ │ │ ├── Data.svg │ │ │ ├── Down.svg │ │ │ ├── EmptyHeart.svg │ │ │ ├── Error.svg │ │ │ ├── Eye.svg │ │ │ ├── Filter.svg │ │ │ ├── Group.svg │ │ │ ├── Heart.svg │ │ │ ├── Home.svg │ │ │ ├── Info.svg │ │ │ ├── Json.svg │ │ │ ├── Last.svg │ │ │ ├── Leters.svg │ │ │ ├── Logout.svg │ │ │ ├── Moon.svg │ │ │ ├── Pencil.svg │ │ │ ├── Plus.svg │ │ │ ├── Pointer.svg │ │ │ ├── Refresh.svg │ │ │ ├── Search.svg │ │ │ ├── Server.svg │ │ │ ├── Share.svg │ │ │ ├── ShareLink.svg │ │ │ ├── Success.svg │ │ │ ├── Sun.svg │ │ │ ├── Tips.svg │ │ │ ├── User.svg │ │ │ ├── Warning.svg │ │ │ ├── Wheel.svg │ │ │ └── font-css.hbs │ │ │ ├── onLogsFont.css │ │ │ ├── onLogsFont.eot │ │ │ ├── onLogsFont.html │ │ │ ├── onLogsFont.svg │ │ │ ├── onLogsFont.ttf │ │ │ ├── onLogsFont.woff │ │ │ └── onLogsFont.woff2 │ ├── lib │ │ ├── Button │ │ │ ├── Button.scss │ │ │ ├── Button.stories.js │ │ │ └── Button.svelte │ │ ├── ButtonToBottom │ │ │ ├── ButtonToBottom.scss │ │ │ └── ButtonToBottom.svelte │ │ ├── ChartMenu │ │ │ ├── Chart.svelte │ │ │ ├── ChartMenu.scss │ │ │ └── MainChartMenu.svelte │ │ ├── CheckBox │ │ │ ├── CheckBox.scss │ │ │ └── Checkbox.svelte │ │ ├── ClientPanel │ │ │ ├── ClientPanel.scss │ │ │ └── ClientPanel.svelte │ │ ├── CommonList │ │ │ ├── CommonList.scss │ │ │ └── CommonList.svelte │ │ ├── ConfirmationMenu │ │ │ ├── ConfirmationMenu.scss │ │ │ └── ConfirmationMenu.svelte │ │ ├── Container │ │ │ ├── Container.scss │ │ │ ├── Container.stories.js │ │ │ ├── Container.svelte │ │ │ └── ContainerView.svelte │ │ ├── DropDown │ │ │ ├── DropDown.scss │ │ │ ├── DropDown.svelte │ │ │ ├── DropDownAddHost.svelte │ │ │ └── dropDownRow.svelte │ │ ├── HostList │ │ │ ├── HostList.scss │ │ │ └── HostList.svelte │ │ ├── Input │ │ │ └── Input.svelte │ │ ├── ListWithChoise │ │ │ ├── ListWithChoise.scss │ │ │ └── ListWithChoise.svelte │ │ ├── LogsSize │ │ │ ├── LogSize.scss │ │ │ └── LogsSize.svelte │ │ ├── LogsString │ │ │ ├── LogsString.scss │ │ │ ├── LogsString.stories.js │ │ │ └── LogsString.svelte │ │ ├── Modal │ │ │ ├── Modal.scss │ │ │ └── Modal.svelte │ │ ├── NotFound │ │ │ ├── Notfound.scss │ │ │ └── Notfound.svelte │ │ ├── OutsideClicker │ │ │ └── OutsideClicker.js │ │ ├── ProgressBar │ │ │ ├── ProgressBar.scss │ │ │ └── ProgressBar.svelte │ │ ├── SecretModal │ │ │ ├── DockerComposeSnippet.svelte │ │ │ ├── DockerSnippet.svelte │ │ │ ├── SecretModal.scss │ │ │ └── SecretModal.svelte │ │ ├── Stats │ │ │ ├── Stats.scss │ │ │ └── Stats.svelte │ │ ├── StreamInfo │ │ │ ├── StreamInfo.scss │ │ │ └── StreamInfo.svelte │ │ ├── Toast │ │ │ ├── Toast.scss │ │ │ └── Toast.svelte │ │ └── UserMenu │ │ │ ├── UserManageForm.svelte │ │ │ ├── UserMenu.scss │ │ │ └── UserMenu.svelte │ ├── main.js │ ├── main.scss │ ├── utils │ │ ├── _variables.scss │ │ ├── changeKey.js │ │ ├── fetch.js │ │ └── functions.js │ └── vite-env.d.ts ├── startDebug.js ├── storybook-static │ ├── favicon.ico │ ├── project.json │ └── stories.json └── vite.config.js └── release.sh /.assets/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/.assets/1.gif -------------------------------------------------------------------------------- /.assets/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/.assets/2.gif -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v3 18 | with: 19 | go-version: 1.19.1 20 | 21 | - name: Get coverage tool 22 | run: | 23 | cd application/backend 24 | go get golang.org/x/tools/cmd/cover 25 | REF=${{ github.ref }} 26 | IFS='/' read -ra PATHS <<< "$REF" 27 | BRANCH_NAME="${PATHS[1]}_${PATHS[2]}" 28 | echo $BRANCH_NAME 29 | echo "BRANCH=$(echo ${BRANCH_NAME})" >> $GITHUB_ENV 30 | 31 | - name: Create failing badge 32 | uses: schneegans/dynamic-badges-action@v1.0.0 33 | with: 34 | auth: ${{ secrets.GIST_SECRET }} 35 | gistID: 7a0933f8cba0bddbcc95c8b850e32663 36 | filename: onlogs_passing__${{ env.BRANCH }}.json 37 | label: Tests 38 | message: Failed 39 | color: red 40 | namedLogo: checkmarx 41 | 42 | - name: Test 43 | run: | 44 | cd application/backend 45 | go test ./... -coverprofile cover.out 46 | go tool cover -func cover.out > covered.txt 47 | 48 | - name: Get coverage 49 | run: | 50 | cd application/backend 51 | for word in $(cat covered.txt); do total_percent=$word; done 52 | echo $total_percent 53 | echo "COVERAGE=$total_percent" >> $GITHUB_ENV 54 | 55 | - name: Create passing badge 56 | uses: schneegans/dynamic-badges-action@v1.0.0 57 | if: ${{ env.COVERAGE!=null }} 58 | with: 59 | auth: ${{ secrets.GIST_SECRET }} 60 | gistID: 7a0933f8cba0bddbcc95c8b850e32663 61 | filename: onlogs_passing__${{ env.BRANCH }}.json 62 | label: Tests 63 | message: Passed 64 | color: green 65 | namedLogo: checkmarx 66 | 67 | - name: Create coverage badge 68 | uses: schneegans/dynamic-badges-action@v1.0.0 69 | if: ${{ env.COVERAGE!=null }} 70 | with: 71 | auth: ${{ secrets.GIST_SECRET }} 72 | gistID: 7a0933f8cba0bddbcc95c8b850e32663 73 | filename: onlogs_units_coverage__${{ env.BRANCH }}.json 74 | label: Test Coverage 75 | message: ${{ env.COVERAGE }} 76 | color: green 77 | namedLogo: go 78 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"], 3 | "files.autoSave": "onFocusChange" 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Run front", 6 | "type": "shell", 7 | "command": "cd application/frontend && npm run dev", 8 | "presentation": { 9 | "reveal": "always", 10 | "panel": "new", 11 | "group": "develop" 12 | }, 13 | "runOptions": { "runOn": "folderOpen" } 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Devforth.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /application/.dockerignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | frontend/node_modules 11 | frontend/dist 12 | frontend/dist-ssr 13 | frontend/*.local 14 | frontend/*.prettierrc 15 | frontend/.gitignore 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | backend/.gitignore 29 | backend/dist 30 | leveldb 31 | *_test.go 32 | 33 | .assets/ 34 | README.md 35 | -------------------------------------------------------------------------------- /application/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16-alpine AS frontbuilder 2 | 3 | WORKDIR /code/ 4 | ADD frontend/package-lock.json . 5 | ADD frontend/package.json . 6 | RUN npm install -g npm:16 && npm ci 7 | 8 | ADD frontend/. . 9 | 10 | RUN npm run build 11 | 12 | COPY . /code/ 13 | 14 | FROM alpine 15 | 16 | COPY --from=frontbuilder /code/dist/ /backend/dist/ 17 | 18 | FROM golang:alpine AS backendbuilder 19 | 20 | ADD backend/. /backend/ 21 | WORKDIR /backend/ 22 | 23 | RUN go mod download \ 24 | && go build -o onlogs . 25 | 26 | FROM alpine 27 | 28 | COPY --from=frontbuilder /code/dist/ /dist/ 29 | COPY --from=backendbuilder /backend/onlogs /backend/onlogs 30 | CMD ["/backend/onlogs"] 31 | -------------------------------------------------------------------------------- /application/backend/.env example: -------------------------------------------------------------------------------- 1 | PASSWORD=fsadfsadfad 2 | ENV_NAME = local 3 | PORT=2874 4 | ONLOGS_PATH_PREFIX='' 5 | 6 | # HOST=onlogs.coposter.me 7 | # AGENT=true -------------------------------------------------------------------------------- /application/backend/.gitignore: -------------------------------------------------------------------------------- 1 | leveldb 2 | .env 3 | dist -------------------------------------------------------------------------------- /application/backend/app/agent/agent.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io" 7 | "net/http" 8 | "os" 9 | 10 | "github.com/devforth/OnLogs/app/util" 11 | "github.com/devforth/OnLogs/app/vars" 12 | ) 13 | 14 | func SendInitRequest(containers []string) { 15 | postBody, _ := json.Marshal(map[string]interface{}{ 16 | "Hostname": util.GetHost(), 17 | "Token": os.Getenv("ONLOGS_TOKEN"), 18 | "Services": containers, 19 | }) 20 | responseBody := bytes.NewBuffer(postBody) 21 | 22 | resp, err := http.Post(os.Getenv("HOST")+"/api/v1/addHost", "application/json", responseBody) 23 | if err != nil { 24 | panic("ERROR: Can't send request to host: " + err.Error()) 25 | } 26 | 27 | if resp.StatusCode != 200 { 28 | b, _ := io.ReadAll(resp.Body) 29 | panic("ERROR: Response status from host is " + resp.Status + "\nResponse body: " + string(b)) 30 | } 31 | } 32 | 33 | func SendLogMessage(token string, container string, message_item []string) bool { 34 | postBody, _ := json.Marshal(map[string]interface{}{ 35 | "Host": util.GetHost(), 36 | "Token": token, 37 | "LogLine": []string{message_item[0], message_item[1]}, 38 | "Container": container, 39 | }) 40 | resp, err := http.Post(os.Getenv("HOST")+"/api/v1/addLogLine", "application/json", bytes.NewBuffer(postBody)) 41 | if err != nil || resp.StatusCode != 200 { 42 | vars.BrokenLogs_DBs[container].Put([]byte(message_item[0]), []byte(message_item[1]), nil) 43 | return false 44 | } 45 | return true 46 | } 47 | 48 | func TryResend() { 49 | token := os.Getenv("ONLOGS_TOKEN") 50 | containers, _ := os.ReadDir("leveldb/hosts/" + util.GetHost() + "/containers/") 51 | for _, container := range containers { 52 | tmpDB := vars.BrokenLogs_DBs[container.Name()] 53 | if tmpDB == nil { 54 | tmpDB = util.GetDB(util.GetHost(), container.Name(), "/brokenLogs") 55 | defer tmpDB.Close() 56 | } 57 | 58 | iter := tmpDB.NewIterator(nil, nil) 59 | defer iter.Release() 60 | iter.First() 61 | if iter.Value() == nil { 62 | continue 63 | } 64 | 65 | if !SendLogMessage(token, container.Name(), []string{string(iter.Key()), string(iter.Value())}) { 66 | return 67 | } 68 | tmpDB.Delete(iter.Key(), nil) 69 | 70 | for iter.Next() { 71 | if !SendLogMessage(token, container.Name(), []string{string(iter.Key()), string(iter.Value())}) { 72 | return 73 | } 74 | tmpDB.Delete(iter.Key(), nil) 75 | } 76 | } 77 | } 78 | 79 | func SendUpdate(containers []string) { 80 | postBody, _ := json.Marshal(map[string]interface{}{ 81 | "Hostname": util.GetHost(), 82 | "Token": os.Getenv("ONLOGS_TOKEN"), 83 | "Services": containers, 84 | }) 85 | responseBody := bytes.NewBuffer(postBody) 86 | 87 | http.Post(os.Getenv("HOST")+"/api/v1/addHost", "application/json", responseBody) 88 | AskForDelete() 89 | } 90 | 91 | func AskForDelete() { 92 | postBody, _ := json.Marshal(map[string]interface{}{ 93 | "Hostname": util.GetHost(), 94 | "Token": os.Getenv("ONLOGS_TOKEN"), 95 | }) 96 | responseBody := bytes.NewBuffer(postBody) 97 | 98 | resp, _ := http.Post(os.Getenv("HOST")+"/api/v1/askForDelete", "application/json", responseBody) 99 | 100 | body, _ := io.ReadAll(resp.Body) 101 | if string(body) != "" { 102 | var toDelete map[string][]string 103 | json.Unmarshal(body, &toDelete) 104 | 105 | for _, container := range toDelete["Services"] { 106 | util.DeleteDockerLogs(util.GetHost(), container) 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /application/backend/app/agent/agent_test.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import "testing" 4 | 5 | func TestSendInitRequest(t *testing.T) { 6 | defer func() { 7 | r := recover().(string) 8 | if r != "ERROR: Can't send request to host: Post \"/api/v1/addHost\": unsupported protocol scheme \"\"" { 9 | t.Error("Not expected error: ", r) 10 | } 11 | }() 12 | SendInitRequest([]string{}) 13 | } 14 | -------------------------------------------------------------------------------- /application/backend/app/containerdb/containerdb_test.go: -------------------------------------------------------------------------------- 1 | package containerdb 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/devforth/OnLogs/app/vars" 7 | "github.com/syndtr/goleveldb/leveldb" 8 | ) 9 | 10 | func TestPutLogMessage(t *testing.T) { 11 | cont := "testCont" 12 | host := "testHost" 13 | vars.Container_Stat_Counter[host+"/"+cont] = map[string]uint64{"error": 0, "debug": 0, "info": 0, "warn": 0, "meta": 0, "other": 0} 14 | db, _ := leveldb.OpenFile("leveldb/hosts/"+host+"/containers/"+cont+"/logs", nil) 15 | statusDB, _ := leveldb.OpenFile("leveldb/hosts/"+host+"/containers/"+cont+"statuses", nil) 16 | vars.Statuses_DBs[host+"/"+cont] = statusDB 17 | defer statusDB.Close() 18 | defer db.Close() 19 | 20 | PutLogMessage(db, host, cont, []string{vars.Year + "-02-10T12:56:09.230421754Z", "vokAU6OdSulJGynsz wBaKssXuAPGk6ZFiQxq4sQHe7B9Q9RbTAy\r\n"}) 21 | PutLogMessage(db, host, cont, []string{vars.Year + "-02-10T12:57:09.230421754Z", "ERROR wBaKssXuAPGk6ZFiQxq4sQHe7B9Q9RbTAy\r\n"}) 22 | PutLogMessage(db, host, cont, []string{vars.Year + "-02-10T12:58:09.230421754Z", "WARN vokAU6OdSulJGynsz\r\n"}) 23 | PutLogMessage(db, host, cont, []string{vars.Year + "-02-10T12:59:09.230421754Z", "DEBUG wBaKssXuAPGk6ZFiQxq4sQHe7B9Q9RbTAy\r\n"}) 24 | PutLogMessage(db, host, cont, []string{vars.Year + "-02-10T12:59:59.230421754Z", "INFO fasdfasdfB&^*inuk\r\n"}) 25 | 26 | keys := []string{ 27 | vars.Year + "-02-10T12:56:09.230421754Z", vars.Year + "-02-10T12:57:09.230421754Z", 28 | vars.Year + "-02-10T12:58:09.230421754Z", vars.Year + "-02-10T12:59:09.230421754Z", 29 | vars.Year + "-02-10T12:59:59.230421754Z", 30 | } 31 | for _, key := range keys { 32 | has, _ := db.Has([]byte(key), nil) 33 | if !has { 34 | t.Error("Key is not in db: " + key) 35 | } 36 | } 37 | 38 | PutLogMessage(db, host, cont, []string{"123", "fasdf\r\n"}) 39 | has, _ := db.Has([]byte("123"), nil) 40 | if has { 41 | t.Error("Bad key is in db!") 42 | } 43 | 44 | defer func() { 45 | r := recover().(string) 46 | if r != "Host is not mentioned!" { 47 | t.Error("Not expected error: ", r) 48 | } 49 | }() 50 | PutLogMessage(db, "", cont, []string{vars.Year + "-02-10T12:57:09.230421754Z", "fasdf\r\n"}) 51 | } 52 | 53 | func TestGetLogs(t *testing.T) { 54 | db, _ := leveldb.OpenFile("leveldb/hosts/Test/containers/TestGetLogsCont/logs", nil) 55 | vars.Container_Stat_Counter["Test/TestGetLogsCont"] = map[string]uint64{"error": 0, "debug": 0, "info": 0, "warn": 0, "meta": 0, "other": 0} 56 | statusDB, _ := leveldb.OpenFile("leveldb/hosts/Test/containers/TestGetLogsCont/statuses", nil) 57 | vars.Statuses_DBs["Test/TestGetLogsCont"] = statusDB 58 | defer statusDB.Close() 59 | 60 | PutLogMessage(db, "Test", "TestGetLogsCont", []string{vars.Year + "-02-10T12:57:09.230421754Z", "fasdf\r\n"}) 61 | PutLogMessage(db, "Test", "TestGetLogsCont", []string{vars.Year + "-02-10T12:51:09.230421754Z", "fasdf\r\n"}) 62 | PutLogMessage(db, "Test", "TestGetLogsCont", []string{vars.Year + "-02-10T12:52:09.230421754Z", "fasdf\r\n"}) 63 | PutLogMessage(db, "Test", "TestGetLogsCont", []string{vars.Year + "-02-10T12:53:09.230421754Z", "fasdf\r\n"}) 64 | PutLogMessage(db, "Test", "TestGetLogsCont", []string{vars.Year + "-02-10T12:54:09.230421754Z", "fasdf\r\n"}) 65 | db.Close() 66 | 67 | var logs [][]string 68 | logs = GetLogs(false, true, "Test", "TestGetLogsCont", "", 30, vars.Year+"-02-10T12:57:09.230421754Z", false, nil)["logs"].([][]string) 69 | if len(logs) != 5 { 70 | t.Error("5 logItems must be returned!") 71 | } 72 | if logs[0][0] != vars.Year+"-02-10T12:57:09.230421754Z" { 73 | t.Error("Invalid first logItem datetime: ", logs[0][0]) 74 | } 75 | if logs[4][0] != vars.Year+"-02-10T12:51:09.230421754Z" { 76 | t.Error("Invalid last logItem datetime: ", logs[4][0]) 77 | } 78 | 79 | logs = GetLogs(true, false, "Test", "TestGetLogsCont", "", 30, vars.Year+"-02-10T12:51:09.230421754Z", false, nil)["logs"].([][]string) 80 | if len(logs) != 4 { 81 | t.Error("4 logItems must be returned!") 82 | } 83 | if logs[0][0] != vars.Year+"-02-10T12:52:09.230421754Z" { 84 | t.Error("Invalid first logItem datetime: ", logs[0][0]) 85 | } 86 | if logs[3][0] != vars.Year+"-02-10T12:57:09.230421754Z" { 87 | t.Error("Invalid last logItem datetime: ", logs[3][0]) 88 | } 89 | 90 | logs = GetLogs(true, false, "Test", "TestGetLogsCont", "", 30, vars.Year+"-02-10T12:51:09.230421753Z", false, nil)["logs"].([][]string) 91 | if len(logs) != 5 { 92 | t.Error("4 logItems must be returned!") 93 | } 94 | if logs[0][0] != vars.Year+"-02-10T12:51:09.230421754Z" { 95 | t.Error("Invalid first logItem datetime: ", logs[0][0]) 96 | } 97 | if logs[4][0] != vars.Year+"-02-10T12:57:09.230421754Z" { 98 | t.Error("Invalid last logItem datetime: ", logs[3][0]) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /application/backend/app/daemon/daemon_test.go: -------------------------------------------------------------------------------- 1 | package daemon 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func Test_validateMessage(t *testing.T) { 9 | type args struct { 10 | message string 11 | } 12 | tests := []struct { 13 | name string 14 | args args 15 | want string 16 | want1 bool 17 | }{ 18 | {"Bad message", args{message: string([]byte{10})}, "", false}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | got, got1 := validateMessage(tt.args.message) 23 | if !reflect.DeepEqual(got, tt.want) { 24 | t.Errorf("validateMessage() got = %v, want %v", got, tt.want) 25 | } 26 | if got1 != tt.want1 { 27 | t.Errorf("validateMessage() got1 = %v, want %v", got1, tt.want1) 28 | } 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /application/backend/app/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/devforth/OnLogs/app/util" 7 | "github.com/devforth/OnLogs/app/vars" 8 | "github.com/syndtr/goleveldb/leveldb" 9 | ) 10 | 11 | func CreateOnLogsToken() string { 12 | token := util.GenerateJWTSecret() 13 | to_put := time.Now().UTC().Add(24 * time.Hour).String() 14 | err := vars.TokensDB.Put([]byte(token), []byte(to_put), nil) 15 | if err != nil { 16 | vars.TokensDB.Close() 17 | vars.TokensDB, vars.TokensDBErr = leveldb.OpenFile("leveldb/tokens", nil) 18 | 19 | err = vars.TokensDB.Put([]byte(token), []byte(to_put), nil) 20 | if err != nil { 21 | panic(err) 22 | } 23 | } 24 | return token 25 | } 26 | 27 | func IsTokenExists(token string) bool { 28 | iter := vars.TokensDB.NewIterator(nil, nil) 29 | defer iter.Release() 30 | iter.First() 31 | if string(iter.Key()) == token { 32 | vars.TokensDB.Put([]byte(token), []byte("was used"), nil) 33 | return true 34 | } 35 | for iter.Next() { 36 | if string(iter.Key()) == token { 37 | vars.TokensDB.Put([]byte(token), []byte("was used"), nil) 38 | return true 39 | } 40 | } 41 | return false 42 | } 43 | 44 | func DeleteUnusedTokens() { 45 | for { 46 | db := vars.TokensDB 47 | iter := db.NewIterator(nil, nil) 48 | for iter.Next() { 49 | wasUsed := string(iter.Value()) 50 | if wasUsed == "was used" { 51 | continue 52 | } 53 | 54 | created, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", string(wasUsed)) 55 | if created.Before(time.Now()) { 56 | db.Delete(iter.Key(), nil) 57 | } 58 | } 59 | iter.Release() 60 | db.Close() 61 | time.Sleep(time.Hour * 1) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /application/backend/app/db/db_test.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestIsTokenExists(t *testing.T) { 8 | type args struct { 9 | token string 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | want bool 15 | }{ 16 | {"Bad token", args{token: "fasdfadsf"}, false}, 17 | {"Valid token", args{token: CreateOnLogsToken()}, true}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if got := IsTokenExists(tt.args.token); got != tt.want { 22 | t.Errorf("IsTokenExists() = %v, want %v", got, tt.want) 23 | } 24 | }) 25 | } 26 | } 27 | 28 | func TestCreateOnLogsToken(t *testing.T) { 29 | token := CreateOnLogsToken() 30 | if !IsTokenExists(token) { 31 | t.Error("Invalid token") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /application/backend/app/statistics/statistics_test.go: -------------------------------------------------------------------------------- 1 | package statistics 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "strings" 7 | "testing" 8 | "time" 9 | 10 | "github.com/devforth/OnLogs/app/vars" 11 | "github.com/syndtr/goleveldb/leveldb" 12 | ) 13 | 14 | func TestRunStatisticForContainer(t *testing.T) { 15 | go RunStatisticForContainer("Test", "TestContainer") 16 | time.Sleep(1 * time.Second) 17 | if vars.Container_Stat_Counter["Test/TestContainer"] == nil { 18 | t.Error("No counter variable for container was created!") 19 | } 20 | if vars.Stat_Containers_DBs["Test/TestContainer"] == nil { 21 | t.Error("DB for stats wasn't created!") 22 | } 23 | } 24 | 25 | func TestGetStatisticsByService(t *testing.T) { 26 | vars.Container_Stat_Counter["test/test"] = map[string]uint64{"error": 1, "debug": 2, "info": 3, "warn": 4, "meta": 0, "other": 5} 27 | os.RemoveAll("leveldb/hosts/test/containers/test/statistics") 28 | statDB, _ := leveldb.OpenFile("leveldb/hosts/test/containers/test/statistics", nil) 29 | to_put, _ := json.Marshal(vars.Container_Stat_Counter["test/test"]) 30 | datetime := strings.Replace(strings.Split(time.Now().UTC().String(), ".")[0], " ", "T", 1) + "Z" 31 | statDB.Put([]byte(datetime), to_put, nil) 32 | statDB.Close() 33 | 34 | res := GetStatisticsByService("test", "test", 2) 35 | if res["debug"] != 4 || res["error"] != 2 || 36 | res["info"] != 6 || res["other"] != 10 || 37 | res["warn"] != 8 { 38 | t.Error("Wrong value!\n", res) 39 | } 40 | } 41 | 42 | func TestGetChartData(t *testing.T) { 43 | cur_db, _ := leveldb.OpenFile("leveldb/hosts/test/statistics", nil) 44 | vars.Container_Stat_Counter["test/test"] = map[string]uint64{"error": 2, "debug": 1, "info": 3, "warn": 5, "meta": 0, "other": 4} 45 | vars.Stat_Containers_DBs["test/test"] = cur_db 46 | to_put, _ := json.Marshal(vars.Container_Stat_Counter["test/test"]) 47 | datetime := strings.Replace(strings.Split(time.Now().UTC().String(), ".")[0], " ", "T", 1) + "Z" 48 | cur_db.Put([]byte(datetime), to_put, nil) 49 | 50 | res := GetChartData("test", "test", "hour", 2) 51 | datetime = datetime[:len(datetime)-6] + "00Z" 52 | if res[datetime]["debug"] != 1 || res[datetime]["error"] != 2 || 53 | res[datetime]["info"] != 3 || res[datetime]["other"] != 4 || 54 | res[datetime]["warn"] != 5 || res["now"]["debug"] != 1 || 55 | res["now"]["error"] != 2 || res["now"]["info"] != 3 || 56 | res["now"]["other"] != 4 || res["now"]["warn"] != 5 { 57 | t.Error("Wrong value!\n", res[datetime]) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /application/backend/app/streamer/streamer.go: -------------------------------------------------------------------------------- 1 | package streamer 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "time" 8 | 9 | "github.com/devforth/OnLogs/app/agent" 10 | "github.com/devforth/OnLogs/app/daemon" 11 | "github.com/devforth/OnLogs/app/statistics" 12 | "github.com/devforth/OnLogs/app/util" 13 | "github.com/devforth/OnLogs/app/vars" 14 | ) 15 | 16 | func createStreams(containers []string) { 17 | for _, container := range vars.DockerContainers { 18 | if !util.Contains(container, vars.Active_Daemon_Streams) { 19 | go statistics.RunStatisticForContainer(util.GetHost(), container) 20 | vars.Active_Daemon_Streams = append(vars.Active_Daemon_Streams, container) 21 | if os.Getenv("AGENT") != "" { 22 | go daemon.CreateDaemonToHostStream(container) 23 | } else { 24 | go daemon.CreateDaemonToDBStream(container) 25 | } 26 | } 27 | } 28 | } 29 | 30 | func StreamLogs() { 31 | if vars.FavsDBErr != nil || vars.StateDBErr != nil || vars.UsersDBErr != nil { 32 | fmt.Println("ERROR: unable to open leveldb", vars.FavsDBErr, vars.StateDBErr, vars.UsersDBErr) 33 | return 34 | } 35 | 36 | vars.DockerContainers = daemon.GetContainersList() 37 | if os.Getenv("AGENT") != "" { 38 | agent.SendInitRequest(vars.DockerContainers) 39 | } 40 | for { 41 | createStreams(vars.DockerContainers) 42 | time.Sleep(20 * time.Second) 43 | vars.Year = strconv.Itoa(time.Now().UTC().Year()) 44 | vars.DockerContainers = daemon.GetContainersList() 45 | if os.Getenv("AGENT") != "" { 46 | agent.SendUpdate(vars.DockerContainers) 47 | agent.TryResend() 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /application/backend/app/streamer/streamer_test.go: -------------------------------------------------------------------------------- 1 | package streamer 2 | 3 | import "testing" 4 | 5 | func Test_createStreams(t *testing.T) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /application/backend/app/userdb/userdb.go: -------------------------------------------------------------------------------- 1 | package userdb 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "os" 7 | "strings" 8 | 9 | "github.com/devforth/OnLogs/app/vars" 10 | "github.com/syndtr/goleveldb/leveldb" 11 | ) 12 | 13 | func IsUserExists(login string) bool { 14 | isExists, _ := vars.UsersDB.Has([]byte(login), nil) 15 | return isExists 16 | } 17 | 18 | func CreateUser(login string, password string) error { 19 | if IsUserExists(login) { 20 | return errors.New("User is already exists") 21 | } 22 | 23 | vars.UsersDB.Put([]byte(login), []byte(password), nil) 24 | return nil 25 | } 26 | 27 | func GetUsers() []string { 28 | users := []string{} 29 | iter := vars.UsersDB.NewIterator(nil, nil) 30 | for iter.Next() { 31 | if string(iter.Key()) == os.Getenv("ADMIN_USERNAME") { 32 | continue 33 | } 34 | users = append(users, string(iter.Key())) 35 | } 36 | defer iter.Release() 37 | 38 | return users 39 | } 40 | 41 | func EditUser(login string, password string) { 42 | vars.UsersDB.Put([]byte(login), []byte(password), nil) 43 | } 44 | 45 | func DeleteUser(login string, password string) error { 46 | isExists, _ := vars.UsersDB.Has([]byte(login), nil) 47 | if !isExists { 48 | return errors.New("No such user") 49 | } 50 | 51 | vars.UsersDB.Delete([]byte(login), nil) 52 | return nil 53 | } 54 | 55 | func CheckUserPassword(login string, gotPassword string) bool { 56 | password, err := vars.UsersDB.Get([]byte(login), nil) 57 | if err != nil || strings.Compare(string(password), gotPassword) != 0 { 58 | return false 59 | } 60 | 61 | return true 62 | } 63 | 64 | func GetUserSettings(username string) map[string]interface{} { 65 | settingsDB, _ := leveldb.OpenFile("leveldb/usersSettings", nil) 66 | defer settingsDB.Close() 67 | var to_return map[string]interface{} 68 | result, _ := settingsDB.Get([]byte(username), nil) 69 | json.Unmarshal(result, &to_return) 70 | return to_return 71 | } 72 | 73 | func UpdateUserSettings(username string, settings map[string]interface{}) { 74 | settingsDB, _ := leveldb.OpenFile("leveldb/usersSettings", nil) 75 | defer settingsDB.Close() 76 | to_put, _ := json.Marshal(settings) 77 | settingsDB.Put([]byte(username), to_put, nil) 78 | } 79 | -------------------------------------------------------------------------------- /application/backend/app/userdb/userdb_test.go: -------------------------------------------------------------------------------- 1 | package userdb 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/devforth/OnLogs/app/vars" 7 | ) 8 | 9 | func TestIsUserExists(t *testing.T) { 10 | if IsUserExists("random") { 11 | t.Error("User shouldn't exist") 12 | } 13 | } 14 | 15 | func TestCreateUser(t *testing.T) { 16 | CreateUser("amogus", "sus") 17 | if !IsUserExists("amogus") { 18 | t.Error("User is not exist") 19 | } 20 | 21 | err := CreateUser("amogus", "sus") 22 | if err == nil || err.Error() != "User is already exists" { 23 | t.Error("Error \"User is already exists\" expected, got ", err) 24 | } 25 | } 26 | 27 | func TestGetUsers(t *testing.T) { 28 | CreateUser("admin", "admin") 29 | CreateUser("admin1", "admin") 30 | CreateUser("admin2", "admin") 31 | 32 | users := GetUsers() 33 | if len(users) < 3 { 34 | t.Error("Need more users") 35 | } 36 | } 37 | 38 | func TestEditUser(t *testing.T) { 39 | CreateUser("testtest", "testtest") 40 | EditUser("testtest", "sus?") 41 | 42 | pass, _ := vars.UsersDB.Get([]byte("testtest"), nil) 43 | if string(pass) != "sus?" { 44 | t.Error("User wasn't edited") 45 | } 46 | } 47 | 48 | func TestDeleteUser(t *testing.T) { 49 | err := DeleteUser("aaaaaaaaa????????", "123") 50 | if err == nil { 51 | t.Error("Error is nil") 52 | } 53 | 54 | DeleteUser("admin1", "admin") 55 | if IsUserExists("admin1") { 56 | t.Error("User should be deleted") 57 | } 58 | } 59 | 60 | func TestCheckUserPassword(t *testing.T) { 61 | CreateUser("testpassword", "123456") 62 | if !CheckUserPassword("testpassword", "123456") { 63 | t.Error("Password should be correct") 64 | } 65 | if CheckUserPassword("testpassword", "1") { 66 | t.Error("Password shouldn't be correct") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /application/backend/app/util/util_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | "testing" 7 | 8 | "github.com/devforth/OnLogs/app/vars" 9 | ) 10 | 11 | func TestContains(t *testing.T) { 12 | type args struct { 13 | a string 14 | list []string 15 | } 16 | tests := []struct { 17 | name string 18 | args args 19 | want bool 20 | }{ 21 | {"Is contain 'a'", args{a: "a", list: []string{"a", "b", "c"}}, true}, 22 | {"Is contain 'A'", args{a: "A", list: []string{"a", "b", "c"}}, false}, 23 | } 24 | for _, tt := range tests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | if got := Contains(tt.args.a, tt.args.list); got != tt.want { 27 | t.Errorf("Contains() = %v, want %v", got, tt.want) 28 | } 29 | }) 30 | } 31 | } 32 | 33 | func TestCreateInitUser(t *testing.T) { 34 | CreateInitUser() 35 | isExist, err := vars.UsersDB.Has([]byte("admin"), nil) 36 | if err != nil { 37 | t.Error(err.Error()) 38 | } 39 | if !isExist { 40 | t.Error("User was not created!") 41 | } 42 | } 43 | 44 | func TestCreateJWT(t *testing.T) { 45 | os.Setenv("JWT_SERCRET", "1231efdZF") 46 | token := CreateJWT("test_user") 47 | 48 | test_req, _ := http.NewRequest("GET", "", nil) 49 | test_req.AddCookie( 50 | &http.Cookie{ 51 | Name: "onlogs-cookie", 52 | Value: token, 53 | }, 54 | ) 55 | 56 | username, err := GetUserFromJWT(*test_req) 57 | if err != nil { 58 | t.Error(err) 59 | } 60 | if username != "test_user" { 61 | t.Error("Username in JWT is wrong: ", username) 62 | } 63 | } 64 | 65 | func TestGetHost(t *testing.T) { 66 | host, _ := os.Hostname() 67 | if host[len(host)-1] < 32 || host[len(host)-1] > 126 { 68 | host = host[:len(host)-1] 69 | } 70 | 71 | if GetHost() != host { 72 | t.Error("Hosts is not matching!") 73 | } 74 | } 75 | 76 | func TestGetUserFromJWT(t *testing.T) { 77 | os.Setenv("JWT_SERCRET", "1231efdZF") 78 | 79 | test_req1, _ := http.NewRequest("GET", "", nil) 80 | test_req1.AddCookie( 81 | &http.Cookie{ 82 | Name: "onlogs-cookie", 83 | Value: CreateJWT("test_user"), 84 | }, 85 | ) 86 | test_req2, _ := http.NewRequest("GET", "", nil) 87 | test_req2.AddCookie( 88 | &http.Cookie{ 89 | Name: "onlogs-cookie", 90 | Value: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE2NzU4NDU4MDAsInVzZXIiOiJ0ZXN0X3VzZXIifQ.eqlUc3XkL8u-icC-2nihIrh1IedWP-cC9ewa4OI7wBg", 91 | }, 92 | ) 93 | 94 | test_req3, _ := http.NewRequest("GET", "", nil) 95 | 96 | username, _ := GetUserFromJWT(*test_req1) 97 | if username != "test_user" { 98 | t.Error("Username in JWT is wrong: ", username) 99 | } 100 | 101 | _, err := GetUserFromJWT(*test_req2) 102 | if err.Error() != "Token is expired" { 103 | t.Error("Token should be expired") 104 | } 105 | 106 | _, err = GetUserFromJWT(*test_req3) 107 | if err.Error() != "401 - Unauthorized!" { 108 | t.Error("Req should be unauthorized") 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /application/backend/app/vars/vars.go: -------------------------------------------------------------------------------- 1 | package vars 2 | 3 | import ( 4 | "strconv" 5 | "sync" 6 | "time" 7 | 8 | "github.com/gorilla/websocket" 9 | "github.com/syndtr/goleveldb/leveldb" 10 | ) 11 | 12 | var ( 13 | ActiveDBs = map[string]*leveldb.DB{} 14 | Stat_Containers_DBs = map[string]*leveldb.DB{} 15 | Stat_Hosts_DBs = map[string]*leveldb.DB{} 16 | Statuses_DBs = map[string]*leveldb.DB{} 17 | BrokenLogs_DBs = map[string]*leveldb.DB{} 18 | ContainersMeta_DBs = map[string]*leveldb.DB{} 19 | 20 | Active_Daemon_Streams = []string{} 21 | 22 | DockerContainers = []string{} 23 | AgentsActiveContainers = map[string][]string{} 24 | 25 | ToDelete = map[string][]string{} 26 | Connections = map[string][]websocket.Conn{} 27 | 28 | Counters_For_Hosts_Last_30_Min = map[string]map[string]uint64{} 29 | Container_Stat_Counter = map[string]map[string]uint64{} 30 | 31 | Mutex sync.Mutex 32 | DBMutex sync.RWMutex 33 | 34 | FavsDB, FavsDBErr = leveldb.OpenFile("leveldb/favourites", nil) 35 | StateDB, StateDBErr = leveldb.OpenFile("leveldb/state", nil) 36 | UsersDB, UsersDBErr = leveldb.OpenFile("leveldb/users", nil) 37 | TokensDB, TokensDBErr = leveldb.OpenFile("leveldb/tokens", nil) 38 | 39 | Year = strconv.Itoa(time.Now().UTC().Year()) 40 | ) 41 | 42 | const ( 43 | StatisticsSaveInterval = 1 * time.Minute 44 | ) 45 | 46 | type UserData struct { 47 | Login string `json:"login"` 48 | Password string `json:"password"` 49 | } 50 | -------------------------------------------------------------------------------- /application/backend/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/devforth/OnLogs 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/golang-jwt/jwt v3.2.2+incompatible 7 | github.com/gorilla/websocket v1.5.0 8 | github.com/joho/godotenv v1.4.0 9 | github.com/syndtr/goleveldb v1.0.0 10 | ) 11 | 12 | require ( 13 | github.com/golang/snappy v0.0.1 // indirect 14 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect 15 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect 16 | golang.org/x/text v0.3.7 // indirect 17 | gopkg.in/yaml.v2 v2.2.2 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /application/backend/go.sum: -------------------------------------------------------------------------------- 1 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 2 | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= 3 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 4 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 5 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 6 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 7 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 8 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 9 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 10 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 11 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 12 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= 13 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 14 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 15 | github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= 16 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 17 | github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= 18 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 19 | github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= 20 | github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= 21 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 22 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 23 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= 24 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 25 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 26 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 27 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 28 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= 29 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 30 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 31 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 32 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 33 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 34 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 35 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 36 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 37 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 38 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 39 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 40 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 41 | -------------------------------------------------------------------------------- /application/backend/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | 8 | "github.com/devforth/OnLogs/app/db" 9 | "github.com/devforth/OnLogs/app/routes" 10 | "github.com/devforth/OnLogs/app/streamer" 11 | "github.com/devforth/OnLogs/app/util" 12 | "github.com/joho/godotenv" 13 | ) 14 | 15 | func init_config() { 16 | if os.Getenv("PORT") == "" { 17 | os.Setenv("PORT", "2874") 18 | } 19 | 20 | if os.Getenv("JWT_SECRET") == "" { 21 | token, err := os.ReadFile("leveldb/JWT_secret") 22 | if err != nil { 23 | os.WriteFile("leveldb/JWT_secret", []byte(os.Getenv("JWT_SECRET")), 0700) 24 | token, _ = os.ReadFile("leveldb/JWT_secret") 25 | } 26 | os.Setenv("JWT_SECRET", string(token)) 27 | } 28 | 29 | if os.Getenv("DOCKER_SOCKET_PATH") == "" { 30 | os.Setenv("DOCKER_SOCKET_PATH", "/var/run/docker.sock") 31 | } 32 | 33 | if os.Getenv("MAX_LOGS_SIZE") == "" { 34 | os.Setenv("MAX_LOGS_SIZE", "10GB") 35 | } 36 | 37 | fmt.Println("INFO: OnLogs configs done!") 38 | } 39 | 40 | func main() { 41 | godotenv.Load(".env") 42 | init_config() 43 | if os.Getenv("AGENT") != "" { 44 | streamer.StreamLogs() 45 | } 46 | 47 | go db.DeleteUnusedTokens() 48 | go streamer.StreamLogs() 49 | // go util.RunSpaceMonitoring() 50 | util.ReplacePrefixVariableForFrontend() 51 | util.CreateInitUser() 52 | 53 | pathPrefix := os.Getenv("ONLOGS_PATH_PREFIX") 54 | http.HandleFunc(pathPrefix+"/", routes.Frontend) 55 | http.HandleFunc(pathPrefix+"/api/v1/addHost", routes.AddHost) 56 | http.HandleFunc(pathPrefix+"/api/v1/addLogLine", routes.AddLogLine) 57 | http.HandleFunc(pathPrefix+"/api/v1/askForDelete", routes.AskForDelete) 58 | http.HandleFunc(pathPrefix+"/api/v1/changeFavorite", routes.ChangeFavourite) 59 | http.HandleFunc(pathPrefix+"/api/v1/checkCookie", routes.CheckCookie) 60 | http.HandleFunc(pathPrefix+"/api/v1/createUser", routes.CreateUser) 61 | http.HandleFunc(pathPrefix+"/api/v1/deleteContainer", routes.DeleteContainer) 62 | http.HandleFunc(pathPrefix+"/api/v1/deleteContainerLogs", routes.DeleteContainerLogs) 63 | http.HandleFunc(pathPrefix+"/api/v1/deleteDockerLogs", routes.DeleteDockerLogs) 64 | http.HandleFunc(pathPrefix+"/api/v1/deleteUser", routes.DeleteUser) 65 | http.HandleFunc(pathPrefix+"/api/v1/editHostname", routes.EditHostname) 66 | http.HandleFunc(pathPrefix+"/api/v1/editUser", routes.EditUser) 67 | http.HandleFunc(pathPrefix+"/api/v1/getChartData", routes.GetChartData) 68 | http.HandleFunc(pathPrefix+"/api/v1/getDockerSize", routes.GetDockerSize) 69 | http.HandleFunc(pathPrefix+"/api/v1/getHosts", routes.GetHosts) 70 | http.HandleFunc(pathPrefix+"/api/v1/getLogWithPrev", routes.GetLogWithPrev) 71 | http.HandleFunc(pathPrefix+"/api/v1/getLogs", routes.GetLogs) 72 | http.HandleFunc(pathPrefix+"/api/v1/getLogsStream", routes.GetLogsStream) 73 | http.HandleFunc(pathPrefix+"/api/v1/getPrevLogs", routes.GetPrevLogs) 74 | http.HandleFunc(pathPrefix+"/api/v1/getSecret", routes.GetSecret) 75 | http.HandleFunc(pathPrefix+"/api/v1/getSizeByAll", routes.GetSizeByAll) 76 | http.HandleFunc(pathPrefix+"/api/v1/getSizeByService", routes.GetSizeByService) 77 | http.HandleFunc(pathPrefix+"/api/v1/getStats", routes.GetStats) 78 | http.HandleFunc(pathPrefix+"/api/v1/getStorageData", routes.GetStorageData) 79 | http.HandleFunc(pathPrefix+"/api/v1/getUserSettings", routes.GetUserSettings) 80 | http.HandleFunc(pathPrefix+"/api/v1/getUsers", routes.GetUsers) 81 | http.HandleFunc(pathPrefix+"/api/v1/login", routes.Login) 82 | http.HandleFunc(pathPrefix+"/api/v1/logout", routes.Logout) 83 | http.HandleFunc(pathPrefix+"/api/v1/updateUserSettings", routes.UpdateUserSettings) 84 | 85 | fmt.Println("Listening on port:", string(os.Getenv("PORT"))+"...") 86 | fmt.Println("ONLOGS: ", http.ListenAndServe(":"+string(os.Getenv("PORT")), nil)) 87 | } 88 | -------------------------------------------------------------------------------- /application/build.sh: -------------------------------------------------------------------------------- 1 | # docker buildx create --use 2 | docker buildx build --load --platform=linux/amd64,linux/arm64 --tag "devforth/onlogs:latest" --tag "devforth/onlogs:1.1.4" . 3 | -------------------------------------------------------------------------------- /application/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | *.prettierrc 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | .env 27 | 28 | -------------------------------------------------------------------------------- /application/frontend/.storybook/main.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "stories": [ 3 | "../src/**/*.stories.mdx", 4 | "../src/**/*.stories.@(js|jsx|ts|tsx|svelte)" 5 | ], 6 | "addons": [ 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-interactions" 10 | ], 11 | "framework": "@storybook/svelte", 12 | "core": { 13 | "builder": "@storybook/builder-vite" 14 | }, 15 | "features": { 16 | "storyStoreV7": true 17 | } 18 | } -------------------------------------------------------------------------------- /application/frontend/.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /application/frontend/.storybook/preview.cjs: -------------------------------------------------------------------------------- 1 | import "../src/main.scss"; 2 | 3 | export const parameters = { 4 | actions: { argTypesRegex: "^on[A-Z].*" }, 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/, 9 | }, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /application/frontend/generate_font.js: -------------------------------------------------------------------------------- 1 | import webfontsGenerator from "@vusion/webfonts-generator"; 2 | import fs from "fs"; 3 | 4 | fs.readdir("src/assets/res/font", function (err, items) { 5 | if (err) { 6 | console.log("cant read res directory"); 7 | } 8 | const files = items 9 | .filter((i) => i.toLowerCase().endsWith(".svg")) 10 | .map((i) => { 11 | return `src/assets/res/font/${i}`; 12 | }); 13 | 14 | webfontsGenerator( 15 | { 16 | files: files, 17 | dest: "src/assets/res", 18 | fontName: "onLogsFont", 19 | 20 | 21 | // https://github.com/nfroidure/svgicons2svgfont options 22 | normalize: true, 23 | html: true, 24 | cssTemplate: "src/assets/res/font/font-css.hbs", 25 | templateOptions: { 26 | classPrefix: "log-", 27 | baseSelector: ".log", 28 | }, 29 | types: ["svg", "ttf", "woff", "woff2", "eot"], 30 | }, 31 | function (error) { 32 | if (error) { 33 | console.log("Fail!", error); 34 | } else { 35 | console.log("Done!"); 36 | } 37 | } 38 | ); 39 | }); 40 | -------------------------------------------------------------------------------- /application/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | OnLogs 29 | 30 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /application/frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "Node", 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | /** 7 | * svelte-preprocess cannot figure out whether you have 8 | * a value or a type, so tell TypeScript to enforce using 9 | * `import type` instead of `import` for Types. 10 | */ 11 | "importsNotUsedAsValues": "error", 12 | "isolatedModules": true, 13 | "resolveJsonModule": true, 14 | /** 15 | * To have warnings / errors of the Svelte compiler at the 16 | * correct position, enable source maps by default. 17 | */ 18 | "sourceMap": true, 19 | "esModuleInterop": true, 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "baseUrl": ".", 23 | /** 24 | * Typecheck JS in `.svelte` and `.js` files by default. 25 | * Disable this if you'd like to use dynamic types. 26 | */ 27 | "checkJs": true 28 | }, 29 | /** 30 | * Use global.d.ts instead of compilerOptions.types 31 | * to avoid limiting type declarations. 32 | */ 33 | "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte", "generate_font.js"] 34 | } 35 | -------------------------------------------------------------------------------- /application/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build --base=/ONLOGS_PREFIX_ENV_VARIABLE_THAT_SHOULD_BE_REPLACED_ON_BACKEND_INITIALIZATION ", 9 | "test": "vite build --base=/ONLOGS_PREFIX_ENV_VARIABLE_THAT_SHOULD_BE_REPLACED_ON_BACKEND_INITIALIZATION && node startDebug.js ", 10 | "preview": "vite preview", 11 | "sb": "start-storybook -p 6006", 12 | "build-storybook": "build-storybook", 13 | "buildfont": "node generate_font.js" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.19.3", 17 | "@storybook/addon-actions": "^6.5.12", 18 | "@storybook/addon-essentials": "^6.5.12", 19 | "@storybook/addon-interactions": "^6.5.12", 20 | "@storybook/addon-links": "^6.5.12", 21 | "@storybook/builder-vite": "^0.2.3", 22 | "@storybook/svelte": "^6.5.12", 23 | "@storybook/testing-library": "^0.0.13", 24 | "@sveltejs/vite-plugin-svelte": "^1.0.2", 25 | "eslint-plugin-svelte3": "^4.0.0", 26 | "fs-extra": "^11.1.0", 27 | "sass": "^1.55.0", 28 | "svelte": "^3.49.0", 29 | "svelte-intersection-observer": "^0.10.0", 30 | "vite": "^3.1.0" 31 | }, 32 | "dependencies": { 33 | "@vusion/webfonts-generator": "^0.8.0", 34 | "chart.js": "^4.2.0", 35 | "json-to-html": "^0.1.2", 36 | "svelte-chartjs": "^3.1.2", 37 | "svelte-loading-spinners": "^0.3.4", 38 | "svelte-routing": "^1.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /application/frontend/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /application/frontend/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /application/frontend/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/apple-touch-icon.png -------------------------------------------------------------------------------- /application/frontend/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /application/frontend/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/favicon-16x16.png -------------------------------------------------------------------------------- /application/frontend/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/favicon-32x32.png -------------------------------------------------------------------------------- /application/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/favicon.ico -------------------------------------------------------------------------------- /application/frontend/public/favicon_package_v0.16.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/favicon_package_v0.16.zip -------------------------------------------------------------------------------- /application/frontend/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/public/mstile-150x150.png -------------------------------------------------------------------------------- /application/frontend/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /application/frontend/src/App.svelte: -------------------------------------------------------------------------------- 1 | 83 | 84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
94 |
95 |
96 | {#if $toastIsVisible} {/if} 97 |
98 | -------------------------------------------------------------------------------- /application/frontend/src/Stores/stores.js: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | 3 | export const store = writable({ 4 | UTCtime: true, 5 | breakLines: true, 6 | // used insensitive prop coz for now default value MUST be true 7 | caseInSensitive: true, 8 | transformJson: true, 9 | deleteFromDocker: false, 10 | }); 11 | 12 | //chosen logs string 13 | export const chosenLogsString = writable(""); 14 | 15 | //modals state 16 | export const userMenuOpen = writable(false); 17 | export const userDeleteOpen = writable(false); 18 | export const addUserModalOpen = writable(false); 19 | export const editUserOpen = writable(false); 20 | 21 | export const theme = writable("light"); 22 | 23 | // hosts service 24 | 25 | export const lastChosenHost = writable(""); 26 | export const lastChosenService = writable(""); 27 | 28 | // toast state 29 | 30 | export const toast = writable({ 31 | tittle: "", 32 | message: "", 33 | position: "", 34 | status: "", 35 | additionButton: {}, 36 | }); 37 | export const toastIsVisible = writable(false); 38 | export const toastTimeoutId = writable(null); 39 | 40 | // active menu option 41 | export const activeMenuOption = writable("home"); 42 | 43 | //add host menu 44 | export const addHostMenuIsVisible = writable(false); 45 | 46 | //snippet modal 47 | export const snipetModalIsVisible = writable(false); 48 | export const currentSnippedOption = writable("Docker"); 49 | 50 | //hosts list scroll is visible 51 | export const listScrollIsVisible = writable(false); 52 | 53 | //confirmation menu 54 | export const confirmationObj = writable({ 55 | action: function () {}, 56 | message: 57 | "You want to delete host service logs. This data will be lost. This action cannot be undone.", 58 | 59 | isVisible: false, 60 | }); 61 | 62 | //serviceSettings 63 | export const lastChosenSetting = writable("General"); 64 | 65 | //make highlightsLogs 66 | 67 | export const lastLogTimestamp = writable(0); 68 | 69 | //stats 70 | export const lastStatsPeriod = writable(2); 71 | export const lastStatisticPeriod = writable("Per hour"); 72 | 73 | //spiner 74 | 75 | export const isPending = writable(false); 76 | 77 | //url hash 78 | 79 | export const urlHash = writable(""); 80 | 81 | //cancel fetch (for bed connection) 82 | 83 | export const isFeatching = writable(false); 84 | export const isSearching = writable(false); 85 | 86 | //status for serching logs by status 87 | 88 | export const chosenStatus = writable(""); 89 | 90 | //last logTime for logsStream 91 | export const lastLogTime = writable(""); 92 | 93 | // webSocket isMuted 94 | export const WSisMuted = writable(false); 95 | export const manuallyUnmuted = writable(false); 96 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Login/Login.scss: -------------------------------------------------------------------------------- 1 | div.login.contentContainer { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | } 6 | 7 | div.loginForm { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | gap: 20px; 12 | padding: 0 15px 0 15px; 13 | 14 | h1#title { 15 | color: $active-color; 16 | } 17 | 18 | input { 19 | font-family: "Ubuntu"; 20 | font-style: normal; 21 | font-weight: 700; 22 | font-size: 14px; 23 | height: 30px; 24 | padding-left: 15px; 25 | background-color: #f8fafb; 26 | border: 1px solid #a3a3b9; 27 | border-radius: 10px; 28 | :focus { 29 | outline: none; 30 | } 31 | } 32 | 33 | input.wrong { 34 | border: 1px solid red; 35 | } 36 | 37 | div.bottom { 38 | display: flex; 39 | width: 100%; 40 | align-items: center; 41 | justify-content: space-between; 42 | 43 | p { 44 | font-family: "Ubuntu"; 45 | font-style: normal; 46 | // font-weight: 700; 47 | font-weight: 400; 48 | font-size: 12px; 49 | visibility: hidden; 50 | color: red; 51 | } 52 | 53 | p.wrong { 54 | visibility: initial; 55 | } 56 | 57 | div.confirmButton { 58 | box-shadow: 1px 1px 15px rgba(5, 39, 70, 0.3); 59 | border-radius: 20px; 60 | } 61 | } 62 | form { 63 | display: flex; 64 | flex-direction: column; 65 | gap: 20px; 66 | } 67 | } 68 | .loginContainer { 69 | display: flex; 70 | min-height: 25vh; 71 | min-width: 20vw; 72 | 73 | position: absolute; 74 | left: 50%; 75 | top: 50%; 76 | transform: translate(-50%, -50%); 77 | justify-content: center; 78 | align-items: center; 79 | background-color: $block-bg-color; 80 | border-radius: $main-border-radius; 81 | padding: $normal-padding; 82 | } 83 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Login/Login.svelte: -------------------------------------------------------------------------------- 1 | 45 | 46 |
47 |
48 |

onLogs

49 |
50 | { 56 | wrong = ""; 57 | }} 58 | /> 59 | { 66 | wrong = ""; 67 | }} 68 | /> 69 |
70 |
71 |

{message}

72 |
73 |
81 |
82 |
83 |
84 | 85 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Logs/Loader.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Logs/LogStringHeader.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Logs/LogsViewHeder/LogsViewHeder.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 |
29 |

Service logs

30 |

recent at bottom

31 | 36 | {#if !isSearchVIsible} 37 |
42 |
53 |
54 |
62 | {/if} 63 |
64 |
74 | 86 |
87 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Logs/Spiner.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 | 14 |
15 | -------------------------------------------------------------------------------- /application/frontend/src/Views/Main/SettingsController.svelte: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /application/frontend/src/Views/ServiceSettings/Acess.svelte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/src/Views/ServiceSettings/Acess.svelte -------------------------------------------------------------------------------- /application/frontend/src/Views/ServiceSettings/General.svelte: -------------------------------------------------------------------------------- 1 | 43 | 44 |
45 |

Change settings for current service:

46 |

HOST: {$lastChosenHost}

47 |

SERVICE: {$lastChosenService}

48 |
49 |

50 | Delete this service 51 | Once you delete a service, there is no going back. Please be certain. 52 |

53 |
54 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /application/frontend/src/Views/ServiceSettings/ServiceSettings.scss: -------------------------------------------------------------------------------- 1 | .serviceSettings { 2 | margin: $container-padding; 3 | @include for-mobile { 4 | text-align: center; 5 | margin: 0; 6 | margin-top: 30px; 7 | } 8 | .title { 9 | margin-bottom: 24px; 10 | padding-bottom: 16px; 11 | border-bottom: 1px solid $lines-color; 12 | } 13 | .text { 14 | margin: 16px; 15 | } 16 | .actionThumb { 17 | display: flex; 18 | justify-content: space-between; 19 | align-items: center; 20 | margin-top: 26px; 21 | @include for-mobile { 22 | flex-direction: column; 23 | text-align: center; 24 | } 25 | } 26 | .actionTitle { 27 | display: flex; 28 | flex-direction: column; 29 | @include for-mobile { 30 | margin-bottom: 12px; 31 | } 32 | } 33 | span { 34 | font-weight: 700; 35 | margin-bottom: 12px; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /application/frontend/src/Views/ServiceSettings/ServiceSettings.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | {#if $lastChosenSetting.trim() === "General"} 9 | 10 | {/if} 11 | {#if $lastChosenSetting.trim() === "Acess"} 12 | 13 | {/if} 14 |
15 | -------------------------------------------------------------------------------- /application/frontend/src/Views/ServiceSettings/ServiceSettingsLeft.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Archive.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/ArrowRight.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Break.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Burger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Chart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Clean.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Colums.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Combine.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Cut.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Data.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/EmptyHeart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Eye.svg: -------------------------------------------------------------------------------- 1 | 2 | /> 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Json.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Last.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Leters.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Moon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Pointer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Server.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/ShareLink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Success.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Sun.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Tips.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/User.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/Wheel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/font/font-css.hbs: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "{{fontName}}"; 3 | src: {{{src}}}; 4 | font-weight: normal; 5 | font-style: normal; 6 | } 7 | 8 | {{baseSelector}} { 9 | } 10 | 11 | {{baseSelector}}:before { 12 | font-family: {{fontName}} !important; 13 | font-style: normal !important; 14 | font-weight: normal !important; 15 | font-variant: normal !important; 16 | text-transform: none !important; 17 | speak: none; 18 | -webkit-font-smoothing: antialiased; 19 | -moz-osx-font-smoothing: grayscale; 20 | } 21 | 22 | {{#each codepoints}} 23 | .{{../classPrefix}}{{@key}}:before { 24 | content: "\\{{this}}"; 25 | } 26 | {{/each}} -------------------------------------------------------------------------------- /application/frontend/src/assets/res/onLogsFont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "onLogsFont"; 3 | src: url("onLogsFont.eot?b1b1fa2c569a9742068bfa91c7006c7a?#iefix") format("embedded-opentype"), 4 | url("onLogsFont.woff2?b1b1fa2c569a9742068bfa91c7006c7a") format("woff2"), 5 | url("onLogsFont.woff?b1b1fa2c569a9742068bfa91c7006c7a") format("woff"), 6 | url("onLogsFont.ttf?b1b1fa2c569a9742068bfa91c7006c7a") format("truetype"), 7 | url("onLogsFont.svg?b1b1fa2c569a9742068bfa91c7006c7a#onLogsFont") format("svg"); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | .log { 13 | } 14 | 15 | .log:before { 16 | font-family: onLogsFont !important; 17 | font-style: normal !important; 18 | font-weight: normal !important; 19 | font-variant: normal !important; 20 | text-transform: none !important; 21 | speak: none; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .log-Alert:before { 27 | content: "\f101"; 28 | } 29 | .log-Archive:before { 30 | content: "\f102"; 31 | } 32 | .log-ArrowRight:before { 33 | content: "\f103"; 34 | } 35 | .log-Break:before { 36 | content: "\f104"; 37 | } 38 | .log-Burger:before { 39 | content: "\f105"; 40 | } 41 | .log-Chart:before { 42 | content: "\f106"; 43 | } 44 | .log-Clean:before { 45 | content: "\f107"; 46 | } 47 | .log-Clock:before { 48 | content: "\f108"; 49 | } 50 | .log-Close:before { 51 | content: "\f109"; 52 | } 53 | .log-Colums:before { 54 | content: "\f10a"; 55 | } 56 | .log-Combine:before { 57 | content: "\f10b"; 58 | } 59 | .log-Copy:before { 60 | content: "\f10c"; 61 | } 62 | .log-Cut:before { 63 | content: "\f10d"; 64 | } 65 | .log-Data:before { 66 | content: "\f10e"; 67 | } 68 | .log-Down:before { 69 | content: "\f10f"; 70 | } 71 | .log-EmptyHeart:before { 72 | content: "\f110"; 73 | } 74 | .log-Error:before { 75 | content: "\f111"; 76 | } 77 | .log-Eye:before { 78 | content: "\f112"; 79 | } 80 | .log-Filter:before { 81 | content: "\f113"; 82 | } 83 | .log-Group:before { 84 | content: "\f114"; 85 | } 86 | .log-Heart:before { 87 | content: "\f115"; 88 | } 89 | .log-Home:before { 90 | content: "\f116"; 91 | } 92 | .log-Info:before { 93 | content: "\f117"; 94 | } 95 | .log-Json:before { 96 | content: "\f118"; 97 | } 98 | .log-Last:before { 99 | content: "\f119"; 100 | } 101 | .log-Leters:before { 102 | content: "\f11a"; 103 | } 104 | .log-Logout:before { 105 | content: "\f11b"; 106 | } 107 | .log-Moon:before { 108 | content: "\f11c"; 109 | } 110 | .log-Pencil:before { 111 | content: "\f11d"; 112 | } 113 | .log-Plus:before { 114 | content: "\f11e"; 115 | } 116 | .log-Pointer:before { 117 | content: "\f11f"; 118 | } 119 | .log-Refresh:before { 120 | content: "\f120"; 121 | } 122 | .log-Search:before { 123 | content: "\f121"; 124 | } 125 | .log-Server:before { 126 | content: "\f122"; 127 | } 128 | .log-Share:before { 129 | content: "\f123"; 130 | } 131 | .log-ShareLink:before { 132 | content: "\f124"; 133 | } 134 | .log-Success:before { 135 | content: "\f125"; 136 | } 137 | .log-Sun:before { 138 | content: "\f126"; 139 | } 140 | .log-Tips:before { 141 | content: "\f127"; 142 | } 143 | .log-User:before { 144 | content: "\f128"; 145 | } 146 | .log-Warning:before { 147 | content: "\f129"; 148 | } 149 | .log-Wheel:before { 150 | content: "\f12a"; 151 | } 152 | -------------------------------------------------------------------------------- /application/frontend/src/assets/res/onLogsFont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/src/assets/res/onLogsFont.eot -------------------------------------------------------------------------------- /application/frontend/src/assets/res/onLogsFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/src/assets/res/onLogsFont.ttf -------------------------------------------------------------------------------- /application/frontend/src/assets/res/onLogsFont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/src/assets/res/onLogsFont.woff -------------------------------------------------------------------------------- /application/frontend/src/assets/res/onLogsFont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/src/assets/res/onLogsFont.woff2 -------------------------------------------------------------------------------- /application/frontend/src/lib/Button/Button.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | font-family: "Ubuntu", sans-serif; 3 | line-height: 1; 4 | height: 100%; 5 | 6 | background-color: $btn-primary-color; 7 | border-radius: $main-border-radius; 8 | 9 | font-size: $main-font-s; 10 | color: $text-dark-color; 11 | font-weight: 400; 12 | line-height: $line-height; 13 | padding-left: $normal-padding; 14 | padding-right: $normal-padding; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | cursor: pointer; 19 | 20 | &.highlighted { 21 | background-color: $active-color; 22 | color: $text-onactive-color; 23 | } 24 | &.border { 25 | box-shadow: $main-shadow; 26 | } 27 | 28 | .iconWidthText { 29 | padding-right: $normal-padding; 30 | } 31 | &:disabled { 32 | opacity: 0.6; 33 | transform: none; 34 | cursor: auto; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Button/Button.stories.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import Button from "./Button.svelte"; 3 | import { action } from "@storybook/addon-actions"; 4 | import "../../assets/res/onLogsFont.css"; 5 | 6 | export const actionsData = { 7 | onCkickButton: action("onClickButton"), 8 | }; 9 | 10 | export default { 11 | component: Button, 12 | title: "Button", 13 | excludeStories: /.*Data$/, 14 | //👇 The argTypes are included so that they are properly displayed in the Actions Panel 15 | argTypes: { 16 | onCkickButton: { action: "onClickButton" }, 17 | }, 18 | }; 19 | 20 | const Template = ({ onCkickButton, ...args }) => ({ 21 | Component: Button, 22 | props: args, 23 | on: { 24 | ...actionsData, 25 | }, 26 | }); 27 | 28 | export const Default = Template.bind({}); 29 | Default.args = { 30 | title: "Text", 31 | border: true, 32 | highlighted: false, 33 | minWidth: 90, 34 | minHeight: 32, 35 | icon: "", 36 | state: "BUTTON_TEXT", 37 | iconHeight: 12, 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Button/Button.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 | 43 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ButtonToBottom/ButtonToBottom.scss: -------------------------------------------------------------------------------- 1 | .buttonToBottomContainer { 2 | width: 40px; 3 | height: 40px; 4 | 5 | color: white; 6 | border-radius: $main-border-radius; 7 | box-shadow: $main-shadow; 8 | @include center; 9 | position: absolute; 10 | bottom: 20px; 11 | right: 20px; 12 | background-color: $active-color; 13 | opacity: 0.4; 14 | &:hover { 15 | opacity: 1; 16 | cursor: pointer; 17 | } 18 | .icoContainer { 19 | @include center; 20 | font-size: 14px; 21 | z-index: 4; 22 | color: $text-onactive-color; 23 | } 24 | @include for-mobile { 25 | bottom: 110px; 26 | } 27 | 28 | .buttonToBottomNumber { 29 | position: absolute; 30 | background-color: $background-color-dark; 31 | border-radius: 6px; 32 | min-width: 50%; 33 | 34 | top: 0; 35 | right: 0; 36 | 37 | padding: 2px; 38 | 39 | transform: translate(0, -70%); 40 | } 41 | } 42 | 43 | .subContainerMiddle .subContainer { 44 | position: relative; 45 | } 46 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ButtonToBottom/ButtonToBottom.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
{ 11 | await callBack(); 12 | }} 13 | > 14 |
15 | 16 |
17 | {#if number}
18 |

{number}

19 |
20 | {/if} 21 |
22 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ChartMenu/ChartMenu.scss: -------------------------------------------------------------------------------- 1 | .chartHeader { 2 | ul { 3 | margin-top: 12px; 4 | // gap: 6px; 5 | } 6 | 7 | .item { 8 | flex: 1; 9 | font-size: $main-font-m; 10 | box-shadow: $main-shadow-dark; 11 | 12 | cursor: pointer; 13 | &.isActive { 14 | color: $active-color; 15 | } 16 | &:first-child { 17 | border-top-left-radius: $main-border-radius; 18 | border-bottom-left-radius: $main-border-radius; 19 | } 20 | &:last-child { 21 | border-top-right-radius: $main-border-radius; 22 | border-bottom-right-radius: $main-border-radius; 23 | } 24 | // border-radius: $main-border-radius; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ChartMenu/MainChartMenu.svelte: -------------------------------------------------------------------------------- 1 | 26 | 27 |
28 |

Logs statistic:

29 | 30 |
31 |
    32 | {#each headerOptions as option} 33 |
  • { 36 | lastStatisticPeriod.set(option); 37 | }} 38 | > 39 | {option} 40 |
  • {/each} 41 |
42 |
43 | 44 |
45 | -------------------------------------------------------------------------------- /application/frontend/src/lib/CheckBox/CheckBox.scss: -------------------------------------------------------------------------------- 1 | .checkboxContainer { 2 | width: 47px; 3 | height: 28px; 4 | background-color: $lines-color; 5 | border-radius: 30px; 6 | display: flex; 7 | align-items: center; 8 | padding: 5px; 9 | box-sizing: border-box; 10 | justify-content: start; 11 | cursor: pointer; 12 | position: relative; 13 | } 14 | 15 | .active { 16 | .checkboxRoll { 17 | background-color: $active-color; 18 | position: absolute; 19 | transform: translateX(85%); 20 | transition: all 100ms; 21 | } 22 | } 23 | 24 | .inactive { 25 | .checkboxRoll { 26 | transform: translateX(0); 27 | transition: all 200ms; 28 | } 29 | 30 | .checkboxRoll { 31 | background-color: $btn-common-color; 32 | } 33 | } 34 | 35 | .checkboxRoll { 36 | width: 20px; 37 | height: 20px; 38 | background-color: $active-color; 39 | border-radius: 100%; 40 | } 41 | -------------------------------------------------------------------------------- /application/frontend/src/lib/CheckBox/Checkbox.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ClientPanel/ClientPanel.scss: -------------------------------------------------------------------------------- 1 | div.clientPanel { 2 | height: 100%; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | 7 | i { 8 | font-size: 27px; 9 | line-height: 1; 10 | color: $text-dark-color; 11 | } 12 | ul { 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | height: 100%; 17 | } 18 | li { 19 | width: 100%; 20 | height: 100%; 21 | padding: 0%; 22 | cursor: pointer; 23 | margin: 0; 24 | position: relative; 25 | display: flex; 26 | align-items: center; 27 | justify-content: center; 28 | &:hover { 29 | opacity: 0.8; 30 | } 31 | &.active i { 32 | color: $active-color; 33 | } 34 | 35 | .higlightedOverlay.active { 36 | position: absolute; 37 | 38 | background-color: rgba(0, 0, 0, 0.05); 39 | width: 100%; 40 | height: calc(100% + 32px); 41 | top: -16px; 42 | left: 0; 43 | z-index: -1; 44 | 45 | &.active { 46 | background: rgba(140, 168, 254, 0.1); 47 | border-bottom: 6px solid $active-color; 48 | box-sizing: border-box; 49 | z-index: 1; 50 | } 51 | } 52 | } 53 | 54 | .clientPanelOptionsList { 55 | width: 100%; 56 | display: flex; 57 | justify-content: space-between; 58 | } 59 | 60 | .burger { 61 | @include for-tablet { 62 | @include hide; 63 | } 64 | } 65 | .burger { 66 | @include for-desctop { 67 | @include hide; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ClientPanel/ClientPanel.svelte: -------------------------------------------------------------------------------- 1 | 47 | 48 |
49 |
    50 |
  • { 52 | if ($activeMenuOption === "burger") { 53 | activeMenuOption.set(location.pathname.split("/")[1] || "home"); 54 | } else { 55 | activeMenuOption.set("burger"); 56 | } 57 | }} 58 | class="{$activeMenuOption === 'burger' && 'active'} burger" 59 | > 60 | 61 |
    64 |
  • 65 |
  • 66 | 67 |
    71 |
  • 72 |
  • 76 | 77 |
    80 |
  • 81 | 82 | 85 |
  • 86 | 87 |
  • 88 |
89 |
90 | -------------------------------------------------------------------------------- /application/frontend/src/lib/CommonList/CommonList.scss: -------------------------------------------------------------------------------- 1 | .commonList { 2 | margin-top: 24px; 3 | margin-left: 16px; 4 | margin-right: 16px; 5 | li { 6 | margin: 0; 7 | position: relative; 8 | cursor: default; 9 | &.clickable { 10 | cursor: pointer; 11 | } 12 | } 13 | li:hover { 14 | opacity: 0.8; 15 | .log { 16 | font-size: $main-font-l; 17 | opacity: 1; 18 | cursor: pointer; 19 | } 20 | } 21 | .listElement { 22 | @include center; 23 | justify-content: space-between; 24 | } 25 | .name { 26 | font-size: $main-font-s; 27 | } 28 | .log { 29 | font-size: $main-font-l; 30 | opacity: 0; 31 | } 32 | .highlightedOverlay { 33 | position: absolute; 34 | 35 | background-color: rgba(0, 0, 0, 0.05); 36 | width: calc(100% + 40px); 37 | height: 100%; 38 | top: 0; 39 | z-index: -1; 40 | margin-left: -16px; 41 | // margin-right: -16px; 42 | 43 | &.active { 44 | background: rgba(251, 252, 255, 0.1); 45 | border-left: 9px solid $text-dark-color-dark; 46 | box-sizing: border-box; 47 | z-index: 1; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /application/frontend/src/lib/CommonList/CommonList.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |
    12 | {#each listData as listEl, index} 13 |
  • { 16 | isRowClickable && storeProp?.set && storeProp.set(listEl.name); 17 | initialActive = null; 18 | listEl.callBack(); 19 | }} 20 | > 21 |
    22 |

    23 | {listEl.name} 24 |

    25 |
    26 |
    27 | 28 |
    29 |
    34 |
  • 35 | {/each} 36 |
37 |
38 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ConfirmationMenu/ConfirmationMenu.scss: -------------------------------------------------------------------------------- 1 | .deleteModalContainer { 2 | background-color: $block-bg-color; 3 | font-size: $main-font-m; 4 | position: absolute; 5 | left: 50%; 6 | top: 50%; 7 | transform: translate(-50%, -50%); 8 | padding: $normal-padding; 9 | border-radius: $main-border-radius; 10 | box-shadow: $main-shadow; 11 | min-width: 350px; 12 | z-index: 7; 13 | 14 | max-width: 450px; 15 | @include for-mobile { 16 | width: 80vw; 17 | } 18 | .confirmationName { 19 | margin: 20px 0 20px 0; 20 | } 21 | 22 | .buttonsBox { 23 | display: flex; 24 | justify-content: space-between; 25 | margin-top: 24px; 26 | } 27 | .boldText { 28 | font-weight: 800; 29 | } 30 | 31 | .deleteModalTitle { 32 | margin-top: 16px; 33 | margin-bottom: 16px; 34 | text-align: center; 35 | } 36 | 37 | .optionsBox { 38 | display: flex; 39 | flex-direction: column; 40 | margin-top: 24px; 41 | margin-bottom: 24px; 42 | align-items: center; 43 | } 44 | 45 | .optionBox { 46 | display: grid; 47 | grid-template-columns: 1fr 1fr; 48 | // margin-left: 62px; 49 | p, 50 | .checkboxContainerThumb { 51 | display: flex; 52 | align-items: center; 53 | justify-content: center; 54 | } 55 | } 56 | .buttonsBox { 57 | display: flex; 58 | justify-content: space-between; 59 | align-items: center; 60 | margin-top: 24px; 61 | } 62 | 63 | .confirmationText { 64 | .boldText { 65 | font-weight: 700; 66 | } 67 | } 68 | 69 | .log-Tips { 70 | line-height: 1; 71 | font-size: $main-font-m; 72 | position: absolute; 73 | right: 16px; 74 | top: 16px; 75 | color: $lines-color; 76 | } 77 | } 78 | .tipsContainer { 79 | position: relative; 80 | } 81 | 82 | .tipsText { 83 | position: absolute; 84 | line-height: 1.5; 85 | top: 0%; 86 | right: 0%; 87 | transform: translate(106%); 88 | max-width: 236px; 89 | background-color: $block-bg-color; 90 | z-index: 8; 91 | height: 238px !important; 92 | font-size: $main-font-s; 93 | border-radius: $main-border-radius; 94 | box-shadow: $main-shadow; 95 | @include for-mobile { 96 | transform: translate(0%, -108%); 97 | } 98 | @include for-tablet { 99 | transform: translate(0%, -108%); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ConfirmationMenu/ConfirmationMenu.svelte: -------------------------------------------------------------------------------- 1 | 68 | 69 |
70 |
71 | { 74 | tipsIsVisible = true; 75 | }} 76 | on:mouseleave={() => { 77 | tipsIsVisible = false; 78 | }} 79 | /> 80 | {#if tipsIsVisible} 81 |
82 | Delete Docker logs - when the option is set to 83 | "OFF" 84 | logs will be deleted only from onLogs. Logs will be available in docker containers, but not for onLogs. 85 | When 86 | enabled , each deletion of logs will 87 | clear logs from both onLogs and the 88 | Docker container 89 | . 90 |
{/if} 91 |
92 | 93 |

Delete logs options

94 |
95 |
96 |

Delete Docker logs

97 |
98 | 99 |
100 |
101 |
102 |
103 |

104 | {`Host: ${ 105 | $lastChosenHost ? $lastChosenHost : "host" 106 | }`} 107 |

108 |

109 | {`Service: ${ 110 | $lastChosenService ? $lastChosenService : "service" 111 | }, from: `} 112 | 113 | {$confirmationObj.message} 116 |

117 |

This data will be lost. This action cannot be undone.

118 |
119 | 120 |
121 | Please type: "{confirmationWord}" to confirm. 124 |
125 |
126 | 132 |
133 |
134 |
154 |
155 |
156 | 157 | { 159 | key === "Escape" && closeMenu(); 160 | 161 | }} 162 | /> 163 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Container/Container.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | font-family: "Ubuntu", sans-serif; 3 | 4 | background-color: $btn-primary-color; 5 | border-radius: $large-border-radius; 6 | color: $text-dark-color; 7 | padding-left: $container-padding; 8 | padding-right: $container-padding; 9 | padding-top: $container-vertical-padding; 10 | padding-bottom: $container-vertical-padding; 11 | box-sizing: border-box; 12 | height: 100%; 13 | @include for-mobile { 14 | padding: 12px; 15 | border-radius: 0px; 16 | } 17 | 18 | &.highlighted { 19 | background-color: $active-color; 20 | color: $text-onactive-color; 21 | } 22 | &.border { 23 | box-shadow: $container-shadow; 24 | } 25 | &.paddingOff { 26 | padding: 0; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Container/Container.stories.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import ContainerView from "./ContainerView.svelte"; 3 | import Container from "./Container.svelte"; 4 | import "../../assets/res/onLogsFont.css"; 5 | 6 | 7 | 8 | export default { 9 | component: ContainerView, 10 | title: "Container", 11 | excludeStories: /.*Data$/, 12 | //👇 The argTypes are included so that they are properly displayed in the Actions Panel 13 | argTypes: { 14 | 15 | }, 16 | }; 17 | 18 | const Template = ({ ...args }) => ({ 19 | Component: ContainerView, 20 | props: args, 21 | }); 22 | 23 | export const Default = Template.bind({}); 24 | Default.args = { 25 | 26 | 27 | newHighlighted: false, 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Container/Container.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
16 | 17 |
18 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Container/ContainerView.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 |

Slot 1

9 |

Slot 2

10 |

Slot 3

11 |
-------------------------------------------------------------------------------- /application/frontend/src/lib/DropDown/DropDown.scss: -------------------------------------------------------------------------------- 1 | .dropDownContainer { 2 | box-shadow: $main-shadow; 3 | border-radius: $main-border-radius; 4 | background-color: $block-bg-color; 5 | padding: 20px; 6 | color: $text-dark-color; 7 | position: absolute; 8 | z-index: 5; 9 | width: max-content; 10 | right: 50%; 11 | top: 110%; 12 | transform: translate(50%); 13 | @include for-mobile { 14 | position: fixed; 15 | top: 60px; 16 | left: 0; 17 | transform: translate(20%, 0); 18 | } 19 | 20 | td { 21 | padding-top: 12px; 22 | vertical-align: middle; 23 | } 24 | & { 25 | right: 100%; 26 | transform: translate(25%); 27 | .dropDownRawEl.text { 28 | margin-right: 5px; 29 | } 30 | } 31 | 32 | &.addHost#addHost { 33 | @include for-mobile { 34 | padding: 12px; 35 | position: fixed; 36 | left: 0; 37 | right: 0; 38 | width: auto; 39 | top: 0; 40 | z-index: 150; 41 | transform: none; 42 | } 43 | } 44 | } 45 | 46 | .emptyBox { 47 | height: 28px; 48 | width: 1px; 49 | opacity: 0; 50 | } 51 | 52 | .dropDownRawEl.ico { 53 | margin-right: 12px; 54 | } 55 | 56 | .dropDownRawEl.text { 57 | margin-right: 26px; 58 | font-size: $main-font-s; 59 | } 60 | 61 | .rowContainer { 62 | margin-bottom: 20px; 63 | } 64 | 65 | .isFirst { 66 | td { 67 | padding-top: 0; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /application/frontend/src/lib/DropDown/DropDown.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 32 | -------------------------------------------------------------------------------- /application/frontend/src/lib/DropDown/DropDownAddHost.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | -------------------------------------------------------------------------------- /application/frontend/src/lib/DropDown/dropDownRow.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 | { 21 | if (titleCallBack) { 22 | titleCallBack(); 23 | } 24 | }} 25 | > 26 | 27 | 28 | 35 | 36 | 37 | 38 | {#if !disableCheckbox} 40 | {:else} 41 |
42 | {/if} 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /application/frontend/src/lib/HostList/HostList.scss: -------------------------------------------------------------------------------- 1 | .hostListHeader { 2 | font-size: $main-font-s; 3 | line-height: 1.14; 4 | font-weight: bold; 5 | 6 | ul { 7 | font-weight: 400; 8 | } 9 | .listName { 10 | font-weight: bold; 11 | } 12 | .icon { 13 | display: flex; 14 | align-items: center; 15 | vertical-align: baseline; 16 | position: relative; 17 | margin-bottom: 22px; 18 | } 19 | .log { 20 | margin-bottom: 5px; 21 | margin-right: 10px; 22 | font-size: 16px; 23 | line-height: 0.1; 24 | } 25 | } 26 | 27 | li { 28 | cursor: pointer; 29 | color: white; 30 | padding: 10px 0 10px 0; 31 | margin-bottom: 5px; 32 | } 33 | 34 | .selected { 35 | background-color: rgba(251, 252, 255, 0.1); 36 | padding: 10px 0 10px 15px; 37 | border-left: 5px solid white; 38 | margin: 0 -20px 5px -20px; 39 | 40 | .log.log-Wheel { 41 | padding-right: 20px; 42 | font-size: 20px; 43 | line-height: 1; 44 | float: right; 45 | } 46 | } 47 | 48 | .hosts { 49 | overflow-x: hidden; 50 | overflow-y: scroll; 51 | padding-right: 16px; 52 | height: 36vh; 53 | 54 | } 55 | 56 | .hosts::-webkit-scrollbar { 57 | width: 10px; 58 | height: 10px; 59 | background-color: #00000000; 60 | } 61 | 62 | .hosts::-webkit-scrollbar-thumb { 63 | background-color: #ffffff4a; 64 | border-radius: 10px; 65 | } -------------------------------------------------------------------------------- /application/frontend/src/lib/HostList/HostList.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 |
14 |
15 | 16 |
17 |

{hostName}

18 |
19 | 20 |
21 |
    22 | {#if servicesData != null} 23 | {#each servicesData as service} 24 | {#if selectedName.localeCompare(service) == 0} 25 |
  • {service}
  • 26 | 27 | {:else} 28 |
  • { 30 | selectItem(service); 31 | }} 32 | > 33 | {service} 34 |
  • 35 | {/if} 36 | {/each} 37 | {/if} 38 |
39 |
40 |
41 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Input/Input.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 19 |
20 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ListWithChoise/ListWithChoise.scss: -------------------------------------------------------------------------------- 1 | .listWithChoise { 2 | padding: $container-padding; 3 | padding-top: 0; 4 | padding-bottom: 0; 5 | 6 | overflow-y: overlay; 7 | overflow-x: auto; 8 | 9 | &::-webkit-scrollbar { 10 | width: 10px; 11 | height: 10px; 12 | background-color: rgba(0, 0, 0, 0); 13 | } 14 | 15 | &.active::-webkit-scrollbar-thumb { 16 | background-color: #0000002a; 17 | border-radius: 10px; 18 | } 19 | 20 | &::-webkit-scrollbar-corner { 21 | display: none; 22 | } 23 | 24 | .listElementButton { 25 | text-align: center; 26 | } 27 | .listElement { 28 | cursor: default; 29 | } 30 | .hostHeader:hover { 31 | opacity: 0.8; 32 | .headerButton { 33 | opacity: 1; 34 | } 35 | } 36 | 37 | .headerButton { 38 | opacity: 0; 39 | } 40 | 41 | .hostHeader { 42 | @include center; 43 | justify-content: start; 44 | gap: 12px; 45 | } 46 | .log-Pencil { 47 | font-size: 18px; 48 | } 49 | 50 | .hostName { 51 | font-weight: bold; 52 | font-size: $main-font-s; 53 | cursor: pointer; 54 | } 55 | 56 | .hostRow { 57 | @include center; 58 | justify-content: space-between; 59 | margin-left: $normal-padding; 60 | margin-right: $normal-padding; 61 | 62 | p { 63 | overflow: hidden; 64 | text-overflow: ellipsis; 65 | white-space: nowrap; 66 | font-size: $main-font-s; 67 | z-index: 3; 68 | cursor: pointer; 69 | } 70 | .disabled { 71 | opacity: 0.2; 72 | } 73 | } 74 | .highlightedOverlay { 75 | position: absolute; 76 | 77 | background-color: rgba(0, 0, 0, 0.05); 78 | width: 100%; 79 | height: 39px; 80 | top: 0; 81 | z-index: -1; 82 | &.active { 83 | background: rgba(251, 252, 255, 0.1); 84 | border-left: 9px solid $text-dark-color-dark; 85 | box-sizing: border-box; 86 | z-index: 1; 87 | } 88 | } 89 | li { 90 | margin-bottom: 0; 91 | cursor: pointer; 92 | } 93 | 94 | .listElementButton { 95 | .log-Heart { 96 | opacity: 1; 97 | } 98 | .log-EmptyHeart { 99 | opacity: 0; 100 | } 101 | .log-Wheel { 102 | opacity: 0; 103 | } 104 | } 105 | 106 | .serviceListItem:hover { 107 | opacity: 0.8; 108 | .log-EmptyHeart { 109 | opacity: 1; 110 | } 111 | .log-Wheel { 112 | opacity: 1; 113 | } 114 | 115 | .listElementButton { 116 | cursor: pointer; 117 | z-index: 2; 118 | } 119 | } 120 | 121 | .serviceListItem { 122 | margin-left: -$normal-padding; 123 | margin-right: -$normal-padding; 124 | 125 | position: relative; 126 | div & { 127 | @include for-mobile { 128 | margin-left: 0px; 129 | margin-right: 0px; 130 | } 131 | } 132 | } 133 | 134 | .stopedServices { 135 | font-weight: 700; 136 | font-size: $main-font-s; 137 | padding-left: 12px; 138 | } 139 | .stopedServicesBox { 140 | margin-top: 4px; 141 | margin-bottom: 4px; 142 | 143 | .log-Pointer { 144 | font-size: 10px; 145 | cursor: pointer; 146 | padding: 6px; 147 | transform: rotate(0); 148 | &.rotated { 149 | transform: rotate(-90deg); 150 | } 151 | } 152 | } 153 | .buttonBox { 154 | display: flex; 155 | gap: 8px; 156 | } 157 | 158 | .listElementButton { 159 | &:hover { 160 | transform: scale(1.15); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /application/frontend/src/lib/LogsSize/LogSize.scss: -------------------------------------------------------------------------------- 1 | .logSizeContainer { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: space-around; 6 | height: 100%; 7 | color: $text-dark-color; 8 | .log { 9 | font-size: 24px; 10 | } 11 | .title { 12 | margin-top: 10px; 13 | margin-bottom: 10px; 14 | & span { 15 | font-size: 0.7rem; 16 | } 17 | } 18 | .commonText { 19 | color: $text-placeholder-color; 20 | font-size: $main-font-s; 21 | } 22 | .cleanButtonContainer { 23 | position: absolute; 24 | top: 0; 25 | right: 0; 26 | .log { 27 | font-size: 24px !important; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /application/frontend/src/lib/LogsSize/LogsSize.svelte: -------------------------------------------------------------------------------- 1 | 64 | 65 |
66 | 67 | {#if !isAllLogs}
68 |
77 | {/if} 78 |

{logsSize} MiB

79 |

{discribeText}

80 |
81 | -------------------------------------------------------------------------------- /application/frontend/src/lib/LogsString/LogsString.scss: -------------------------------------------------------------------------------- 1 | .logsString { 2 | display: flex; 3 | vertical-align: middle; 4 | align-items: flex-start; 5 | position: relative; 6 | gap: 10px; 7 | padding-bottom: 5px; 8 | padding-top: 5px; 9 | font-family: $mono-font; 10 | font-size: $main-font-s; 11 | 12 | @include for-mobile { 13 | display: block; 14 | line-height: 1.5; 15 | 16 | .message { 17 | // float: left; 18 | display: flex; 19 | flex-direction: column; 20 | } 21 | } 22 | 23 | @include for-tablet { 24 | display: block; 25 | line-height: 1.5; 26 | 27 | .message { 28 | // float: left; 29 | display: flex; 30 | flex-direction: column; 31 | } 32 | } 33 | 34 | .onlogs, 35 | .meta { 36 | color: $active-color; 37 | } 38 | 39 | .status { 40 | vertical-align: middle; 41 | // margin-right: 12px; 42 | min-width: 68px; 43 | line-height: 130%; 44 | cursor: pointer; 45 | & :hover { 46 | transform: scale(1.02); 47 | } 48 | 49 | span { 50 | font-size: 18px; 51 | line-height: 50%; 52 | } 53 | 54 | &.chosenStatus { 55 | background-color: $active-transparent-color; 56 | border-radius: 6px; 57 | } 58 | } 59 | 60 | .time { 61 | width: 84px; 62 | min-width: 101px; 63 | margin-right: 8px; 64 | text-align: center; 65 | display: flex; 66 | @include for-tablet { 67 | margin: 0; 68 | width: 150px; 69 | // display: table-cell; 70 | position: absolute; 71 | left: 80px; 72 | top: 4px; 73 | justify-content: start; 74 | flex-direction: row-reverse; 75 | } 76 | @include for-mobile { 77 | margin: 0; 78 | width: 150px; 79 | // display: table-cell; 80 | position: absolute; 81 | left: 80px; 82 | top: 4px; 83 | justify-content: start; 84 | flex-direction: row-reverse; 85 | } 86 | } 87 | 88 | .shareLinkButtonThumb { 89 | margin-left: 4px; 90 | opacity: 0; 91 | cursor: pointer; 92 | @include for-tablet { 93 | margin: 0 4px 0 0; 94 | } 95 | } 96 | 97 | &:after { 98 | content: ""; 99 | width: 100%; 100 | position: absolute; 101 | bottom: 0; 102 | 103 | z-index: 1; 104 | } 105 | .hidden { 106 | opacity: 0; 107 | } 108 | &:last-child { 109 | border-top: solid 1px $lines-color; 110 | } 111 | &.new { 112 | background-color: #4492db2c; 113 | } 114 | 115 | .log-Json { 116 | position: absolute; 117 | left: 12px; 118 | font-size: $main-font-xl; 119 | cursor: pointer; 120 | } 121 | pre { 122 | white-space: pre-wrap; 123 | word-break: break-all; 124 | } 125 | } 126 | 127 | .logsString:hover { 128 | .shareLinkButtonThumb { 129 | opacity: 0.6; 130 | &:hover { 131 | opacity: 1; 132 | } 133 | } 134 | } 135 | 136 | .emptyLogsString { 137 | border-top: none !important; 138 | } 139 | 140 | .number { 141 | color: #f99157; 142 | } 143 | 144 | .string { 145 | color: #be998a; 146 | } 147 | 148 | .key { 149 | color: #6e1963; 150 | } 151 | -------------------------------------------------------------------------------- /application/frontend/src/lib/LogsString/LogsString.stories.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import LogsString from "./LogsString.svelte"; 3 | import { action } from "@storybook/addon-actions"; 4 | import "../../assets/res/onLogsFont.css"; 5 | 6 | 7 | 8 | export default { 9 | component: LogsString, 10 | title: "LogsString", 11 | excludeStories: /.*Data$/, 12 | argTypes: { 13 | status: { 14 | type: "string", 15 | description: "Status of string", 16 | defaultValue: "debug", 17 | options: ["error", "debug", "warn", "info"], 18 | control: { type: "radio" }, 19 | }, 20 | }, 21 | 22 | //👇 The argTypes are included so that they are properly displayed in the Actions Panel 23 | }; 24 | 25 | const Template = ({ ...args }) => ({ 26 | Component: LogsString, 27 | props: args, 28 | 29 | }); 30 | 31 | export const Default = Template.bind({}); 32 | Default.args = { 33 | status: "debug", 34 | time: " 16 Jul 07:18:30.683", 35 | message:"starting PostgreSQL 14.0 (Debian 14.0-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit" 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /application/frontend/src/lib/LogsString/LogsString.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | { 27 | if ($chosenStatus !== status) { 28 | chosenStatus.set(status); 29 | } else { 30 | chosenStatus.set(""); 31 | } 32 | }} 33 | class="status {status ? status : 'hidden'} {status === $chosenStatus 34 | ? 'chosenStatus' 35 | : ''}">

{status.toUpperCase()}

37 | 38 |

{message?.trim()?.length > 0 ? time : ""}

40 |
41 | {#if message?.trim()?.length > 0} 42 |
{ 46 | sharedLinkCallBack(); 47 | }} 48 | > 49 | 50 |
{/if} 51 |
52 | 53 | 54 | {#if !parsedStr}

55 | {@html message} 56 |

{:else if $store.transformJson}

{parsedStr.startText}

57 |
{@html parsedStr.html}
58 |

{parsedStr.endText}

59 | {:else}

60 | {@html message} 61 |

{/if} 62 | 63 | 64 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Modal/Modal.scss: -------------------------------------------------------------------------------- 1 | .modalContainer { 2 | // min-width: 40vw; 3 | max-width: 86vw; 4 | // min-width: 40vw; 5 | min-height: min-content; 6 | background-color: $background-color; 7 | 8 | box-shadow: $main-shadow; 9 | padding: $normal-padding; 10 | border-radius: $main-border-radius; 11 | position: absolute; 12 | top: 50%; 13 | left: 50%; 14 | transform: translate(-50%, -50%); 15 | z-index: 6; 16 | @include for-mobile { 17 | z-index: 15; 18 | max-width: 96vw; 19 | min-width: 40vw; 20 | .modalContainer { 21 | max-width: 86vw; 22 | min-width: 40vw; 23 | overflow-x: auto; 24 | } 25 | .attentionZone { 26 | width: 86vw; 27 | min-width: 40vw; 28 | overflow-x: auto; 29 | } 30 | } 31 | } 32 | 33 | .closeButton { 34 | color: $active-color; 35 | height: 32px; 36 | width: 32px; 37 | border-radius: 100%; 38 | background-color: rgba(0, 0, 0, 0.1); 39 | display: flex; 40 | align-items: center; 41 | justify-content: center; 42 | position: absolute; 43 | left: calc(100% - 40px); 44 | top: 10px; 45 | cursor: pointer; 46 | } 47 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Modal/Modal.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | {#if modalIsOpen} 20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 |
28 |
{/if} 29 | 30 | -------------------------------------------------------------------------------- /application/frontend/src/lib/NotFound/Notfound.scss: -------------------------------------------------------------------------------- 1 | .textContainer { 2 | display: block; 3 | margin-left: auto; 4 | margin-right: auto; 5 | width: fit-content; 6 | margin-top: 30vh; 7 | 8 | .tittle { 9 | margin-bottom: 16px; 10 | } 11 | .linksContainer { 12 | display: flex; 13 | gap: 16px; 14 | justify-content: center; 15 | p { 16 | padding: 8px; 17 | cursor: pointer; 18 | &:hover { 19 | color: $active-color; 20 | background-color: $block-bg-color; 21 | border-radius: $main-border-radius; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /application/frontend/src/lib/NotFound/Notfound.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |

404 This is not the web page you are looking for...

8 | 24 |
25 | -------------------------------------------------------------------------------- /application/frontend/src/lib/OutsideClicker/OutsideClicker.js: -------------------------------------------------------------------------------- 1 | export function clickOutside(node) { 2 | const handleClick = (event) => { 3 | if (node && !node.contains(event.target) && !event.defaultPrevented) { 4 | node.dispatchEvent(new CustomEvent("click_outside", node)); 5 | } 6 | }; 7 | 8 | document.addEventListener("click", handleClick, true); 9 | 10 | return { 11 | destroy() { 12 | document.removeEventListener("click", handleClick, true); 13 | }, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ProgressBar/ProgressBar.scss: -------------------------------------------------------------------------------- 1 | .progressBarContainer { 2 | width: 100%; 3 | height: 12px; 4 | background-color: $background-color; 5 | border: 2px; 6 | border-radius: 4px; 7 | overflow: hidden; 8 | position: relative; 9 | 10 | .progressBarValue { 11 | height: 12px; 12 | background-color: $active-color; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /application/frontend/src/lib/ProgressBar/ProgressBar.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /application/frontend/src/lib/SecretModal/DockerComposeSnippet.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
example_onlogs:
 7 |     image: devforth/onlogs 
 8 |     restart: always
 9 |     environment:
10 |       - AGENT=true
11 |       - HOST={origin}
12 |       - ONLOGS_TOKEN={token}
13 |     volumes:
14 |      - /var/run/docker.sock:/var/run/docker.sock
15 |      - /etc/hostname:/etc/hostname
16 |      - onlogs-volume:/leveldb 
17 | -------------------------------------------------------------------------------- /application/frontend/src/lib/SecretModal/DockerSnippet.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
 7 | docker run -d --restart always --name onlogs \
 8 |   -e AGENT=true \
 9 |   -e HOST={origin} \
10 |   -e ONLOGS_TOKEN={token} \
11 |   -v /var/run/docker.sock:/var/run/docker.sock:ro \
12 |   -v /etc/hostname:/etc/hostname \
13 |   -v /var/lib/docker/containers:/var/lib/docker/containers \
14 |   -v onlogs-volume:/leveldb \
15 | devforth/onlogs
16 |   
17 | -------------------------------------------------------------------------------- /application/frontend/src/lib/SecretModal/SecretModal.scss: -------------------------------------------------------------------------------- 1 | .secretModalContainer { 2 | background-color: $block-bg-color; 3 | border-radius: $main-border-radius; 4 | padding: $container-padding; 5 | position: absolute; 6 | left: 50%; 7 | top: 50%; 8 | transform: translate(-50%, -50%); 9 | min-height: 200px; 10 | min-width: 300px; 11 | z-index: 7; 12 | display: flex; 13 | flex-direction: column; 14 | .snippetContainer { 15 | min-height: 170px; 16 | min-width: 430px; 17 | background-color: $inpun-color; 18 | border-radius: $main-border-radius; 19 | border-top-left-radius: 0; 20 | box-shadow: $main-shadow; 21 | margin-bottom: 30px; 22 | padding: 20px 16px 20px 16px; 23 | position: relative; 24 | 25 | pre { 26 | color: $text-dark-color; 27 | margin: 0; 28 | } 29 | } 30 | .buttonWrapper { 31 | display: flex; 32 | justify-content: end; 33 | } 34 | 35 | .secretMoalTitle { 36 | color: $text-dark-color; 37 | } 38 | 39 | .labelsBox { 40 | justify-content: left; 41 | max-width: 50%; 42 | max-height: 70px; 43 | box-shadow: $main-shadow; 44 | margin-top: $container-padding; 45 | align-items: stretch; 46 | 47 | font-size: $main-font-xs; 48 | } 49 | .labelItem { 50 | padding: 6px; 51 | width: 50%; 52 | border-top-right-radius: 4px; 53 | border-top-left-radius: 4px; 54 | margin-right: 4px; 55 | 56 | background-color: $inpun-color-dark; 57 | &.active { 58 | z-index: 5; 59 | } 60 | &.active { 61 | color: $active-color; 62 | font-weight: 600; 63 | } 64 | } 65 | 66 | .coppyButton { 67 | position: absolute; 68 | top: 14px; 69 | right: 14px; 70 | i { 71 | font-size: 18px !important; 72 | } 73 | } 74 | @include for-mobile { 75 | z-index: 15; 76 | max-width: 86vw; 77 | .snippetContainer { 78 | max-width: 76vw; 79 | min-width: 60vw; 80 | overflow-x: auto; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /application/frontend/src/lib/SecretModal/SecretModal.svelte: -------------------------------------------------------------------------------- 1 | 40 | 41 |
{ 45 | snipetModalIsVisible.set(false); 46 | }} 47 | > 48 |

Connect new host

49 |
50 |
{ 55 | choseSnippetOption("Docker"); 56 | }} 57 | > 58 | Docker 59 |
60 |
{ 65 | choseSnippetOption("DockerCompose"); 66 | }} 67 | > 68 | Docker Compose 69 |
70 |
71 |
72 | {#if $currentSnippedOption === "Docker"} 73 | 74 | {/if} 75 | {#if $currentSnippedOption === "DockerCompose"} 76 | 77 | {/if} 78 |
79 |
100 |
101 |
102 |
112 |
113 |
114 | { 116 | handleKeydown(e, "Escape", () => { 117 | snipetModalIsVisible.set(false); 118 | }); 119 | }} 120 | /> 121 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Stats/Stats.scss: -------------------------------------------------------------------------------- 1 | .statsItem { 2 | padding: 0; 3 | margin: 0 0 6px 0; 4 | font-size: $main-font-s; 5 | cursor: pointer; 6 | & :hover { 7 | transform: scale(1.02); 8 | } 9 | } 10 | 11 | .statsTittle { 12 | margin-top: 12px; 13 | margin-bottom: 12px; 14 | } 15 | 16 | .log-Info { 17 | font-size: 18px; 18 | line-height: 1; 19 | } 20 | .timeSpan { 21 | font-size: $main-font-s; 22 | & div { 23 | padding: 2px; 24 | font-weight: 600; 25 | cursor: pointer; 26 | &.active { 27 | color: $active-color; 28 | } 29 | } 30 | } 31 | 32 | .statsContainer { 33 | color: $text-dark-color; 34 | } 35 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Stats/Stats.svelte: -------------------------------------------------------------------------------- 1 | 50 | 51 |
52 |
53 | { 56 | // navigate( 57 | // `${changeKey}/stats/${$lastChosenHost}/${$lastChosenService}`, 58 | // { 59 | // replace: true, 60 | // } 61 | // ); 62 | }} 63 | title="Counter updates every 1 min since OnLogs started. So, it may cause some asynchrony." 64 | /> 65 |
66 |
{ 69 | setPeriod(2); 70 | }} 71 | > 72 | 1hr 73 |
74 |
{ 77 | setPeriod(48); 78 | }} 79 | > 80 | 1d 81 |
82 |
{ 85 | setPeriod(336); 86 | }} 87 | > 88 | 1w 89 |
90 |
{ 93 | setPeriod(1344); 94 | }} 95 | > 96 | 1m 97 |
98 |
99 |
100 |

101 | Top {Object.keys(data).length ? Object.keys(data).length : ""} levels: 102 |

103 |
    104 | {#each Object.entries(data).sort((a, b) => { 105 | if (a[1] > b[1]) { 106 | return -1; 107 | } 108 | if (a[1] < b[1]) { 109 | return 1; 110 | } 111 | }) as [key, name]} 112 |
  • { 114 | if ($chosenStatus !== key) { 115 | chosenStatus.set(key); 116 | } else { 117 | chosenStatus.set(""); 118 | } 119 | }}> 120 |

    {key.charAt(0).toUpperCase() + key.slice(1)}

    121 |

    {name}

    122 |
  • 123 | {/each} 124 |
125 |
126 | -------------------------------------------------------------------------------- /application/frontend/src/lib/StreamInfo/StreamInfo.scss: -------------------------------------------------------------------------------- 1 | .log-Last { 2 | font-size: 20px; 3 | color: $active-color; 4 | cursor: pointer; 5 | } 6 | 7 | .log-container { 8 | display: flex; 9 | flex-direction: column; 10 | gap: 8px; 11 | 12 | .log-Last { 13 | margin-right: 8px; 14 | &.WSisMuted { 15 | color: rgba(0, 0, 0, 0.151); 16 | } 17 | } 18 | 19 | .log-time { 20 | display: flex; 21 | align-items: center; 22 | 23 | span { 24 | margin-left: 4px; 25 | } 26 | } 27 | 28 | .log-time-ago { 29 | } 30 | } 31 | .streamInfoTimeWrapper { 32 | display: flex; 33 | gap: 4px; 34 | align-items: baseline; 35 | } 36 | 37 | .streamInfoTime { 38 | font-size: $main-font-m; 39 | font-weight: 700; 40 | } 41 | 42 | .streamInfoTimeShortName { 43 | vertical-align: bottom; 44 | line-height: 1; 45 | font-size: 0.8rem; 46 | } 47 | .log-heading { 48 | font-size: $main-font-s; 49 | font-weight: 200; 50 | } 51 | -------------------------------------------------------------------------------- /application/frontend/src/lib/StreamInfo/StreamInfo.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 |
29 | { 33 | if ($WSisMuted) { 34 | WSisMuted.set(false); 35 | manuallyUnmuted.set(true); 36 | } else { 37 | WSisMuted.set(true); 38 | manuallyUnmuted.set(false); 39 | } 40 | }} 41 | /> 42 | 43 |

Last log line:

44 | {#if Array.isArray(componentLastLogTime)} 45 | {#if componentLastLogTime?.at(0)[0] || componentLastLogTime?.at(1)[0]} 46 |
47 | {#each componentLastLogTime as e} 48 | {#if e?.at(0)} 49 | {e?.at(0)} 50 | 51 | {e?.at(1)}{/if} 52 | {/each} 53 |
54 | {/if} 55 | {#if componentLastLogTime?.at(0)[0] === 0 && componentLastLogTime?.at(1)[0] === 0} 56 | Recently 57 | {/if} 58 | {#if componentLastLogTime?.at(0) === "" && componentLastLogTime?.at(1) === ""} 59 | No logs 60 | {/if} 61 | {/if} 62 |
63 | 64 |
65 |
66 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Toast/Toast.scss: -------------------------------------------------------------------------------- 1 | .toastContainer { 2 | width: 300px; 3 | height: 140px; 4 | position: absolute; 5 | top: 20px; 6 | left: 50%; 7 | transform: translate(-50%); 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | padding: 0 12px 0 12px; 12 | 13 | border-radius: $main-border-radius; 14 | box-shadow: $main-shadow; 15 | box-sizing: border-box; 16 | z-index: 10; 17 | color: #ffffff; 18 | 19 | background-color: $block-bg-color; 20 | 21 | .toastButtonContainer { 22 | max-height: 64px; 23 | position: absolute; 24 | bottom: 12px; 25 | right: 12px; 26 | &.additionalButton { 27 | left: 12px; 28 | } 29 | } 30 | 31 | .log { 32 | font-size: $main-font-l; 33 | position: absolute; 34 | left: 12px; 35 | top: 12px; 36 | &-Error { 37 | color: #992c2c; 38 | } 39 | 40 | &-Success { 41 | color: #2f912d; 42 | } 43 | 44 | &-Warning { 45 | color: #ac681a; 46 | } 47 | } 48 | 49 | p { 50 | overflow: hidden; 51 | text-overflow: ellipsis; 52 | color: $text-dark-color; 53 | margin-bottom: 12px; 54 | font-size: $main-font-s; 55 | } 56 | h4 { 57 | margin: 12px 0 12px 0; 58 | color: $text-dark-color; 59 | font-size: $main-font-l; 60 | } 61 | 62 | .additionButtonContainer { 63 | display: flex; 64 | justify-content: space-between; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /application/frontend/src/lib/Toast/Toast.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 |
25 |
26 |

{tittle}

27 |

{message}

28 | 29 | 30 |
31 |
32 | {#if additionButton?.isVisible} 33 |
43 | 44 |
45 |
54 |
55 |
56 | 57 | { 59 | handleKeydown(e, "Escape", () => { 60 | toastIsVisible.set(false); 61 | if (toastTimeoutId) { 62 | clearTimeout($toastTimeoutId); 63 | } 64 | }); 65 | }} 66 | /> 67 | -------------------------------------------------------------------------------- /application/frontend/src/lib/UserMenu/UserManageForm.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 |

Create user

11 |
12 | 13 | 20 |
21 |
22 | 23 | 31 |
32 |
33 |
34 |
43 |
44 |
48 |
49 | -------------------------------------------------------------------------------- /application/frontend/src/lib/UserMenu/UserMenu.scss: -------------------------------------------------------------------------------- 1 | .userTable { 2 | width: 100%; 3 | 4 | th { 5 | padding: 5px; 6 | border-bottom: 1px solid $lines-color; 7 | } 8 | tr { 9 | border-bottom: 1px solid $lines-color; 10 | } 11 | 12 | span { 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | padding: 12px; 17 | } 18 | .buttonSpanContainer { 19 | max-width: 150px; 20 | margin-left: auto; 21 | margin-right: 16px; 22 | padding: 4px; 23 | } 24 | .buttonSpan { 25 | padding: 0; 26 | margin-left: 12px; 27 | } 28 | } 29 | 30 | table { 31 | border-collapse: collapse; 32 | } 33 | 34 | .userCreateForm { 35 | color: $lines-color; 36 | 37 | .input { 38 | padding: $normal-padding; 39 | background-color: $inpun-color; 40 | border-radius: $main-border-radius; 41 | border: 1px solid $lines-color; 42 | width: 100%; 43 | outline: none; 44 | box-sizing: border-box; 45 | } 46 | label { 47 | margin-bottom: 6px; 48 | font-size: $main-font-s; 49 | color: $text-dark-color; 50 | margin-left: 6px; 51 | } 52 | 53 | .inputContainer { 54 | display: flex; 55 | flex-direction: column; 56 | margin-top: 12px; 57 | justify-content: center; 58 | align-items: center; 59 | } 60 | 61 | input:focus { 62 | border: 2px solid $active-color; 63 | } 64 | 65 | .buttonsContainer { 66 | display: flex; 67 | justify-content: center; 68 | margin-top: 24px; 69 | gap: 42px; 70 | } 71 | 72 | h3 { 73 | color: $text-dark-color; 74 | } 75 | } 76 | 77 | .usersHeaderContainer { 78 | display: flex; 79 | justify-content: space-between; 80 | gap: 24px; 81 | align-items: center; 82 | h3 { 83 | max-width: 150px; 84 | } 85 | .addUserButton { 86 | padding: 12px; 87 | width: 20px; 88 | height: 20px; 89 | border-radius: 100%; 90 | display: flex; 91 | align-items: center; 92 | justify-content: center; 93 | cursor: pointer; 94 | background-color: $active-color; 95 | color: $text-onactive-color; 96 | } 97 | .addUserButton:hover { 98 | transform: scale(1.1); 99 | } 100 | } 101 | 102 | .buttonModalContainer { 103 | display: flex; 104 | margin-top: 54px; 105 | margin-bottom: 24px; 106 | justify-content: space-around; 107 | } 108 | 109 | .editInput { 110 | border-radius: 10px; 111 | padding: 6px 12px; 112 | box-sizing: border-box; 113 | font-size: $main-font-m; 114 | border: 1px solid $lines-color; 115 | margin-top: 20px; 116 | 117 | border: 1px solid $text-placeholder-color; 118 | color: $text-dark-color; 119 | 120 | &:focus { 121 | outline: none; 122 | border: 2px solid $active-color; 123 | // caret-color: transparent; 124 | } 125 | } 126 | .editInputContainer { 127 | display: flex; 128 | justify-content: center; 129 | } 130 | .userMenu { 131 | text-align: center; 132 | } 133 | -------------------------------------------------------------------------------- /application/frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import "./main.scss"; 2 | import App from "./App.svelte"; 3 | import "@/assets/res/onLogsFont.css"; 4 | 5 | const app = new App({ 6 | target: document.getElementById("app"), 7 | }); 8 | 9 | export default app; 10 | -------------------------------------------------------------------------------- /application/frontend/src/main.scss: -------------------------------------------------------------------------------- 1 | @import "./utils/variables"; 2 | @import "./Views/Main/Main.scss"; 3 | @import "./lib/Button/Button.scss"; 4 | @import "./lib/Container/Container.scss"; 5 | @import "./lib/LogsString/LogsString.scss"; 6 | 7 | @import "./Views/Logs/LogsView.scss"; 8 | @import "./Views/Login//Login.scss"; 9 | @import "./lib/HostList/HostList.scss"; 10 | @import "./lib/ClientPanel/ClientPanel.scss"; 11 | @import "./lib/DropDown/DropDown.scss"; 12 | @import "./lib/CheckBox/CheckBox.scss"; 13 | @import "./lib/UserMenu/UserMenu.scss"; 14 | @import "./lib/Modal/Modal.scss"; 15 | @import "./Theme.scss"; 16 | @import "./lib/ListWithChoise/ListWithChoise.scss"; 17 | @import "./lib/CommonList/CommonList.scss"; 18 | @import "./lib/ButtonToBottom/ButtonToBottom.scss"; 19 | @import "./lib/Toast/Toast.scss"; 20 | @import "./lib/NotFound/Notfound.scss"; 21 | @import "./lib/SecretModal/SecretModal.scss"; 22 | @import "./lib/LogsSize/LogSize.scss"; 23 | @import "./lib/ConfirmationMenu/ConfirmationMenu.scss"; 24 | @import "./Views/ServiceSettings/ServiceSettings.scss"; 25 | @import "./lib/Stats/Stats.scss"; 26 | @import "./lib/ChartMenu/ChartMenu.scss"; 27 | @import "./lib/ProgressBar/ProgressBar.scss"; 28 | @import "./lib/StreamInfo/StreamInfo.scss"; 29 | body { 30 | font-family: "Ubuntu", sans-serif; 31 | background-color: $background-color; 32 | height: 100vh; 33 | width: 100vw; 34 | margin: 0; 35 | } 36 | 37 | h1, 38 | h2, 39 | h3, 40 | h4 { 41 | margin: 0; 42 | } 43 | h1 { 44 | font-size: $main-font-xl; 45 | } 46 | 47 | .contentContainer { 48 | padding: $normal-padding; 49 | box-sizing: border-box; 50 | height: 100vh; 51 | } 52 | 53 | li { 54 | list-style: none; 55 | color: inherit; 56 | } 57 | 58 | p { 59 | margin: 0; 60 | } 61 | 62 | button { 63 | border-width: 0px; 64 | } 65 | 66 | ul { 67 | padding: 0; 68 | margin: 0; 69 | } 70 | 71 | h2 { 72 | padding: 0; 73 | margin: 0; 74 | } 75 | 76 | input { 77 | border: 0; 78 | } 79 | 80 | .visuallyHidden { 81 | position: absolute; 82 | left: -999999px; 83 | top: -999999px; 84 | width: 1px; 85 | height: 1px; 86 | display: none; 87 | opacity: 0; 88 | } 89 | 90 | .clickable { 91 | cursor: pointer; 92 | } 93 | 94 | .modalOverlay { 95 | position: absolute; 96 | height: 100%; 97 | width: 100%; 98 | background-color: rgba(0, 0, 0, 0.4); 99 | top: 0; 100 | left: 0; 101 | z-index: 6; 102 | } 103 | 104 | @include for-mobile { 105 | #modalOverlay { 106 | z-index: 14; 107 | } 108 | } 109 | 110 | ::-webkit-scrollbar-thumb { 111 | background-color: #00000020; 112 | border-radius: 10px; 113 | } 114 | .error { 115 | color: #ff4242; 116 | } 117 | 118 | .debug { 119 | color: #178f15; 120 | } 121 | 122 | .warn { 123 | color: #ff8a00; 124 | } 125 | 126 | .info { 127 | color: skyblue; 128 | } 129 | 130 | .meta { 131 | color: #4e49da; 132 | } 133 | 134 | li { 135 | cursor: default; 136 | } 137 | -------------------------------------------------------------------------------- /application/frontend/src/utils/_variables.scss: -------------------------------------------------------------------------------- 1 | // colors 2 | $active-color: #4e49da; 3 | $inpun-color: #f8fafb; 4 | $text-onactive-color: #fbfcff; 5 | $text-dark-color: #1b1850; 6 | $text-placeholder-color: #a3a3b9; 7 | $lines-color: #c8d2e5; 8 | $background-color: #eaf0f7d7; 9 | $btn-common-color: #414860; 10 | $btn-primary-color: #ffffff; 11 | $block-bg-color: #ffffff; 12 | $active-transparent-color: #4e49da40; 13 | 14 | $active-color-dark: #c244db; 15 | $inpun-color-dark: #99a9b931; 16 | $text-onactive-color-dark: #e4e7eb; 17 | $text-dark-color-dark: #cbd2d9; 18 | $text-placeholder-color-dark: #e4e7eb; 19 | $lines-color-dark: #cbd2d9; 20 | $background-color-dark: #121212; 21 | $btn-primary-color-dark: #c244db; 22 | $lines-color-dark: #cbd2d938; 23 | $inputs-border-color: #ffffff00; 24 | $active-transparent-color-dark: #c244db40; 25 | 26 | $block-bg-color-dark: #1f2933; 27 | $mono-font: "Source Code Pro", monospace; 28 | // shadows 29 | 30 | $main-shadow: 1px 1px 10px rgba(0, 0, 0, 0.15); 31 | $container-shadow: 1px 1px 30px rgba(5, 39, 70, 0.1); 32 | 33 | $main-shadow-dark: 1px 1px 5px rgba(0, 0, 0, 0.7); 34 | $container-shadow-dark: 1px 1px 12px rgba(23, 24, 24, 0.7); 35 | 36 | //border-radius 37 | 38 | $main-border-radius: 10px; 39 | $large-border-radius: 20px; 40 | 41 | //fonts 42 | $main-font-xs: 12px; 43 | $main-font-s: 14px; 44 | $main-font-m: 16px; 45 | $main-font-l: 22px; 46 | $main-font-xl: 28px; 47 | 48 | //line-height 49 | $line-height: 2.5; 50 | 51 | //paddings 52 | $normal-padding: 12px; 53 | $container-padding: 12px; 54 | $container-vertical-padding: 16px; 55 | 56 | //mixins 57 | @mixin hide { 58 | position: absolute; 59 | opacity: 0; 60 | left: -99999px; 61 | right: -99999px; 62 | height: 1px; 63 | width: 1px; 64 | } 65 | @mixin visible { 66 | position: static; 67 | opacity: 1; 68 | left: 0px; 69 | right: 0px; 70 | height: auto; 71 | width: auto; 72 | } 73 | 74 | @mixin for-mobile { 75 | @media (min-width: 200px) and (max-width: 750px) { 76 | @content; 77 | } 78 | } 79 | 80 | @mixin for-tablet { 81 | @media (min-width: 750px) and (max-width: 1150px) { 82 | @content; 83 | } 84 | } 85 | 86 | @mixin for-desctop { 87 | @media (min-width: 950px) { 88 | @content; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /application/frontend/src/utils/changeKey.js: -------------------------------------------------------------------------------- 1 | export const changeKey = location.href.includes("localhost:5173") 2 | ? "" 3 | : "/ONLOGS_PREFIX_ENV_VARIABLE_THAT_SHOULD_BE_REPLACED_ON_BACKEND_INITIALIZATION"; 4 | -------------------------------------------------------------------------------- /application/frontend/src/utils/functions.js: -------------------------------------------------------------------------------- 1 | import json2html from "json-to-html"; 2 | 3 | export const handleKeydown = (e, keyValue, cb) => { 4 | if (e.key === keyValue) { 5 | cb(); 6 | } 7 | }; 8 | 9 | export const emulateData = (amount) => { 10 | const randomArray = (length, max) => 11 | [...new Array(length)].map(() => Math.round(Math.random() * max)); 12 | 13 | let data = { 14 | dates: new Array(amount).fill("1"), 15 | debug: randomArray(10, 1000), 16 | error: randomArray(10, 1000), 17 | info: randomArray(10, 1000), 18 | warn: randomArray(10, 1000), 19 | other: randomArray(10, 1000), 20 | }; 21 | return data; 22 | }; 23 | 24 | export const tryToParseLogString = (str) => { 25 | const beginningOfJson = str.indexOf("{"); 26 | const endingOfJson = str.lastIndexOf("}"); 27 | 28 | let html = ""; 29 | let startText = ""; 30 | let endText = ""; 31 | 32 | if (beginningOfJson !== -1 && endingOfJson !== -1) { 33 | if (endingOfJson > beginningOfJson) { 34 | const jsonPart = str.slice(beginningOfJson, endingOfJson); 35 | startText = str.slice(0, beginningOfJson); 36 | endText = str.slice(endingOfJson + 1, -1); 37 | try { 38 | let normilizedStr = JSON.parse(jsonPart + "}"); 39 | html = json2html(normilizedStr, 2); 40 | } catch (e) {} 41 | } 42 | } 43 | 44 | if (html) { 45 | return { startText, html, endText }; 46 | } else return null; 47 | }; 48 | 49 | export const copyText = function (ref, cb) { 50 | const text = ref; 51 | let textToCopy = text.innerText; 52 | if (navigator.clipboard) { 53 | navigator.clipboard.writeText(textToCopy).then(() => { 54 | cb(); 55 | }); 56 | } else { 57 | console.log("Browser Not compatible"); 58 | } 59 | }; 60 | 61 | export const copyCustomText = function (text, cb) { 62 | let textToCopy = text; 63 | if (navigator.clipboard) { 64 | navigator.clipboard.writeText(textToCopy).then(() => { 65 | cb(); 66 | }); 67 | } else { 68 | console.log("Browser Not compatible"); 69 | } 70 | }; 71 | 72 | export function getTimeDifference(t) { 73 | const now = Date.now(); 74 | const timestamp = Date.parse(t); 75 | const difference = Math.abs(now - timestamp) / 1000; // difference in seconds 76 | 77 | const hours = Math.floor((difference % 86400) / 3600); 78 | const minutes = Math.floor((difference % 3600) / 60); 79 | 80 | function showIfExisted(v, time) { 81 | if (v || v === 0) { 82 | return [v, time]; 83 | } 84 | return ""; 85 | } 86 | 87 | return [showIfExisted(hours, "h"), showIfExisted(minutes, "m")]; 88 | } 89 | -------------------------------------------------------------------------------- /application/frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /application/frontend/startDebug.js: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | 3 | const srcDir = `./dist`; 4 | const destDir = `../backend/dist`; 5 | 6 | // To copy a folder or file, select overwrite accordingly 7 | try { 8 | fs.copySync(srcDir, destDir, { overwrite: true }); 9 | console.log("success!"); 10 | } catch (err) { 11 | console.error(err); 12 | } 13 | -------------------------------------------------------------------------------- /application/frontend/storybook-static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devforth/OnLogs/21983bae44c52a347f7d9ef03cabfe636aef0bee/application/frontend/storybook-static/favicon.ico -------------------------------------------------------------------------------- /application/frontend/storybook-static/project.json: -------------------------------------------------------------------------------- 1 | {"generatedAt":1670422110895,"builder":{"name":"@storybook/builder-vite"},"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":false,"refCount":0,"features":{"storyStoreV7":true},"storybookVersion":"6.5.13","language":"javascript","storybookPackages":{"@storybook/addon-actions":{"version":"6.5.13"},"@storybook/builder-vite":{"version":"0.2.5"},"@storybook/svelte":{"version":"6.5.13"},"@storybook/testing-library":{"version":"0.0.13"}},"framework":{"name":"svelte"},"addons":{"@storybook/addon-links":{"version":"6.5.12"},"@storybook/addon-essentials":{"version":"6.5.13"},"@storybook/addon-interactions":{"version":"6.5.12"}}} 2 | -------------------------------------------------------------------------------- /application/frontend/storybook-static/stories.json: -------------------------------------------------------------------------------- 1 | {"v":3,"stories":{"button--default":{"id":"button--default","title":"Button","name":"Default","importPath":"./src/lib/Button/Button.stories.js"},"container--default":{"id":"container--default","title":"Container","name":"Default","importPath":"./src/lib/Container/Container.stories.js"},"logsstring--default":{"id":"logsstring--default","title":"LogsString","name":"Default","importPath":"./src/lib/LogsString/LogsString.stories.js"}}} 2 | -------------------------------------------------------------------------------- /application/frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from "vite"; 2 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 3 | import * as path from "path"; 4 | const VITE_ASSET_URL = import.meta.VITE_ASSET_URL || ""; 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | resolve: { 8 | alias: { 9 | "@": path.resolve(__dirname, "src"), 10 | }, 11 | }, 12 | plugins: [svelte({})], 13 | }); 14 | -------------------------------------------------------------------------------- /application/release.sh: -------------------------------------------------------------------------------- 1 | # docker buildx create --use 2 | docker buildx build --platform=linux/amd64,linux/arm64 --tag "devforth/onlogs:latest" --tag "devforth/onlogs:1.1.6" --push . 3 | # docker run -v /var/run/docker.sock:/var/run/docker.sock --rm -it $(docker build -q -f Dockerfile .) 4 | # docker build . -t devforth/onlogs && docker push devforth/onlogs 5 | --------------------------------------------------------------------------------