├── .editorconfig
├── .eslintrc.js
├── .github
├── dependabot.yml
└── workflows
│ ├── cd.yaml
│ ├── release_build_linux.yaml
│ ├── release_build_macos.yaml
│ ├── release_build_windows.yaml
│ └── release_notifications.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .prettierignore
├── LICENSE
├── README.md
├── RELEASE.md
├── app-icon.png
├── bumpversion.sh
├── index.html
├── package-lock.json
├── package.json
├── public
├── beiboot-logo-dark.svg
├── beiboot-logo-light.png
└── logo.svg
├── rollout.sh
├── screenshot.png
├── src-tauri
├── .gitignore
├── Cargo.lock
├── Cargo.toml
├── build.rs
├── icons
│ ├── 128x128.png
│ ├── 128x128@2x.png
│ ├── 32x32.png
│ ├── 32x32.svg
│ ├── Square107x107Logo.png
│ ├── Square142x142Logo.png
│ ├── Square150x150Logo.png
│ ├── Square284x284Logo.png
│ ├── Square30x30Logo.png
│ ├── Square310x310Logo.png
│ ├── Square44x44Logo.png
│ ├── Square71x71Logo.png
│ ├── Square89x89Logo.png
│ ├── StoreLogo.png
│ ├── icon.icns
│ ├── icon.ico
│ └── icon.png
├── src
│ ├── connection.rs
│ ├── connection
│ │ └── ghostunnel.rs
│ ├── heartbeat.rs
│ ├── lib.rs
│ ├── main.rs
│ └── util.rs
├── tauri.conf.json
└── tests
│ └── connectors.rs
├── src
├── App.vue
├── auth
│ └── keycloak.ts
├── beibootctl.d.ts
├── beibootctl.ts
├── components
│ ├── ClusterTable.vue
│ └── Home.vue
├── layouts
│ └── default
│ │ ├── Default.vue
│ │ └── NoSidebar.vue
├── main.d.ts
├── main.ts
├── plugins
│ ├── index.d.ts
│ ├── index.ts
│ ├── vuetify.d.ts
│ ├── vuetify.ts
│ ├── webfontloader.d.ts
│ └── webfontloader.ts
├── router
│ ├── index.d.ts
│ └── index.ts
├── store
│ ├── app.d.ts
│ ├── app.ts
│ ├── index.d.ts
│ └── index.ts
├── styles
│ └── settings.scss
├── views
│ ├── ClusterCreate.vue
│ ├── Clusters.vue
│ ├── Home.vue
│ └── Login.vue
└── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.tsbuildinfo
├── updater.json
├── vite.config.d.ts
└── vite.config.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: [
7 | 'plugin:vue/vue3-essential',
8 | 'eslint:recommended',
9 | '@vue/eslint-config-typescript',
10 | ],
11 | rules: {
12 | 'vue/multi-word-component-names': 'off',
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "cargo" # See documentation for possible values
9 | directory: "src-tauri/" # Location of package manifests
10 | assignees:
11 | - "tobifroe"
12 | schedule:
13 | interval: "weekly"
14 |
15 | - package-ecosystem: "npm"
16 | directory: "/"
17 | assignees:
18 | - "tobifroe"
19 | schedule:
20 | interval: "weekly"
21 |
--------------------------------------------------------------------------------
/.github/workflows/cd.yaml:
--------------------------------------------------------------------------------
1 | name: "test-and-build-on-pr"
2 | on:
3 | push:
4 | branches:
5 | - main
6 | pull_request:
7 | branches:
8 | - main
9 |
10 | jobs:
11 | test:
12 | strategy:
13 | fail-fast: false
14 |
15 | runs-on: ubuntu-20.04
16 | steps:
17 | - uses: actions/checkout@v3
18 | - name: Create dist dir
19 | run: mkdir dist
20 | - name: setup node
21 | uses: actions/setup-node@v3
22 | with:
23 | node-version: 16
24 | - name: install Rust stable
25 | uses: dtolnay/rust-toolchain@stable
26 | - name: install dependencies
27 | run: |
28 | sudo apt-get update
29 | sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
30 | - name: Lint
31 | uses: actions-rs/cargo@v1
32 | with:
33 | command: clippy
34 | args: --manifest-path ./src-tauri/Cargo.toml
35 | - name: Execute tests
36 | uses: actions-rs/cargo@v1
37 | with:
38 | command: test
39 | args: --manifest-path ./src-tauri/Cargo.toml
40 | - uses: taiki-e/install-action@cargo-llvm-cov
41 | - name: Collect Coverage
42 | run: cd src-tauri && cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
43 | - name: Coveralls
44 | uses: coverallsapp/github-action@v2
45 |
46 |
47 | build-debug:
48 | if: ${{ github.event.label.name == 'testbuild' }}
49 | needs: test
50 | strategy:
51 | fail-fast: false
52 | matrix:
53 | platform: [ubuntu-20.04, windows-2022, macos-latest] # TODO add all platforms
54 | runs-on: ${{ matrix.platform }}
55 | steps:
56 | - uses: actions/checkout@v3
57 | - name: setup node
58 | uses: actions/setup-node@v3
59 | with:
60 | node-version: 16
61 | - name: install Rust stable
62 | uses: dtolnay/rust-toolchain@stable
63 | - name: install dependencies (ubuntu only)
64 | if: matrix.platform == 'ubuntu-20.04'
65 | run: |
66 | sudo apt-get update
67 | sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
68 | - name: install app dependencies and build with debug
69 | run: npm install && npm run deploy-debug
70 | - name: Upload Linux debug artifact
71 | uses: actions/upload-artifact@v3
72 | if: matrix.platform == 'ubuntu-20.04'
73 | with:
74 | name: beiboot-desktop-${{ runner.os }}-${{ runner.arch }}-debug
75 | path: |
76 | src-tauri/target/debug/bundle/appimage/getdeck-desktop_0.1.0_amd64.AppImage
77 | /src-tauri/target/debug/bundle/deb/getdeck-desktop_0.1.0_amd64.deb
78 | retention-days: 5
79 | - name: Upload debug artifact
80 | uses: actions/upload-artifact@v3
81 | if: matrix.platform != 'ubuntu-20.04'
82 | with:
83 | name: beiboot-desktop-${{ runner.os }}-${{ runner.arch }}-debug
84 | path: |
85 | src-tauri/target/debug/bundle/
86 | retention-days: 5
87 |
88 | build:
89 | if: ${{ github.event.label.name == 'testbuild' }}
90 | needs: test
91 | strategy:
92 | fail-fast: false
93 | matrix:
94 | platform: [ubuntu-20.04, windows-2022, macos-latest] # TODO add all platforms
95 |
96 | runs-on: ${{ matrix.platform }}
97 | steps:
98 | - uses: actions/checkout@v3
99 | - name: setup node
100 | uses: actions/setup-node@v3
101 | with:
102 | node-version: 16
103 | - name: install Rust stable
104 | uses: dtolnay/rust-toolchain@stable
105 | - name: install dependencies (ubuntu only)
106 | if: matrix.platform == 'ubuntu-20.04'
107 | run: |
108 | sudo apt-get update
109 | sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
110 | - name: build for prod
111 | run: npm install && npm run deploy
112 | - name: Upload Linux prod artifact
113 | uses: actions/upload-artifact@v3
114 | if: matrix.platform == 'ubuntu-20.04'
115 | with:
116 | name: beiboot-desktop-${{ runner.os }}-${{ runner.arch }}
117 | path: |
118 | src-tauri/target/release/bundle/appimage/getdeck-desktop_0.1.0_amd64.AppImage
119 | /src-tauri/target/release/bundle/deb/getdeck-desktop_0.1.0_amd64.deb
120 | retention-days: 5
121 | - name: Upload prod Artifact
122 | uses: actions/upload-artifact@v3
123 | if: matrix.platform != 'ubuntu-20.04'
124 | with:
125 | name: beiboot-desktop-${{ runner.os }}-${{ runner.arch }}
126 | path: |
127 | src-tauri/target/release/bundle/
128 | retention-days: 5
129 |
--------------------------------------------------------------------------------
/.github/workflows/release_build_linux.yaml:
--------------------------------------------------------------------------------
1 | name: "release-build-linux"
2 | on:
3 | push:
4 | tags:
5 | - "*.*.*"
6 |
7 | jobs:
8 | build:
9 | strategy:
10 | fail-fast: false
11 |
12 | runs-on: ubuntu-20.04
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Set Tauri signature private key
16 | run: echo "TAURI_PRIVATE_KEY=${{ secrets.TAURI_PRIVATE_KEY }}" >> $GITHUB_ENV
17 | - name: Set Tauri signature private key password
18 | run: echo "TAURI_KEY_PASSWORD=${{ secrets.TAURI_KEY_PASSWORD }}" >> $GITHUB_ENV
19 | - name: setup node
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: 16
23 | - name: install Rust stable
24 | uses: dtolnay/rust-toolchain@stable
25 | - name: install dependencies (ubuntu only)
26 | run: |
27 | sudo apt-get update
28 | sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
29 | - name: build
30 | run: npm install && npm run deploy
31 | - name: Attach files to release
32 | uses: softprops/action-gh-release@v1
33 | with:
34 | files: |
35 | src-tauri/target/release/bundle/appimage/getdeck-desktop_${{ github.ref_name }}_amd64.AppImage
36 | src-tauri/target/release/bundle/appimage/getdeck-desktop_${{ github.ref_name }}_amd64.AppImage.tar.gz
37 | src-tauri/target/release/bundle/appimage/getdeck-desktop_${{ github.ref_name }}_amd64.AppImage.tar.gz.sig
38 | src-tauri/target/release/bundle/deb/getdeck-desktop_${{ github.ref_name }}_amd64.deb
39 |
40 |
--------------------------------------------------------------------------------
/.github/workflows/release_build_macos.yaml:
--------------------------------------------------------------------------------
1 | name: "release-build-macos"
2 | on:
3 | push:
4 | tags:
5 | - "*.*.*"
6 |
7 | jobs:
8 | build:
9 | strategy:
10 | fail-fast: false
11 |
12 | runs-on: macos-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Set Tauri signature private key
16 | run: echo "TAURI_PRIVATE_KEY=${{ secrets.TAURI_PRIVATE_KEY }}" >> $GITHUB_ENV
17 | - name: Set Tauri signature private key password
18 | run: echo "TAURI_KEY_PASSWORD=${{ secrets.TAURI_KEY_PASSWORD }}" >> $GITHUB_ENV
19 | - name: setup node
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: 16
23 | - name: install Rust stable
24 | uses: dtolnay/rust-toolchain@stable
25 | - name: build
26 | env:
27 | APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
28 | APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
29 | APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
30 | APPLE_ID: ${{ secrets.APPLE_ID }}
31 | APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
32 | run: npm install && npm run deploy
33 | - name: Attach files to release
34 | uses: softprops/action-gh-release@v1
35 | with:
36 | files: |
37 | src-tauri/target/release/bundle/dmg/Getdeck-Desktop_${{ github.ref_name }}_x64.dmg
38 | src-tauri/target/release/bundle/macos/Getdeck-Desktop.app
39 | src-tauri/target/release/bundle/macos/Getdeck-Desktop.app.tar.gz
40 | src-tauri/target/release/bundle/macos/Getdeck-Desktop.app.tar.gz.sig
41 |
42 |
43 |
--------------------------------------------------------------------------------
/.github/workflows/release_build_windows.yaml:
--------------------------------------------------------------------------------
1 | name: "release-build-windows"
2 | on:
3 | push:
4 | tags:
5 | - "*.*.*"
6 |
7 | jobs:
8 | build:
9 | strategy:
10 | fail-fast: false
11 |
12 | runs-on: windows-2022
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Set Tauri Signature Private Key
16 | run: echo "TAURI_PRIVATE_KEY=${{ secrets.TAURI_PRIVATE_KEY }}" | Out-File -FilePath $env:GITHUB_ENV
17 | - name: Set Tauri Sig Password
18 | run: echo "TAURI_KEY_PASSWORD=${{ secrets.TAURI_KEY_PASSWORD }}" | Out-File -FilePath $env:GITHUB_ENV
19 | - name: setup node
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: 16
23 | - name: install Rust stable
24 | uses: dtolnay/rust-toolchain@stable
25 | - name: build
26 | run: npm install && npm run deploy
27 | - name: Attach files to release
28 | uses: softprops/action-gh-release@v1
29 | with:
30 | files: |
31 | src-tauri/target/release/bundle/msi/getdeck-desktop_${{ github.ref_name }}_x64_en-US.msi
32 | src-tauri/target/release/bundle/msi/getdeck-desktop_${{ github.ref_name }}_x64_en-US.msi.zip
33 | src-tauri/target/release/bundle/msi/getdeck-desktop_${{ github.ref_name }}_x64_en-US.msi.zip.sig
34 |
--------------------------------------------------------------------------------
/.github/workflows/release_notifications.yaml:
--------------------------------------------------------------------------------
1 | name: Send mail on release
2 |
3 | on:
4 | workflow_dispatch: {}
5 | release:
6 | types:
7 | - published
8 |
9 | jobs:
10 | post-discord-announcement:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: Ilshidur/action-discord@0.3.2
14 | name: Send Discord Release Announcement
15 | # add random emoji to the message
16 | env:
17 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
18 | with:
19 | args: "Beiboot Desktop Version ${{ github.event.release.tag_name }} is out! 🚀 Here's the changelog: https://github.com/Getdeck/beiboot-desktop/releases/tag/${{ github.event.release.tag_name }}"
20 |
--------------------------------------------------------------------------------
/.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 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | src-tauri/bin
27 | tsconfig.tsbuildinfo
28 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/mirrors-prettier
3 | rev: "cafd550" # Use the sha or tag you want to point at
4 | hooks:
5 | - id: prettier
6 | additional_dependencies:
7 | - prettier-plugin-svelte
8 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
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 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | src-tauri/binaries
27 | src-tauri/target
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
21 | [![Contributors][contributors-shield]][contributors-url]
22 | [![Stargazers][stars-shield]][stars-url]
23 | [![Issues][issues-shield]][issues-url]
24 | [![MIT License][license-shield]][license-url]
25 | 
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
Getdeck Desktop
38 |
39 |
40 | A tool suite to provide reproducible Kubernetes environments for development and testing.
41 |
42 | Install
43 | ·
44 | Report Bug
45 | ·
46 | Request Feature
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Table of Contents
55 |
56 |
57 | About The Project
58 |
59 |
60 | Getting Started
61 |
65 |
66 | Usage
67 | Roadmap
68 | Contributing
69 | License
70 | Contact
71 | Acknowledgments
72 |
73 |
74 |
75 |
76 |
77 |
78 | ## About The Project
79 |
80 | [![Product Name Screen Shot][product-screenshot]](https://example.com)
81 |
82 | (back to top )
83 |
84 |
85 | ## Getting Started
86 | ### Prerequisites
87 | In order to use Getdeck Desktop to connect to a remote cluster, [Docker Engine](https://docs.docker.com/engine/install/) needs to run on your machine.
88 | Running the AppImage on Linux requires [Fuse](https://docs.appimage.org/user-guide/troubleshooting/fuse.html).
89 |
90 | ### Installation
91 | Note: The tarballs attached to releases are update packages.
92 |
93 | 1. Download a version of Getdeck Desktop from the [releases page](https://github.com/Getdeck/Getdeck-Desktop/releases) that fits your operating system. Currently, we support Linux, MacOS and Windows.
94 | 2. Follow the installation process for your operating system.
95 | 3. After starting Getdeck Desktop, create an account. (It's free!)
96 | 4. You are now able to create a ephemeral, remote kubernetes cluster and connect your machine to it. 🚀
97 |
98 | (back to top )
99 |
100 |
101 |
102 | ## Usage
103 |
104 | Getdeck Desktop allows you to create virtual, remote kubernetes clusters easily through the UI.
105 | First, create a new cluster through the UI via the `create` dialog. Pick a name, choose ports that should be available for you later and hit create.
106 | Once the cluster is ready, you will see a green `RUNNING` badge in the cluster list.
107 | Next, hit the connect icon to enable port forwardings between the remote virtual cluster and your machine. As soon as the connection is established, you
108 | can copy the path to the kubeconfig, set the `KUBECONFIG` env variable in your favorite shell and use any tool that can talk to the Kubernetes API server!🚀
109 |
110 | (back to top )
111 |
112 |
113 |
114 |
115 | ## Roadmap
116 |
117 | - [ ] Shelf clusters
118 | - [ ] ...
119 | - [ ] ...
120 |
121 | See the [open issues](https://github.com/Getdeck/Getdeck-Desktop/issues) for a full list of proposed features (and known issues).
122 |
123 | (back to top )
124 |
125 |
126 |
127 |
128 | ## Contributing
129 |
130 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
131 |
132 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
133 | Don't forget to give the project a star! Thanks again!
134 |
135 | 1. Fork the Project
136 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
137 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
138 | 4. Push to the Branch (`git push origin feature/AmazingFeature`)
139 | 5. Open a Pull Request
140 |
141 | (back to top )
142 |
143 |
144 |
145 |
146 | ## License
147 |
148 | Distributed under the Apache 2.0 License. See `LICENSE` for more information.
149 |
150 | (back to top )
151 |
152 |
153 |
154 | ## Contact
155 |
156 | If you're stuck or just want to have a chat, please join the [Team Blueshoe Discord](https://discord.gg/qb5gjmzr)!
157 |
158 | (back to top )
159 |
160 |
161 |
162 |
163 | [contributors-shield]: https://img.shields.io/github/contributors/Getdeck/Getdeck-Desktop.svg?style=for-the-badge
164 | [contributors-url]: https://github.com/Getdeck/Getdeck-Desktop/graphs/contributors
165 | [stars-shield]: https://img.shields.io/github/stars/Getdeck/Getdeck-Desktop.svg?style=for-the-badge
166 | [stars-url]: https://github.com/Getdeck/Getdeck-Desktop/stargazers
167 | [issues-shield]: https://img.shields.io/github/issues/Getdeck/Getdeck-Desktop.svg?style=for-the-badge
168 | [issues-url]: https://github.com/Getdeck/Getdeck-Desktop/issues
169 | [license-shield]: https://img.shields.io/github/license/Getdeck/Getdeck-Desktop.svg?style=for-the-badge
170 | [license-url]: https://github.com/Getdeck/Getdeck-Desktop/blob/main/LICENSE
171 | [product-screenshot]: screenshot.png
172 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Releases
2 |
3 | ## How to release a new version of Getdeck Desktop
4 |
5 | 1. Make sure you have `jq` and `toml-cli` installed and available in your path
6 | 2. From the project root, run `./bumpversion.sh $VERSION_NUMBER` and commit the result
7 | 3. Create a new tag with the version number that you are publishing
8 | 4. Push the tag and watch the CI/CD pipeline build bundles and create a new release on Github
9 | 5. Once the pipeline finishes (make sure every OS build went through smoothly and all files are present),
10 | run `./rollout.sh $VERSION_NUMBER` to adapt `updater.json`.
11 | 6. Commit the result, Tauri Updater will now notify users that new version is ready to download.
12 |
--------------------------------------------------------------------------------
/app-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/app-icon.png
--------------------------------------------------------------------------------
/bumpversion.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script is used to bump the version of Getdeck Desktop in all relevant files.
4 | # This script requires toml-cli (https://github.com/gnprice/toml-cli) to work correctly.
5 |
6 | VERSION=$1
7 |
8 | if [ -z "$VERSION" ]
9 | then
10 | echo "Please provide a version number."
11 | exit 1
12 | fi
13 |
14 | jq --arg VERSION "$VERSION" '.version = $VERSION' package.json > package.json.tmp && mv package.json.tmp package.json
15 | jq --arg VERSION "$VERSION" '.package.version = $VERSION' src-tauri/tauri.conf.json > src-tauri/tauri.conf.json.tmp && mv src-tauri/tauri.conf.json.tmp src-tauri/tauri.conf.json
16 | toml set src-tauri/Cargo.toml package.version "$VERSION" > src-tauri/Cargo.toml.tmp && mv src-tauri/Cargo.toml.tmp src-tauri/Cargo.toml
17 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Welcome to Vuetify 3
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "beiboot-desktop",
3 | "private": true,
4 | "version": "0.1.2",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview",
10 | "tauri": "cross-env NODE_ENV=debug tauri",
11 | "deploy": "tauri build",
12 | "deploy-debug": "cross-env NODE_ENV=debug tauri build --debug"
13 | },
14 | "devDependencies": {
15 | "@babel/types": "^7.22.10",
16 | "@mdi/font": "7.2.96",
17 | "@tauri-apps/api": "^1.3.0",
18 | "@tauri-apps/cli": "^1.3.0",
19 | "@types/node": "^18.11.11",
20 | "@types/webfontloader": "^1.6.35",
21 | "@vitejs/plugin-vue": "^3.0.3",
22 | "@vue/eslint-config-typescript": "^11.0.3",
23 | "core-js": "^3.8.3",
24 | "cross-env": "^7.0.3",
25 | "eslint": "^8.22.0",
26 | "eslint-plugin-vue": "^9.3.0",
27 | "pinia": "^2.1.6",
28 | "prettier": "^2.8.8",
29 | "roboto-fontface": "*",
30 | "sass": "^1.66.1",
31 | "typescript": "^4.6.4",
32 | "vite": "^3.2.3",
33 | "vite-plugin-vuetify": "^1.0.0-alpha.12",
34 | "vue": "^3.2.13",
35 | "vue-router": "^4.0.0",
36 | "vuetify": "3.2.4",
37 | "webfontloader": "^1.0.0"
38 | },
39 | "dependencies": {
40 | "@sentry/vue": "^7.55.2",
41 | "axios": "^1.2.5",
42 | "beiboot-api-client": "^0.1.4",
43 | "keycloak-js": "^21.0.1",
44 | "tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/public/beiboot-logo-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
26 |
32 |
35 |
41 |
47 |
53 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
67 |
70 |
71 |
74 |
77 |
80 |
81 |
82 |
83 |
84 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/public/beiboot-logo-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/public/beiboot-logo-light.png
--------------------------------------------------------------------------------
/public/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
12 |
15 |
16 |
19 |
22 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/rollout.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script is used to rollout the new version of Getdeck Desktop via Tauri Updater.
4 |
5 | VERSION=$1
6 |
7 | if [ -z "$VERSION" ]
8 | then
9 | echo "Please provide a version number."
10 | exit 1
11 | fi
12 |
13 | MACOS_SIG=$(wget -q -O- https://github.com/Getdeck/Getdeck-Desktop/releases/download/$VERSION/Getdeck-Desktop.app.tar.gz.sig)
14 | LINUX_SIG=$(wget -q -O- https://github.com/Getdeck/Getdeck-Desktop/releases/download/$VERSION/getdeck-desktop_${VERSION}_amd64.AppImage.tar.gz.sig)
15 | WINDOWS_SIG=$(wget -q -O- https://github.com/Getdeck/Getdeck-Desktop/releases/download/$VERSION/getdeck-desktop_${VERSION}_x64_en-US.msi.zip.sig)
16 |
17 | MACOS_DOWNLOAD="https://github.com/Getdeck/Getdeck-Desktop/releases/download/$VERSION/Getdeck-Desktop.app.tar.gz"
18 | LINUX_DOWNLOAD="https://github.com/Getdeck/Getdeck-Desktop/releases/download/$VERSION/getdeck-desktop_${VERSION}_amd64.AppImage.tar.gz"
19 | WINDOWS_DOWNLOAD="https://github.com/Getdeck/Getdeck-Desktop/releases/download/$VERSION/getdeck-desktop_${VERSION}_x64_en-US.msi.zip"
20 |
21 | NOTES="Getdeck Desktop $VERSION is now available."
22 |
23 |
24 | jq --arg MACOS_SIG "$MACOS_SIG" --arg LINUX_SIG "$LINUX_SIG" --arg WINDOWS_SIG "$WINDOWS_SIG" '.platforms."darwin-x86_64".signature = $MACOS_SIG |
25 | .platforms."linux-x86_64".signature = $LINUX_SIG |
26 | .platforms."windows-x86_64".signature = $WINDOWS_SIG' updater.json > updater.json.tmp && mv updater.json.tmp updater.json
27 |
28 | jq --arg MACOS_DOWNLOAD "$MACOS_DOWNLOAD" --arg LINUX_DOWNLOAD "$LINUX_DOWNLOAD" --arg WINDOWS_DOWNLOAD "$WINDOWS_DOWNLOAD" '.platforms."darwin-x86_64".url = $MACOS_DOWNLOAD |
29 | .platforms."linux-x86_64".url = $LINUX_DOWNLOAD |
30 | .platforms."windows-x86_64".url = $WINDOWS_DOWNLOAD' updater.json > updater.json.tmp && mv updater.json.tmp updater.json
31 |
32 | jq --arg VERSION "$VERSION" '.version = $VERSION' updater.json > updater.json.tmp && mv updater.json.tmp updater.json
33 | jq --arg NOTES "$NOTES" '.notes = $NOTES' updater.json > updater.json.tmp && mv updater.json.tmp updater.json
34 |
35 |
36 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/screenshot.png
--------------------------------------------------------------------------------
/src-tauri/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | /target/
4 |
--------------------------------------------------------------------------------
/src-tauri/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "beiboot_desktop"
3 | version = "0.1.2"
4 | description = "Getdeck-Desktop allows to manage Getdeck Kubernetes clusters and connect to them from a local machine."
5 | authors = ["Tobias Frölich ", "Michael Schilonka "]
6 | license = "../LICENSE"
7 | repository = "https://github.com/Getdeck/Getdeck-Desktop/"
8 | default-run = "beiboot_desktop"
9 | edition = "2021"
10 | rust-version = "1.59"
11 | publish = false
12 |
13 | [build-dependencies]
14 | tauri-build = { version = "1.4.0", features = [] }
15 |
16 | [dependencies]
17 | serde_json = "1.0"
18 | serde = { version = "1.0", features = ["derive"] }
19 | tauri = { version = "1.3.0", features = ["process-command-api", "shell-open", "updater"] }
20 | tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
21 | strum = "0.25.0"
22 | strum_macros = "0.25.1"
23 | bollard = "0.14.0"
24 | futures = "0.3.28"
25 | tokio = "1.29.1"
26 | shellexpand = "3.1.0"
27 | futures-util = "0.3"
28 | tauri-plugin-oauth = "0.0.0-alpha.0"
29 | sentry = "0.31.5"
30 | tauri-plugin-localhost = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
31 | portpicker = "0.1"
32 | tokio-tungstenite = { version = "0.19.0", features = ["native-tls"] }
33 | httparse = "1.8.0"
34 | reqwest = "0.11.18"
35 | tokio-test = "0.4.2"
36 | mockito = "1.1.0"
37 |
38 | [features]
39 | # by default Tauri runs in production mode
40 | # when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
41 | default = ["custom-protocol"]
42 | # this feature is used for production builds where `devPath` points to the filesystem
43 | # DO NOT remove this
44 | custom-protocol = ["tauri/custom-protocol"]
45 |
--------------------------------------------------------------------------------
/src-tauri/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | tauri_build::build()
3 | }
4 |
--------------------------------------------------------------------------------
/src-tauri/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/128x128.png
--------------------------------------------------------------------------------
/src-tauri/icons/128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/128x128@2x.png
--------------------------------------------------------------------------------
/src-tauri/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/32x32.png
--------------------------------------------------------------------------------
/src-tauri/icons/32x32.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | image/svg+xml
46 |
49 |
51 |
53 |
58 |
62 |
66 |
67 |
68 |
69 |
72 |
73 |
--------------------------------------------------------------------------------
/src-tauri/icons/Square107x107Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square107x107Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square142x142Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square142x142Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square150x150Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square150x150Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square284x284Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square284x284Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square30x30Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square30x30Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square310x310Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square310x310Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square44x44Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square44x44Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square71x71Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square71x71Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square89x89Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/Square89x89Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/StoreLogo.png
--------------------------------------------------------------------------------
/src-tauri/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/icon.icns
--------------------------------------------------------------------------------
/src-tauri/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/icon.ico
--------------------------------------------------------------------------------
/src-tauri/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/289b8c3e66d97ed9a4d717745a243a5ad8bc763c/src-tauri/icons/icon.png
--------------------------------------------------------------------------------
/src-tauri/src/connection.rs:
--------------------------------------------------------------------------------
1 | use std::{error::Error, fmt};
2 | use serde::Deserialize;
3 |
4 | pub mod ghostunnel;
5 |
6 | pub fn get_connector_context<'a>(beiboot_name: &'a str, strategy: &str) -> ConnectorContext<'a> {
7 | let imp_strategy = match strategy {
8 | "GhostunnelDocker" => ghostunnel::GhostunnelDocker,
9 | _ => ghostunnel::GhostunnelDocker,
10 | };
11 | ConnectorContext {
12 | connector: Box::new(imp_strategy),
13 | name: beiboot_name,
14 | }
15 | }
16 |
17 | #[derive(Debug)]
18 | pub struct ConnectError {
19 | details: String,
20 | }
21 |
22 | impl ConnectError {
23 | fn new(msg: &str) -> ConnectError {
24 | ConnectError {
25 | details: msg.to_string(),
26 | }
27 | }
28 | }
29 |
30 | impl fmt::Display for ConnectError {
31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 | write!(f, "{}", self.details)
33 | }
34 | }
35 |
36 | impl Error for ConnectError {
37 | fn description(&self) -> &str {
38 | &self.details
39 | }
40 | }
41 |
42 | pub struct ConnectorContext<'a> {
43 | pub connector: Box,
44 | pub name: &'a str,
45 | }
46 |
47 | impl<'a> ConnectorContext<'a> {
48 | pub fn connect(&self, ports: &[PortMapping], mtls: &TLSFiles) -> Result<(), ConnectError> {
49 | println!("Connecting to Beiboot {}", self.name);
50 | let result = self.connector.establish(self.name, ports, mtls);
51 | println!("Connection to Beiboot {} established", self.name);
52 | result
53 | }
54 | pub fn disconnect(&self) -> Result<(), ConnectError> {
55 | println!("Disconnect preamble");
56 | let result = self.connector.terminate(self.name);
57 | println!("Disconnect postamble");
58 | result
59 | }
60 | pub fn check_running(&self) -> Result, ConnectError> {
61 |
62 | self.connector.check_running()
63 | }
64 | }
65 |
66 | #[derive(Deserialize)]
67 | pub struct PortMapping<'a> {
68 | pub target: u16,
69 | pub endpoint: &'a str,
70 | }
71 |
72 | pub struct TLSFiles<'a> {
73 | pub ca_cert_path: &'a str,
74 | pub client_key_path: &'a str,
75 | pub client_cert_path: &'a str,
76 | }
77 |
78 | pub trait Connector {
79 | fn establish(
80 | &self,
81 | name: &str,
82 | ports: &[PortMapping],
83 | mtls: &TLSFiles,
84 | ) -> Result<(), ConnectError>;
85 | fn check_running(&self) -> Result, ConnectError>;
86 | fn terminate(&self, name: &str) -> Result<(), ConnectError>;
87 | }
88 |
89 | #[cfg(test)]
90 | mod connection_tests {
91 | #[test]
92 | fn test_get_connector_context() {
93 | let connector = super::get_connector_context("test", "GhostunnelDocker");
94 | assert_eq!("test", connector.name);
95 | let other = super::get_connector_context("other", "other");
96 | assert_eq!("other", other.name);
97 | }
98 |
99 | #[test]
100 | fn test_connecterror() {
101 | let err = super::ConnectError::new("test");
102 | assert_eq!("test", err.details);
103 | assert_eq!(format!("{}", err), "test");
104 | }
105 | }
--------------------------------------------------------------------------------
/src-tauri/src/connection/ghostunnel.rs:
--------------------------------------------------------------------------------
1 | use bollard::container::{Config, CreateContainerOptions, StartContainerOptions, ListContainersOptions, RemoveContainerOptions};
2 | use bollard::service::{HostConfig, PortBinding, PortMap, RestartPolicy, RestartPolicyNameEnum};
3 | use bollard::Docker;
4 |
5 | use std::collections::HashMap;
6 | use futures_util::TryStreamExt;
7 |
8 | use crate::connection::{Connector, PortMapping, TLSFiles};
9 |
10 | use super::ConnectError;
11 |
12 | pub struct GhostunnelDocker;
13 |
14 | static GHOSTUNNEL_IMAGE: &str = "ghostunnel/ghostunnel:v1.7.1";
15 |
16 | impl Connector for GhostunnelDocker {
17 | fn establish(&self, name: &str, ports: &[PortMapping], mtls: &TLSFiles) -> Result<(), ConnectError> {
18 | tokio::runtime::Builder::new_multi_thread()
19 | .enable_all()
20 | .build()
21 | .unwrap()
22 | .block_on(async move {
23 | let docker = match Docker::connect_with_socket_defaults() {
24 | Err(why) => return Err(ConnectError::new(format!("Docker error: {}", why).as_str())),
25 | Ok(docker) => docker,
26 | };
27 |
28 | let version = docker.version().await.unwrap();
29 | let platform = format!("linux/{}", version.arch.unwrap());
30 |
31 | for port in ports {
32 | let container_name = format!(
33 | "getdeck-beiboot-{name}-{local_port}",
34 | name = name,
35 | local_port = port.target
36 | );
37 | let fcmd = format!(
38 | "client --listen 0.0.0.0:{local_port} --unsafe-listen --target {endpoint} --cert /crt/client.crt --key /crt/client.key --cacert /crt/ca.crt",
39 | local_port = port.target,
40 | endpoint = port.endpoint
41 | );
42 | let cmd: Vec<&str> = fcmd.split(' ').collect();
43 | let options = Some(CreateContainerOptions {
44 | name: container_name.as_str(),
45 | platform: Some(&platform),
46 | });
47 | let labels = HashMap::from([
48 | ("beiboot.getdeck.dev/name", name)
49 | ]);
50 |
51 | let iport = port.target.to_string();
52 | let exposed_ports = HashMap::from(
53 | [(iport.as_str(), HashMap::from([]))]
54 | );
55 |
56 | let port_map: PortMap = HashMap::from(
57 | [
58 | (iport.clone(),
59 | Some(vec![
60 | PortBinding {host_ip: Some("127.0.0.1".to_string()), host_port: Some(iport.clone())}
61 | ])
62 | )
63 | ]);
64 | let cacrt = format!("{}:{}", mtls.ca_cert_path, "/crt/ca.crt");
65 | let clientcrt = format!("{}:{}", mtls.client_cert_path, "/crt/client.crt");
66 | let clientkey = format!("{}:{}", mtls.client_key_path, "/crt/client.key");
67 | let bind_mounts = vec![cacrt, clientcrt, clientkey];
68 |
69 | let hostconfig = HostConfig {
70 | auto_remove: Some(false),
71 | restart_policy: Some(RestartPolicy { name: Some(RestartPolicyNameEnum::UNLESS_STOPPED), maximum_retry_count: None}),
72 | binds: Some(bind_mounts),
73 | port_bindings: Some(port_map),
74 | ..Default::default()
75 | };
76 |
77 | let _ghostunnel_image = docker.create_image(
78 | Some(bollard::image::CreateImageOptions {
79 | from_image: GHOSTUNNEL_IMAGE,
80 | ..Default::default()
81 | }),
82 | None,
83 | None
84 | ).try_collect::>().await;
85 |
86 | let ghostunnel_config = Config {
87 | image: Some(GHOSTUNNEL_IMAGE),
88 | cmd: Some(cmd),
89 | exposed_ports: Some(exposed_ports),
90 | host_config: Some(hostconfig),
91 | labels: Some(labels),
92 | ..Default::default()
93 | };
94 |
95 | if let Err(why) = docker.create_container(options, ghostunnel_config).await {
96 | return Err(ConnectError::new(format!("Error creating container: {}", why).as_str()))
97 | }
98 |
99 | println!(
100 | "Creating forwarding from {} to {}",
101 | port.target, port.endpoint
102 | );
103 | println!(
104 | "with CA {}, Client {}, Key {}",
105 | mtls.ca_cert_path, mtls.client_cert_path, mtls.client_key_path
106 | );
107 | let sval = docker
108 | .start_container(container_name.as_str(), None::>)
109 | .await;
110 |
111 | match sval {
112 | Ok(sval) => sval,
113 | Err(why) => return Err(ConnectError::new(format!("Could not start container: {}", why).as_str())),
114 | }
115 | }
116 | Ok(())
117 | })
118 |
119 | }
120 |
121 | fn terminate(&self, name: &str) -> Result<(), ConnectError> {
122 | tokio::runtime::Builder::new_multi_thread()
123 | .enable_all()
124 | .build()
125 | .unwrap()
126 | .block_on(async move {
127 | let docker = match Docker::connect_with_socket_defaults() {
128 | Err(why) => return Err(ConnectError::new(format!("Docker error: {}", why).as_str())),
129 | Ok(docker) => docker,
130 | };
131 |
132 |
133 | let name_label = if name.is_empty() { "beiboot.getdeck.dev/name".to_string() } else { format!("beiboot.getdeck.dev/name={name}", name=name) };
134 |
135 |
136 | let filters = HashMap::from([
137 | ("label", vec![name_label.as_str()])
138 | ]);
139 |
140 | let options = Some(ListContainersOptions{
141 | filters,
142 | ..Default::default()
143 | });
144 |
145 | let remove_options = Some(RemoveContainerOptions {
146 | force: true,
147 | ..Default::default()
148 | });
149 |
150 |
151 |
152 | let rcontainers = docker.list_containers(options).await;
153 | let containers = match rcontainers {
154 | Ok(containers) => containers,
155 | Err(why) => return Err(ConnectError::new(format!("Could not find containers: {}", why).as_str())),
156 | };
157 | for container in containers{
158 | match container.id {
159 | None => None,
160 | Some(i) => Some(docker.remove_container(i.as_str(), remove_options).await),
161 | };
162 | }
163 |
164 |
165 |
166 |
167 | Ok(())
168 | })
169 |
170 | }
171 |
172 | fn check_running(&self) -> Result, ConnectError> {
173 | tokio::runtime::Builder::new_multi_thread()
174 | .enable_all()
175 | .build()
176 | .unwrap()
177 | .block_on(async move {
178 | let docker = match Docker::connect_with_socket_defaults() {
179 | Err(why) => return Err(ConnectError::new(format!("Docker error: {}", why).as_str())),
180 | Ok(docker) => docker,
181 | };
182 |
183 | let name_label = "beiboot.getdeck.dev/name".to_string();
184 |
185 | let filters = HashMap::from([
186 | ("label", vec![name_label.as_str()])
187 | ]);
188 |
189 | let options = Some(ListContainersOptions{
190 | filters,
191 | ..Default::default()
192 | });
193 |
194 | let mut result = vec![];
195 |
196 | let rcontainers = docker.list_containers(options).await;
197 | match rcontainers {
198 | Ok(containers) => {
199 | for container in &containers {
200 | match &container.labels.clone().expect("Could not get labels.").get("beiboot.getdeck.dev/name") {
201 | None => return Err(ConnectError::new(format!("Could not find containers: {}", "No name label").as_str())),
202 | Some(name) => result.push(name.to_string()),
203 | }
204 | }
205 | Ok(result)
206 | },
207 | Err(why) => return Err(ConnectError::new(format!("Could not find containers: {}", why).as_str())),
208 | }
209 | })
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src-tauri/src/heartbeat.rs:
--------------------------------------------------------------------------------
1 | use beiboot_desktop::connection::ConnectError;
2 |
3 | pub async fn establish_heartbeat_connection(cluster_id: &str, token: &str, getdeck_url: &str) -> Result {
4 | let resp = reqwest::Client::new()
5 | .post(format!("{}/clusters/{}/heartbeat", getdeck_url, cluster_id).as_str())
6 | .header(reqwest::header::AUTHORIZATION, format!("Bearer {}", token))
7 | .send()
8 | .await
9 | .expect("Failed to send");
10 | Ok(format!("Heartbeat status: {}", resp.status()))
11 | }
12 |
13 | #[cfg(test)]
14 | mod tests {
15 | use super::establish_heartbeat_connection;
16 |
17 | #[tokio::test]
18 | async fn test_establish_heartbeat_connection_success() {
19 | let mut server = mockito::Server::new();
20 | let url = server.url();
21 |
22 | let mock = server.mock("POST", "/clusters/123/heartbeat")
23 | .with_status(200)
24 | .create();
25 |
26 | let result = establish_heartbeat_connection("123", "token", &url).await;
27 | mock.assert();
28 | assert_eq!("Heartbeat status: 200 OK", result.unwrap())
29 | }
30 |
31 | #[tokio::test]
32 | async fn test_establish_heartbeat_connection_failure() {
33 | let mut server = mockito::Server::new();
34 | let url = server.url();
35 |
36 | let mock = server.mock("POST", "/clusters/123/heartbeat")
37 | .with_status(500)
38 | .create();
39 |
40 | let result = establish_heartbeat_connection("123", "token", &url).await;
41 | mock.assert();
42 | assert_eq!("Heartbeat status: 500 Internal Server Error", result.unwrap())
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src-tauri/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod connection;
2 |
--------------------------------------------------------------------------------
/src-tauri/src/main.rs:
--------------------------------------------------------------------------------
1 | #![cfg_attr(
2 | all(not(debug_assertions), target_os = "windows"),
3 | windows_subsystem = "windows"
4 | )]
5 |
6 | use beiboot_desktop::connection::{get_connector_context, PortMapping, TLSFiles};
7 | use tauri_plugin_oauth::start;
8 | use tauri::{utils::config::AppUrl, window::WindowBuilder, WindowUrl};
9 |
10 | mod util;
11 | mod heartbeat;
12 |
13 | fn main() {
14 | let _guard = sentry::init(("https://a64f388330914f08b0a015e6068dac3d@o146863.ingest.sentry.io/4505356777357312", sentry::ClientOptions {
15 | release: sentry::release_name!(),
16 | ..Default::default()
17 | }));
18 | let mut context = tauri::generate_context!();
19 | let mut builder = tauri::Builder::default();
20 |
21 | let port = portpicker::pick_unused_port().expect("failed to find an available port");
22 | #[cfg(dev)]
23 | {
24 | let port = 5173;
25 | }
26 | let url = format!("http://localhost:{}", port).parse().unwrap();
27 | let window_url = WindowUrl::External(url);
28 | context.config_mut().build.dist_dir = AppUrl::Url(window_url.clone());
29 |
30 | builder = builder
31 | .invoke_handler(tauri::generate_handler![connect_beiboot_ghostunnel, disconnect_beiboot_ghostunnel, write_kubeconfig, cleanup, start_server, check_running_connects, establish_heartbeat_connection, check_docker_engine])
32 | .plugin(tauri_plugin_localhost::Builder::new(port).build())
33 | .plugin(tauri_plugin_store::Builder::default().build())
34 | .setup(move |app| {
35 | WindowBuilder::new(
36 | app,
37 | "main".to_string(),
38 | if cfg!(dev) {
39 | Default::default()
40 | } else {
41 | window_url
42 | }
43 | )
44 | .fullscreen(false)
45 | .inner_size(1200.0, 800.0)
46 | .title("Getdeck Desktop")
47 | .build()?;
48 | Ok(())
49 | })
50 | .on_window_event(|event| {
51 | match event.event() {
52 | tauri::WindowEvent::CloseRequested { .. } | tauri::WindowEvent::Destroyed { .. } => {
53 | get_connector_context("", "GhostunnelDocker").disconnect().unwrap();
54 | }
55 | _ => {}
56 | }
57 | });
58 |
59 | builder
60 | .run(context)
61 | .expect("error while running tauri application");
62 | }
63 |
64 | #[tauri::command]
65 | async fn start_server(window: tauri::Window) -> Result {
66 | let tauri_url = window.url();
67 | start(move |url| {
68 | let params = url.split('#').collect::>();
69 | window.eval(format!("window.location.replace('{}#{}')", tauri_url, params[1]).as_str()).unwrap();
70 | })
71 | .map_err(|e| e.to_string())
72 | }
73 |
74 | #[tauri::command]
75 | fn connect_beiboot_ghostunnel(beiboot_name: String, ports: Vec, ca: &str, cl_cert: &str, cl_key: &str) -> Result {
76 | let connector = get_connector_context(&beiboot_name, "GhostunnelDocker");
77 | let ca_cert_path = util::write_conf_file(beiboot_name.clone(), ca, "ca.crt").unwrap();
78 | let client_cert_path = util::write_conf_file(beiboot_name.clone(), cl_cert, "client.crt").unwrap();
79 | let client_key_path = util::write_conf_file(beiboot_name.clone(), cl_key, "client.key").unwrap();
80 |
81 | let tls = TLSFiles {
82 | ca_cert_path: &ca_cert_path,
83 | client_cert_path: &client_cert_path,
84 | client_key_path: &client_key_path,
85 | };
86 |
87 | match connector.connect(&ports, &tls) {
88 | Ok(_) => Ok("Cluster connected successfully".into()),
89 | Err(why) => {
90 | println!("{}", why);
91 | Err(format!("{}", why))
92 | }
93 | }
94 | }
95 |
96 | #[tauri::command]
97 | fn disconnect_beiboot_ghostunnel(beiboot_name: String) -> Result {
98 | let connector = get_connector_context(&beiboot_name, "GhostunnelDocker");
99 | match connector.disconnect() {
100 | Ok(_) => Ok("Cluster disconnected successfully".into()),
101 | Err(why) => {
102 | println!("{}", why);
103 | Err(format!("{}", why))
104 | }
105 | }
106 | }
107 |
108 | #[tauri::command]
109 | fn write_kubeconfig(beiboot_name: String, kubeconfig: String) -> Result {
110 | match util::write_conf_file(beiboot_name, &kubeconfig, "kubeconfig.yaml") {
111 | Ok(path) => Ok(path),
112 | Err(why) => {
113 | println!("{}", why);
114 | Err(why)
115 | }
116 | }
117 | }
118 |
119 | #[tauri::command]
120 | fn cleanup(beiboot_name: String) -> Result<(), String> {
121 | match util::cleanup(beiboot_name) {
122 | Ok(_) => Ok(()),
123 | Err(why) => {
124 | println!("{}", why);
125 | Err(why)
126 | }
127 | }
128 | }
129 |
130 | #[tauri::command]
131 | fn check_running_connects() -> Result, String> {
132 | let connector = get_connector_context("any", "GhostunnelDocker");
133 | match connector.check_running() {
134 | Ok(running) => Ok(running),
135 | Err(why) => {
136 | println!("{}", why);
137 | Err(format!("{}", why))
138 | }
139 | }
140 | }
141 |
142 | #[tauri::command]
143 | async fn establish_heartbeat_connection(cluster_id: &str, token: &str) -> Result<(), String> {
144 | match heartbeat::establish_heartbeat_connection(cluster_id, token, "https://api.getdeck.dev").await {
145 | Ok(_) => Ok(()),
146 | Err(why) => {
147 | println!("{}", why);
148 | Err(format!("{}", why))
149 | }
150 | }
151 | }
152 |
153 | #[tauri::command]
154 | async fn check_docker_engine() -> Result {
155 | match util::check_docker_engine().await {
156 | Ok(res) => Ok(res),
157 | Err(why) => {
158 | println!("{}", why);
159 | Err(format!("{}", why))
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src-tauri/src/util.rs:
--------------------------------------------------------------------------------
1 | use std::fs::{File,create_dir_all};
2 | use std::io::prelude::*;
3 | use std::env::temp_dir;
4 | use std::path::PathBuf;
5 | use bollard::Docker;
6 |
7 | pub fn write_conf_file(beiboot_name: String, content: &str, file_type: &str) -> Result {
8 |
9 | let tmp = temp_dir();
10 | let mut path = PathBuf::from(&tmp);
11 | path.push("beiboot");
12 | path.push(&beiboot_name);
13 | let dir_result = create_dir_all(path.clone());
14 | match dir_result {
15 | Ok(_) => (),
16 | Err(why) => {
17 | println!("{}", why);
18 | return Err(format!("{}", why));
19 | }
20 | }
21 |
22 | path.push(file_type);
23 | let file_result = File::create(&path);
24 | let mut file = match file_result {
25 | Ok(file) => file,
26 | Err(why) => {
27 | println!("{}", why);
28 | return Err(format!("{}", why));
29 | }
30 | };
31 | file.write_all(content.as_bytes()).unwrap();
32 |
33 | Ok(path.to_str().unwrap().to_string())
34 | }
35 |
36 | pub fn cleanup(beiboot_name: String) -> Result<(), String> {
37 | let tmp = temp_dir();
38 | let mut path = PathBuf::from(&tmp);
39 | path.push("beiboot");
40 | path.push(&beiboot_name);
41 | let dir_result = std::fs::remove_dir_all(path);
42 | match dir_result {
43 | Ok(_) => Ok(()),
44 | Err(why) => {
45 | println!("{}", why);
46 | Err(format!("{}", why))
47 | }
48 | }
49 | }
50 |
51 | pub async fn check_docker_engine() -> Result {
52 | let docker = Docker::connect_with_local_defaults().unwrap();
53 | match docker.info().await {
54 | Ok(_) => Ok("Docker engine is running".to_string()),
55 | Err(why) => Err(format!("{}", why))
56 | }
57 | }
58 |
59 | #[cfg(test)]
60 | mod tests {
61 | #[test]
62 | fn test_write_cleanup_tls_files() {
63 | let beiboot_name = "test".to_string();
64 | let content = "test".to_string();
65 | let cert_type = "ca.crt".to_string();
66 | let result = super::write_conf_file(beiboot_name.clone(), &content, &cert_type);
67 | assert!(result.is_ok());
68 |
69 | // Note: this assertion will fail if the temp directory is not /tmp,
70 | // eg on windows or macos. To successfully run this on macos, set TMPDIR=/tmp
71 | assert_eq!(result.unwrap(), "/tmp/beiboot/test/ca.crt".to_string());
72 | let cleanup_result = super::cleanup(beiboot_name);
73 | assert!(cleanup_result.is_ok());
74 | }
75 |
76 | #[tokio::test]
77 | async fn test_check_docker_engine() {
78 | let result = super::check_docker_engine().await;
79 | assert!(result.is_ok());
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src-tauri/tauri.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../node_modules/@tauri-apps/cli/schema.json",
3 | "build": {
4 | "beforeBuildCommand": "npm run build",
5 | "beforeDevCommand": "npm run dev",
6 | "devPath": "http://localhost:5173",
7 | "distDir": "../dist"
8 | },
9 | "package": {
10 | "productName": "Getdeck-Desktop",
11 | "version": "0.1.2"
12 | },
13 | "tauri": {
14 | "allowlist": {
15 | "shell": {
16 | "open": true
17 | }
18 | },
19 | "updater": {
20 | "active": true,
21 | "endpoints": [
22 | "https://raw.githubusercontent.com/Getdeck/Getdeck-Desktop/main/updater.json"
23 | ],
24 | "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDdCRjA3QjMyOTBEQTREMTMKUldRVFRkcVFNbnZ3ZTIrTmJVT1NQL0Ftdi9pRnBQcW5aV1locEdLU2RjY0Z2K1VvMWZqL3pUNHIK"
25 | },
26 | "bundle": {
27 | "active": true,
28 | "category": "DeveloperTool",
29 | "copyright": "",
30 | "deb": {
31 | "depends": []
32 | },
33 | "icon": [
34 | "icons/32x32.png",
35 | "icons/128x128.png",
36 | "icons/128x128@2x.png",
37 | "icons/icon.icns",
38 | "icons/icon.ico"
39 | ],
40 | "identifier": "dev.getdeck.desktop",
41 | "longDescription": "",
42 | "macOS": {
43 | "entitlements": null,
44 | "exceptionDomain": "",
45 | "frameworks": [],
46 | "providerShortName": null,
47 | "signingIdentity": null
48 | },
49 | "resources": [],
50 | "shortDescription": "",
51 | "targets": "all",
52 | "windows": {
53 | "certificateThumbprint": null,
54 | "digestAlgorithm": "sha256",
55 | "timestampUrl": ""
56 | }
57 | },
58 | "security": {
59 | "csp": null,
60 | "dangerousRemoteDomainIpcAccess": [
61 | {
62 | "domain": "getdeck.dev",
63 | "windows": [
64 | "Getdeck Desktop"
65 | ]
66 | }
67 | ]
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src-tauri/tests/connectors.rs:
--------------------------------------------------------------------------------
1 | #[cfg(test)]
2 | mod ghostunnel_docker_tests {
3 | use beiboot_desktop::connection::{get_connector_context, PortMapping, TLSFiles};
4 |
5 | //FIXME: This test fails after the first run because of a container name conflict.
6 | #[test]
7 | fn test_a_connect_ghostunnel_docker() {
8 | let connector = get_connector_context("test", "GhostunnelDocker");
9 |
10 | let ports = vec![PortMapping {
11 | target: 6443,
12 | endpoint: "34.88.204.180:31477",
13 | }, PortMapping {
14 | target: 8080,
15 | endpoint: "34.88.204.180.31477"
16 | }];
17 | let ca_cert_path = shellexpand::tilde("~/.getdeck/test/mtls/ca.crt").into_owned();
18 | let client_cert_path = shellexpand::tilde("~/.getdeck/test/mtls/client.crt").into_owned();
19 | let client_key_path = shellexpand::tilde("~/.getdeck/test/mtls/client.key").into_owned();
20 |
21 | let tls = TLSFiles {
22 | ca_cert_path: &ca_cert_path,
23 | client_cert_path: &client_cert_path,
24 | client_key_path: &client_key_path,
25 | };
26 |
27 | let res = match connector.connect(&ports, &tls) {
28 | Ok(_) => 0,
29 | Err(why) => {
30 | println!("{}", why);
31 | 1
32 | }
33 | };
34 | assert_eq!(0, res)
35 | }
36 |
37 | #[test]
38 | fn test_c_disconnect_ghostunnel_docker() {
39 | let connector = get_connector_context("test", "GhostunnelDocker");
40 | let res = match connector.disconnect() {
41 | Ok(_) => 0,
42 | Err(why) => {
43 | println!("{}", why);
44 | 1
45 | }
46 | };
47 | assert_eq!(0, res)
48 | }
49 | #[test]
50 | fn test_b_check_running() {
51 | let connector = get_connector_context("test", "GhostunnelDocker");
52 | let _res = match connector.check_running() {
53 | Ok(container_summary) => {
54 | println!("{:?}", container_summary);
55 | 0
56 | },
57 | Err(why) => {
58 | println!("{}", why);
59 | 1
60 | }
61 | };
62 | }
63 | #[test]
64 | fn test_d_check_not_running() {
65 | let connector = get_connector_context("test", "GhostunnelDocker");
66 | let _res = match connector.check_running() {
67 | Ok(container_summary) => {
68 | println!("{:?}", container_summary);
69 | 0
70 | },
71 | Err(why) => {
72 | println!("{}", why);
73 | 1
74 | }
75 | };
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/src/auth/keycloak.ts:
--------------------------------------------------------------------------------
1 | import Keycloak from 'keycloak-js';
2 | import axios from 'axios';
3 | import { Store } from "tauri-plugin-store-api";
4 | import { OpenAPI } from "beiboot-api-client";
5 |
6 | import router from "@/router";
7 | import { useAppStore } from "@/store/app";
8 | import { open } from "@tauri-apps/api/shell";
9 | import { listen } from "@tauri-apps/api/event";
10 | import { startOAuthServer } from '@/beibootctl';
11 |
12 | export interface Token {
13 | token: string;
14 | refreshToken: string;
15 | }
16 |
17 | let initOptions = {
18 | url: 'https://login.getdeck.dev/auth/',
19 | realm: 'Getdeck',
20 | clientId: 'beiboot-api'
21 | }
22 |
23 | const openLoginBrowser = async (keycloak: Keycloak.KeycloakInstance) => {
24 | const port = await startOAuthServer();
25 | const redirectUri = `http://localhost:${port}`;
26 | keycloak.init({
27 | checkLoginIframe: false,
28 | });
29 | keycloak.login({
30 | redirectUri: redirectUri
31 | });
32 | console.log("opening...")
33 |
34 | }
35 |
36 | export async function getInitialToken(keycloak: Keycloak.KeycloakInstance) {
37 | const store = new Store(".settings.dat");
38 | listen('redirect_uri', (data) => {
39 | console.log(data.payload);
40 | });
41 | openLoginBrowser(keycloak);
42 | }
43 |
44 | export async function initKeycloak() {
45 | let initOptions = {
46 | url: 'https://login.getdeck.dev/auth/',
47 | realm: 'Getdeck',
48 | clientId: 'beiboot-api'
49 | }
50 | const appStore = useAppStore();
51 | const store = new Store(".settings2.dat");
52 |
53 | const storeToken = await store.get("token");
54 | const storeRefreshToken = await store.get("refreshToken");
55 |
56 | console.log(storeToken)
57 | console.log(storeRefreshToken)
58 |
59 | const keycloak = new Keycloak(initOptions);
60 | keycloak.init({
61 | checkLoginIframe: false,
62 | onLoad: 'check-sso',
63 | enableLogging: true,
64 | // @ts-ignore
65 | token: storeToken?.value,
66 | // @ts-ignore
67 | refreshToken: storeRefreshToken?.value
68 | }).then(async (authenticated) => {
69 | console.log(authenticated)
70 | if (authenticated) {
71 | store.set("token", {value: keycloak.token})
72 | store.set("refreshToken", {value: keycloak.refreshToken})
73 | OpenAPI.TOKEN = keycloak.token;
74 | keycloak.loadUserProfile().then((profile) => {
75 | appStore.auth.authenticated = true;
76 | appStore.auth.user = profile.firstName || "";
77 | appStore.auth.token = keycloak.token || "";
78 | appStore.auth.keycloak = keycloak;
79 | store.set("user", { value: profile });
80 | router.push("/clusters");
81 | });
82 | await store.save();
83 | } else {
84 | store.clear();
85 | store.save();
86 | getInitialToken(keycloak);
87 | }
88 | }).catch((err) => {
89 | console.log(err)
90 | })
91 | setInterval(() => {
92 | keycloak.updateToken(0).then((refreshed) => {
93 | console.debug(refreshed)
94 | if (refreshed) {
95 | console.debug('Token refreshed' + refreshed);
96 | OpenAPI.TOKEN = keycloak.token;
97 | } else {
98 | console.debug('Token not refreshed, still valid.');
99 | }
100 | }).catch(() => {
101 | console.debug('Failed to refresh token');
102 | });
103 | }, 6000)
104 | }
105 |
--------------------------------------------------------------------------------
/src/beibootctl.d.ts:
--------------------------------------------------------------------------------
1 | export declare function getVersion(): Promise;
2 | export declare function createCluster(name: string): Promise;
3 | export declare function deleteCluster(name: string): Promise;
4 | export declare function listCluster(): Promise;
5 |
--------------------------------------------------------------------------------
/src/beibootctl.ts:
--------------------------------------------------------------------------------
1 | import { Command } from "@tauri-apps/api/shell";
2 | import { invoke } from "@tauri-apps/api/tauri";
3 | import { useAppStore } from "./store/app";
4 |
5 | export async function getVersion() {
6 | return "1.0.0";
7 | }
8 |
9 | export async function createCluster(name: string) {
10 | console.log("Ich laufe");
11 | console.log(name);
12 |
13 | return "Created cluster " + name;
14 | }
15 |
16 | export async function deleteCluster(name: string) {
17 | return "Deleted cluster " + name;
18 | }
19 |
20 | export async function listCluster() {
21 | const output = "No Beiboots";
22 | console.log(output);
23 | }
24 |
25 | export async function connectCluster(name: string, portMapping: any, ca: string, clCert: string, clKey: string) {
26 | let res = await invoke("connect_beiboot_ghostunnel", {
27 | beibootName: name,
28 | ports: portMapping,
29 | ca,
30 | clCert,
31 | clKey
32 | })
33 | return res
34 | }
35 |
36 | export async function writeKubeconfig(name: string, kubeconfig: string): Promise {
37 | let res: string = await invoke("write_kubeconfig", {
38 | beibootName: name,
39 | kubeconfig
40 | })
41 | return res
42 | }
43 |
44 | export async function disconnectCluster(name: string) {
45 | let res = await invoke("disconnect_beiboot_ghostunnel", { beibootName: name })
46 | return res
47 | }
48 |
49 | export async function startOAuthServer() {
50 | let res = await invoke("start_server", {})
51 | return res
52 | }
53 |
54 | export async function checkRunningConnects() {
55 | const appStore = useAppStore();
56 |
57 | try {
58 | let res: string[] = await invoke("check_running_connects", {})
59 | if (res.length > 0) {
60 | appStore.connection.clusterName = res[0]
61 | appStore.connection.connected = true;
62 | } else {
63 | appStore.connection.clusterName = ""
64 | appStore.connection.connected = false;
65 | }
66 | return res
67 | } catch {
68 | appStore.connection.clusterName = ""
69 | appStore.connection.connected = false;
70 | console.log("no docker client here.")
71 | return "Docker Client unresponsive."
72 | }
73 | }
74 | export async function checkDockerEngine() {
75 | let res: string = await invoke("check_docker_engine", {})
76 | return res
77 | }
78 |
--------------------------------------------------------------------------------
/src/components/ClusterTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Name
6 | State
7 | Sunset
8 | Lifetime/Timeout
9 | Actions
10 |
11 |
12 |
13 |
14 |
15 | {{ cluster.name }}
16 |
17 |
18 |
19 |
20 |
21 | {{ cluster.state }}
22 |
23 |
24 | {{ getClusterSunset(cluster.sunset) }}
25 | {{ cluster.max_lifetime.value }} / {{ cluster.max_session_timeout.value }}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | No clusters to list. Please create one first.
52 |
53 |
54 |
55 |
56 |
199 |
--------------------------------------------------------------------------------
/src/components/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Welcome to Beiboot Desktop
4 |
5 |
6 |
7 |
13 |
--------------------------------------------------------------------------------
/src/layouts/default/Default.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{ item.title }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
49 | Hi, {{ appStore.auth.user }}
50 |
51 |
52 |
53 |
54 |
55 | Logout
56 |
57 |
58 |
59 | Not logged in
60 |
61 | {{ appStore.docker ? "Engine: Docker" : "Docker Engine not running" }}
62 |
63 |
64 | Connected to {{ appStore.connection.clusterName }}
65 | Not connected
66 |
67 |
68 |
69 | Disconnect
70 |
71 |
72 | Copy Kubeconfig
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
122 |
--------------------------------------------------------------------------------
/src/layouts/default/NoSidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
11 |
--------------------------------------------------------------------------------
/src/main.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * main.ts
3 | *
4 | * Bootstraps Vuetify and other plugins then mounts the App`
5 | */
6 | export {};
7 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * main.ts
3 | *
4 | * Bootstraps Vuetify and other plugins then mounts the App`
5 | */
6 |
7 | // Components
8 | import App from './App.vue'
9 |
10 | // Composables
11 | import { createApp } from 'vue'
12 |
13 | // Plugins
14 | import { registerPlugins } from '@/plugins'
15 |
16 | import router from '@/router'
17 | import { OpenAPI } from "beiboot-api-client";
18 | import { initKeycloak } from '@/auth/keycloak';
19 | import * as Sentry from "@sentry/vue";
20 | import { invoke } from '@tauri-apps/api/tauri';
21 | import { useAppStore } from './store/app';
22 | import { checkDockerEngine } from './beibootctl';
23 |
24 | const app = createApp(App)
25 |
26 | registerPlugins(app)
27 |
28 | OpenAPI.BASE = "https://api.getdeck.dev"
29 |
30 |
31 | if (process.env.NODE_ENV !== 'dev') {
32 | Sentry.init({
33 | app,
34 | dsn: "https://dd838e60a73d4902aa336ca38093e530@o146863.ingest.sentry.io/4505356797018112",
35 | integrations: [
36 | new Sentry.BrowserTracing({
37 | tracePropagationTargets: ["localhost", "tauri.localhost"],
38 | routingInstrumentation: Sentry.vueRouterInstrumentation(router),
39 | }),
40 | new Sentry.Replay(),
41 | ],
42 | // Performance Monitoring
43 | tracesSampleRate: 0.1,
44 | // Session Replay
45 | replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
46 | replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
47 | });
48 | }
49 |
50 | app.mount('#app')
51 |
52 | if (process.env.NODE_ENV !== 'debug') {
53 | document.addEventListener('contextmenu', event => event.preventDefault());
54 | }
55 |
56 | const appStore = useAppStore();
57 |
58 | checkDockerEngine().then((res) => {
59 | console.log("docker engine: ", res);
60 | appStore.docker = true;
61 | }).catch((err) => {
62 | console.log("docker engine: ", err);
63 | appStore.docker = false;
64 | })
65 |
66 | initKeycloak();
67 |
--------------------------------------------------------------------------------
/src/plugins/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugins/index.ts
3 | *
4 | * Automatically included in `./src/main.ts`
5 | */
6 | import type { App } from 'vue';
7 | export declare function registerPlugins(app: App): void;
8 |
--------------------------------------------------------------------------------
/src/plugins/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugins/index.ts
3 | *
4 | * Automatically included in `./src/main.ts`
5 | */
6 |
7 | // Plugins
8 | import { loadFonts } from './webfontloader'
9 | import vuetify from './vuetify'
10 | import pinia from '../store'
11 | import router from '../router'
12 |
13 | // Types
14 | import type { App } from 'vue'
15 |
16 | export function registerPlugins (app: App) {
17 | loadFonts()
18 | app
19 | .use(vuetify)
20 | .use(router)
21 | .use(pinia)
22 | }
23 |
--------------------------------------------------------------------------------
/src/plugins/vuetify.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugins/vuetify.ts
3 | *
4 | * Framework documentation: https://vuetifyjs.com`
5 | */
6 | ///
7 | import '@mdi/font/css/materialdesignicons.css';
8 | import 'vuetify/styles';
9 | declare const _default: {
10 | install: (app: import("vue").App) => void;
11 | defaults: import("vue").Ref;
12 | display: import("vuetify").DisplayInstance;
13 | theme: import("vuetify").ThemeInstance & {
14 | install: (app: import("vue").App) => void;
15 | };
16 | icons: Record;
17 | locale: {
18 | isRtl: import("vue").Ref;
19 | rtl: import("vue").Ref>;
20 | rtlClasses: import("vue").Ref;
21 | name: string;
22 | messages: import("vue").Ref;
23 | current: import("vue").Ref;
24 | fallback: import("vue").Ref;
25 | t: (key: string, ...params: unknown[]) => string;
26 | n: (value: number) => string;
27 | provide: (props: import("vuetify").LocaleOptions) => import("vuetify").LocaleInstance;
28 | };
29 | };
30 | export default _default;
31 |
--------------------------------------------------------------------------------
/src/plugins/vuetify.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugins/vuetify.ts
3 | *
4 | * Framework documentation: https://vuetifyjs.com`
5 | */
6 |
7 | // Styles
8 | import '@mdi/font/css/materialdesignicons.css'
9 | import 'vuetify/styles'
10 |
11 | // Composables
12 | import { createVuetify } from 'vuetify'
13 |
14 | // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
15 | export default createVuetify({
16 | defaults: {
17 | global: {
18 | ripple: false,
19 | },
20 | VTooltip: {
21 | location: "bottom",
22 | offset: "2"
23 | },
24 | VTextField: {
25 | variant: "outlined",
26 | density: "compact"
27 | }
28 | },
29 | theme: {
30 | themes: {
31 | light: {
32 | colors: {
33 | "on-background": "#303846",
34 | primary: "#ff1654",
35 | secondary: "#303846",
36 | 'secondary-2': "#303846"
37 | },
38 | },
39 | },
40 | },
41 | })
42 |
--------------------------------------------------------------------------------
/src/plugins/webfontloader.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugins/webfontloader.ts
3 | *
4 | * webfontloader documentation: https://github.com/typekit/webfontloader
5 | */
6 | export declare function loadFonts(): Promise;
7 |
--------------------------------------------------------------------------------
/src/plugins/webfontloader.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugins/webfontloader.ts
3 | *
4 | * webfontloader documentation: https://github.com/typekit/webfontloader
5 | */
6 |
7 | export async function loadFonts () {
8 | const webFontLoader = await import(/* webpackChunkName: "webfontloader" */'webfontloader')
9 |
10 | webFontLoader.load({
11 | google: {
12 | families: ['Roboto:100,300,400,500,700,900&display=swap'],
13 | },
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/src/router/index.d.ts:
--------------------------------------------------------------------------------
1 | declare const router: import("vue-router").Router;
2 | export default router;
3 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | // Composables
2 | import { createRouter, createWebHistory } from 'vue-router';
3 | const routes = [
4 | {
5 | path: '/',
6 | component: () => import('@/layouts/default/Default.vue'),
7 | children: [
8 | {
9 | path: '/home',
10 | name: 'Home',
11 | // route level code-splitting
12 | // this generates a separate chunk (about.[hash].js) for this route
13 | // which is lazy-loaded when the route is visited.
14 | component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue'),
15 | },
16 | {
17 | path: '/clusters',
18 | name: 'Clusters',
19 | // route level code-splitting
20 | // this generates a separate chunk (about.[hash].js) for this route
21 | // which is lazy-loaded when the route is visited.
22 | component: () => import(/* webpackChunkName: "home" */ '@/views/Clusters.vue'),
23 | },
24 | {
25 | path: '/clusters/create',
26 | name: 'Cluster Create',
27 | // route level code-splitting
28 | // this generates a separate chunk (about.[hash].js) for this route
29 | // which is lazy-loaded when the route is visited.
30 | component: () => import(/* webpackChunkName: "home" */ '@/views/ClusterCreate.vue'),
31 | },
32 | ],
33 | },
34 | {
35 | path: '/login',
36 | component: () => import('@/layouts/default/NoSidebar.vue'),
37 | children: [
38 |
39 | {
40 | path: '',
41 | name: 'Login',
42 | component: () => import('@/views/Login.vue'),
43 | },
44 | ]
45 | }
46 | ];
47 | const router = createRouter({
48 | history: createWebHistory(),
49 | routes,
50 | });
51 | export default router;
52 |
--------------------------------------------------------------------------------
/src/store/app.d.ts:
--------------------------------------------------------------------------------
1 | export declare const useAppStore: import("pinia").StoreDefinition<"app", {}, {}, {}>;
2 |
--------------------------------------------------------------------------------
/src/store/app.ts:
--------------------------------------------------------------------------------
1 | // Utilities
2 | import Keycloak from 'keycloak-js';
3 | import { defineStore } from 'pinia'
4 | import { Store } from 'tauri-plugin-store-api';
5 |
6 | export const useAppStore = defineStore('appStore', {
7 | state: () => {
8 | return {
9 | connection: {
10 | clusterName: "",
11 | clusterId: "",
12 | kubeconfigPath: "",
13 | connected: false,
14 | },
15 | docker: false,
16 | auth: {
17 | authenticated: false,
18 | user: "",
19 | keycloak: null as Keycloak | null,
20 | token: ""
21 | }
22 | }
23 | },
24 | actions: {
25 | logout() {
26 | const store = new Store(".settings.dat");
27 | store.set("token", "");
28 | store.clear();
29 | store.save();
30 | this.auth.authenticated = false;
31 | this.auth.user = "";
32 | if (this.auth.keycloak) {
33 | this.auth.keycloak.logout({})
34 | }
35 | }
36 | }
37 | })
38 |
--------------------------------------------------------------------------------
/src/store/index.d.ts:
--------------------------------------------------------------------------------
1 | declare const _default: import("pinia").Pinia;
2 | export default _default;
3 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | // Utilities
2 | import { createPinia } from 'pinia'
3 |
4 | export default createPinia()
5 |
--------------------------------------------------------------------------------
/src/styles/settings.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * src/styles/settings.scss
3 | *
4 | * Configures SASS variables and Vuetify overwrites
5 | */
6 |
7 | // https://next.vuetifyjs.com/features/sass-variables/`
8 | @use 'vuetify/settings' with (
9 | $button-text-transform: none,
10 | $list-item-icon-margin-end: 15px,
11 | $tooltip-background-color: rgba(var(--v-theme-surface-variant), .9),
12 | $text-field-border-radius: 0,
13 | );
14 | .v-theme--light {
15 | --v-medium-emphasis-opacity: 1;
16 | }
17 |
18 | h1, h2, h3, h4, h5, h6 {
19 | font-weight: 500;
20 | }
21 |
22 | .router-link-btn {
23 | color: currentcolor;
24 | text-decoration: none;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/src/views/ClusterCreate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Create Cluster
5 |
6 |
7 |
8 |
9 |
18 |
19 |
20 |
29 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 | Ports
47 |
48 |
49 | Create
50 |
51 |
52 |
53 |
56 | {{ snackbarInner }}
57 |
58 |
59 |
64 | Close
65 |
66 |
67 |
68 |
69 |
70 |
155 |
156 |
--------------------------------------------------------------------------------
/src/views/Clusters.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Clusters
6 |
7 |
8 |
9 |
10 | Create Cluster
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 | {{ snackbarInner }}
21 |
22 |
23 |
28 | Close
29 |
30 |
31 |
32 |
33 |
34 |
46 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/src/views/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Login
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 | Login
16 |
17 |
18 |
19 |
20 |
39 |
40 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import type { DefineComponent } from 'vue'
5 | const component: DefineComponent<{}, {}, any>
6 | export default component
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "esnext",
5 | "useDefineForClassFields": true,
6 | "allowSyntheticDefaultImports": true,
7 | "composite": true,
8 | "module": "esnext",
9 | "moduleResolution": "node",
10 | "strict": true,
11 | "jsx": "preserve",
12 | "sourceMap": false,
13 | "resolveJsonModule": true,
14 | "esModuleInterop": true,
15 | "lib": ["esnext", "dom"],
16 | "outDir": "dist",
17 | "types": [
18 | "node",
19 | "vuetify"
20 | ],
21 | "paths": {
22 | "@/*": ["src/*"]
23 | },
24 | },
25 | "include": [
26 | "src/**/*.ts",
27 | "src/**/*.d.ts",
28 | "src/**/*.tsx",
29 | "src/**/*.vue",
30 | "vite.config.ts"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.tsbuildinfo:
--------------------------------------------------------------------------------
1 | {"program":{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/@tauri-apps/api/shell-cbf4da8b.d.ts","./node_modules/@tauri-apps/api/shell.d.ts","./src/beibootctl.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@vue/shared/dist/shared.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/source-map/source-map.d.ts","./node_modules/@vue/compiler-core/dist/compiler-core.d.ts","./node_modules/@vue/compiler-dom/dist/compiler-dom.d.ts","./node_modules/@vue/reactivity/dist/reactivity.d.ts","./node_modules/@vue/runtime-core/dist/runtime-core.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts","./node_modules/vue/dist/vue.d.ts","./node_modules/@types/webfontloader/index.d.ts","./src/plugins/webfontloader.ts","./node_modules/vue-router/dist/vue-router.d.ts","./node_modules/vuetify/lib/components/index.d.ts","./node_modules/vuetify/lib/index.d.ts","./src/plugins/vuetify.ts","./node_modules/pinia/node_modules/vue-demi/lib/index.d.ts","./node_modules/pinia/dist/pinia.d.ts","./src/store/index.ts","./src/router/index.ts","./src/plugins/index.ts","./src/main.ts","./node_modules/vite/types/hmrpayload.d.ts","./node_modules/vite/types/customevent.d.ts","./node_modules/vite/types/hot.d.ts","./node_modules/vite/types/importglob.d.ts","./node_modules/vite/types/importmeta.d.ts","./node_modules/vite/client.d.ts","./src/vite-env.d.ts","./src/store/app.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/dom-events.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/globals.global.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/esbuild/lib/main.d.ts","./node_modules/rollup/dist/rollup.d.ts","./node_modules/source-map-js/source-map.d.ts","./node_modules/postcss/lib/comment.d.ts","./node_modules/postcss/lib/at-rule.d.ts","./node_modules/postcss/lib/rule.d.ts","./node_modules/postcss/lib/container.d.ts","./node_modules/postcss/lib/declaration.d.ts","./node_modules/postcss/lib/previous-map.d.ts","./node_modules/postcss/lib/input.d.ts","./node_modules/postcss/lib/css-syntax-error.d.ts","./node_modules/postcss/lib/warning.d.ts","./node_modules/postcss/lib/document.d.ts","./node_modules/postcss/lib/root.d.ts","./node_modules/postcss/lib/lazy-result.d.ts","./node_modules/postcss/lib/no-work-result.d.ts","./node_modules/postcss/lib/processor.d.ts","./node_modules/postcss/lib/result.d.ts","./node_modules/postcss/lib/node.d.ts","./node_modules/postcss/lib/list.d.ts","./node_modules/postcss/lib/postcss.d.ts","./node_modules/vite/dist/node/index.d.ts","./node_modules/magic-string/index.d.ts","./node_modules/@vue/reactivity-transform/dist/reactivity-transform.d.ts","./node_modules/@vue/compiler-sfc/dist/compiler-sfc.d.ts","./node_modules/vue/compiler-sfc/index.d.ts","./node_modules/@vitejs/plugin-vue/dist/index.d.ts","./node_modules/@vuetify/loader-shared/dist/imports/generateimports.d.ts","./node_modules/@vuetify/loader-shared/dist/styles/writestyles.d.ts","./node_modules/@vuetify/loader-shared/dist/index.d.ts","./node_modules/vite-plugin-vuetify/dist/index.d.ts","./vite.config.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c",{"version":"3aafcb693fe5b5c3bd277bd4c3a617b53db474fe498fc5df067c5603b1eebde7","affectsGlobalScope":true},{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true},"893a6d115d83d9c6ea6864a25862a73b8172ee3856366c2f3a026e038478592f","28df0e4d4e5882cc6b0f258f324eccd372e76adcfb3df6a8bdc588ea946b1223",{"version":"515cb86dc06635a6da9e0cae293335fcf8d40390683953a79829f9f91ec89580","signature":"085522f2914d5bb3998b1d00393b2360271d3d11eb660ba20bf15441b8a114c1"},"f4617bbd5403ec5b058db53b242dcb1421952e2652bd5c80abf6a1c4ea5656d6","ae746a298a6f28df1327022f30c25f4e6f3b685f76412d242a4e7dc9c1864055","230d323ef7f2ffadfc0ceae494492c4d2faa2b4eaec07a4b71424d084b97ebb8","2887592574fcdfd087647c539dcb0fbe5af2521270dad4a37f9d17c16190d579","d6f2eb888c21f8714116684379d28ed90b97e8330134a07fdf245681a8df22d2","712fc12e4021b820f7853112d09096e4c5a0f4475915d49f11e076c86fc97f8b","4a7ee458d2b28030d4d3f927c04d84dea97ed6868a50cc08bd3992bd3df37d17",{"version":"021e8b48479ad58e3320f931070c9d18a9497b140e97907992a2296f8a1e123f","affectsGlobalScope":true},"c609b66caa6f5b80a9166ce7505730b398ae7c0eddc0c1feed28a17814cf8609",{"version":"9e1df80422a8188330971a363f767d19ca53804487eb47fc78acebb6a9e75af6","affectsGlobalScope":true},"f79e452d452ab10eac3f96b3b3930cf78ec6c9037c4cd9a062dae61744f634fc","f9391b2ae78058a9fae3280d650e4faad27c24bd2dd4e6fb9f4ff16a61a21f91",{"version":"2787126681c1f3c9499513c33f0d52399311841868d2ba5462a6eab7330dae3b","signature":"f8dd311f5e65a8f5efe4e76653af8eb481e2d2c248057c3f5b16a25867534e65"},"f907b85bf67c02e243690844227315d8f3be4da810fd5e5274737c66e1f2efa6","a9fe220c14fe2f0d5f8b18c839796d2b5915f3077b3bfa3d6d5bf066d164a3a4",{"version":"99bad98e5b9a61da13557aad9121e423a71cab28686d9c0a979413bbef00c0f3","affectsGlobalScope":true},{"version":"eebfa5888ebfdbd1053f9f918e5b0ef200d8301ac0e6b19dc318fb0cdddbe541","signature":"93ee1b9963e1e04b6ac4cf23143cf2538031b552abb2b9f150feebd37247cc26"},"52f5c39e78a90c1d8ed7db18f39d890b2e8464a3f44d4233617893f6648e317d","a5a9d9140415b4563b8fbdb9abec882accc12b5ad26c9071041331a4b275f29a",{"version":"85cc9fdfca89085a65924923cf92b3cd56fde3978df028891dde47913b106eb1","signature":"3f06fbd98cdd8815ad6cf5210ede4d4adec9f26259fb4bf0f01b790b9b1b2b08"},{"version":"dcb9e01a9d9a082e04237a0a4798b3dd52dde76b89d0ca7368a98865d621256a","signature":"2484eadb07b268ddd6b1ca48525126faacaabfe37fb08d37f1fd514919bb681b"},{"version":"2be44db98f7ce25ae1513ab29d5169f7a0969c5a04d5fbdcb3a5922be1adb444","signature":"0e0947bc071a3dc1414ab99304190e1174365e86e90aad223091e9c07460c393"},{"version":"fbeff035b4daef70f40c47ef5d430d07c55c28108bc0e31ea1348c3df6bbefcf","signature":"6a4cc82f07a76e2c185ce63e1968e3f381b16acbdb0c853db9c4faa58355e12e"},"bcb6ea18f23dae2c48459d7b86d3adccd6898f824fcbf9da08b935f559896580","08121bfe3615014d8f667e5069070aefc21dae4301036bee0bbfddafbf90acb5","bd668758155705240608e67d5664e5a34f2ec38724c95272dc134ce3c150dfe1","3cead9ca29f12a4887d2000124caaabe24b8146578b8630890001e7a9cdaa735",{"version":"df93bb67d5ae7be3d599323de42e12cb8da59f0b490c3186ae91d493632b5e36","affectsGlobalScope":true},{"version":"3db18a74a8bd232014ae25149007e17fabe41993a13ff02d2e3e390933344b4e","affectsGlobalScope":true},"cb3a8a70a87f0b1872244cd0bbe5bb5ddd602d820b7766a4d515b04eab8c40c7",{"version":"a1f3faba121854904b8d040f26cdbc60d9f2e8add0b756e3e9937e5f94424564","signature":"b2b4eaf580951cc3905d32c484229e33bdedb76db366857b46b0183bacee718a"},"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a",{"version":"ca72190df0eb9b09d4b600821c8c7b6c9747b75a1c700c4d57dc0bb72abc074c","affectsGlobalScope":true},"21a167fec8f933752fb8157f06d28fab6817af3ad9b0bdb1908a10762391eab9",{"version":"bb65c6267c5d6676be61acbf6604cf0a4555ac4b505df58ac15c831fcbff4e3e","affectsGlobalScope":true},"374ca798f244e464346f14301dc2a8b4b111af1a83b49fffef5906c338a1f922","5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713",{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true},"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","dab86d9604fe40854ef3c0a6f9e8948873dc3509213418e5e457f410fd11200f","bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","489532ff54b714f0e0939947a1c560e516d3ae93d51d639ab02e907a0e950114","f30bb836526d930a74593f7b0f5c1c46d10856415a8f69e5e2fc3db80371e362","14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea",{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true},{"version":"816ad2e607a96de5bcac7d437f843f5afd8957f1fa5eefa6bba8e4ed7ca8fd84","affectsGlobalScope":true},"cec36af22f514322f870e81d30675c78df82ae8bf4863f5fd4e4424c040c678d","d903fafe96674bc0b2ac38a5be4a8fc07b14c2548d1cdb165a80ea24c44c0c54","5eec82ac21f84d83586c59a16b9b8502d34505d1393393556682fe7e7fde9ef2","04eb6578a588d6a46f50299b55f30e3a04ef27d0c5a46c57d8fcc211cd530faa","8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58",{"version":"e8b18c6385ff784228a6f369694fcf1a6b475355ba89090a88de13587a9391d5","affectsGlobalScope":true},"d076fede3cb042e7b13fc29442aaa03a57806bc51e2b26a67a01fbc66a7c0c12","7c013aa892414a7fdcfd861ae524a668eaa3ede8c7c0acafaf611948122c8d93","b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30",{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true},{"version":"b3624aed92dab6da8484280d3cb3e2f4130ec3f4ef3f8201c95144ae9e898bb6","affectsGlobalScope":true},"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","fd93cee2621ff42dabe57b7be402783fd1aa69ece755bcba1e0290547ae60513","1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","223c37f62ce09a3d99e77498acdee7b2705a4ae14552fbdb4093600cd9164f3f",{"version":"970a90f76d4d219ad60819d61f5994514087ba94c985647a3474a5a3d12714ed","affectsGlobalScope":true},"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","4c8525f256873c7ba3135338c647eaf0ca7115a1a2805ae2d0056629461186ce","3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2",{"version":"f0900cd5d00fe1263ff41201fb8073dbeb984397e4af3b8002a5c207a30bdc33","affectsGlobalScope":true},{"version":"4c50342e1b65d3bee2ed4ab18f84842d5724ad11083bd666d8705dc7a6079d80","affectsGlobalScope":true},"06d7c42d256f0ce6afe1b2b6cfbc97ab391f29dadb00dd0ae8e8f23f5bc916c3","ec4bd1b200670fb567920db572d6701ed42a9641d09c4ff6869768c8f81b404c","e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa",{"version":"da26af7362f53d122283bc69fed862b9a9fe27e01bc6a69d1d682e0e5a4df3e6","affectsGlobalScope":true},"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e",{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true},"8dbe725f8d237e70310977afcfa011629804d101ebaa0266cafda6b61ad72236","6cb4fc48f1299d40a9d84282f691e722dfea2d53c92721861166c713928e6f93","eced89c8bebaf21ffa42987fcb24bc4f753db4761b8e90031b605508ed6eef5f","858d0d831826c6eb563df02f7db71c90e26deadd0938652096bea3cc14899700","d1c89db652113258e4ba4bbdf5cc7a2a3a600403d4d864a2087b95186253cd5b","11a90d2cb2eaf7fdf931a63b58279e8161f1477a1bd1e914ae026c1bbf9afed3","af18e30f3ba06e9870b61dfa4a109215caabdaa337590c51b4a044a9f338ce96","ace603f7b60599f2dcdbd71c07137b60a747dd33be540f4a294b890f9e0b89dc","7658fbdd425c656fb1849b44932ae7431e8c3198d22c65ce1490deb582743b52","7786c75c1b46e93b33c63dccf689143a5f47ff451a6b3bd9b10e4801cdeadcc2","615b7264db151461b896cd79719414d63f7b2b2100b275828e53cab95a356e2f","31491a01ed7466e0b3b0ef8407f2524683055eceb955b1d5ccf7096129468b39","f4b12f7dde4fc0e386648318481bdcfe861b566be246bebf0e8a11ebd909adf9","e8966f7c424780bb0b9d411ebe13eda8555ca15aa675603316c2952bc027b0e3","df0e5f3c4a518111d160cf3bebc9a3ac7d39c6e3bfb7a21d43c304896c3015e2","df4e2f161f74870708c2cc5e1036a6405b878496408fda1ee50d5b10e50d6601","bf791da347fb1c0ffc1e2fcd35867e64bb8355270ae26278198c521bdcf94569","e0e0e3c068e145fbb322120979299ff130ffdd39f0dcd0d5aeaa9f3f8a0d01d9","fde91356172e35b9ea68bbdf33721f7c80307a4ce65b82105eac800e9e744995","9bd5e5a4a1e66b35efe3c48ddac1116537ef86e041717f3a9b9f1e060c74efa6","d7e4a5f4ccfb749c3033fafc233073b4d1dcca0249785186c589602a81f9d86f","68161b6f3004fc10f8bb47a4986cef13c3b0728fb1ca3e1dc7316227d09b2c8d","fe4a4ed3b2acff61e22d55bd43456809679ed1887b180d42db000939fdd2f2fd","dd6a4b050f1016c0318291b42c98ab068e07e208b1ae8e4e27167c2b8007406f","4a569e0f6b06bbfd08cbf394f080226608892a9266e3df0b796e611a6b6f5b48","241e274f2e15e8b9d3c8f4187dec9b4f61b4439b5753f10de71b33ca6d4244d8","3feec212c0aeb91e5a6e62caaf9f128954590210f8c302910ea377c088f6b61a","85a093a118d4f2267af7d2aee23444685c05c5d02aaa4482fa4c77317767c8f8","c0ec47ff5e245830967be282a58e34bde9b46a5fb8cb521921558d13583b0746","66e756d6327409624e4e67abeb6f47704e9fd167f0af061b14b2770a55b662f1","98f0142f3b31b14979ba4164ac073ea9e4ec1c4b226b0a48b80bd0081d24f88a","6feb067eed5e88f784c69125ddb10759d73cc710ea0ef1464684b0ac495d4b45",{"version":"aed2c405c9847d860d47e1ee083a8363aa8ee9aa7a1dc37681337f9cf570126d","signature":"ec7ffb6cebb230fb92af9b7fd96b4a9fd9df8001305603bbef1770a77dad9a57"}],"options":{"allowSyntheticDefaultImports":true,"composite":true,"esModuleInterop":true,"jsx":1,"module":99,"sourceMap":false,"strict":true,"target":99,"useDefineForClassFields":true},"fileIdsList":[[59,136],[136],[56,136],[90,136],[93,136],[94,99,127,136],[95,106,107,114,124,135,136],[95,96,106,114,136],[97,136],[98,99,107,115,136],[99,124,132,136],[100,102,106,114,136],[101,136],[102,103,136],[106,136],[104,106,136],[106,107,108,124,135,136],[106,107,108,121,124,127,136],[136,140],[102,109,114,124,135,136],[106,107,109,110,114,124,132,135,136],[109,111,124,132,135,136],[90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142],[106,112,136],[113,135,136],[102,106,114,124,136],[115,136],[116,136],[93,117,136],[118,134,136,140],[119,136],[120,136],[106,121,122,136],[121,123,136,138],[94,106,124,125,126,127,136],[94,124,126,136],[124,125,136],[127,136],[128,136],[106,130,131,136],[130,131,136],[99,114,124,132,136],[133,136],[114,134,136],[94,109,120,135,136],[99,136],[124,136,137],[136,138],[136,139],[94,99,106,108,117,124,135,136,138,140],[124,136,141],[136,165,169],[59,60,61,62,136],[63,136],[59,61,62,63,136,164,166,167],[59,61,136,166],[60,136],[60,65,66,68,72,74,77,136],[65,66,67,72,74,77,136],[136,171,172],[66,72,74,76,136],[69,74,136],[136,150],[136,150,162],[136,147,148,149,151,162],[136,153],[136,150,157,161,164],[136,152,164],[136,155,157,160,161,164],[136,155,157,158,160,161,164],[136,147,148,149,150,151,153,154,155,156,157,161,164],[136,146,147,148,149,150,151,153,154,155,156,157,158,160,161,162,163],[136,146,164],[136,157,158,159,161,164],[136,160,164],[136,150,156,161,164],[136,154,162],[136,146],[136,165,173],[86,136],[82,83,85,106,107,109,111,114,124,132,135,136,141,143,144,145,164],[82,136],[83,136],[84,85,136],[66,69,74,77,136],[136,168],[64,68,74,136],[69,72,74,136],[66,68,69,72,73,74,77,136],[57,136],[69,74,80,88,136],[69,71,74,75,78,79,136],[74,87,136],[70,136],[72,88,136],[77,136],[69,74,87,136],[135,136,165,170,174],[60,61,62,136],[61,62,63,136,164,166,167],[61,136,166],[56],[69,74],[69,74,87],[72],[77],[165]],"referencedMap":[[61,1],[59,2],[56,2],[57,3],[90,4],[91,4],[93,5],[94,6],[95,7],[96,8],[97,9],[98,10],[99,11],[100,12],[101,13],[102,14],[103,14],[105,15],[104,16],[106,15],[107,17],[108,18],[92,19],[142,2],[109,20],[110,21],[111,22],[143,23],[112,24],[113,25],[114,26],[115,27],[116,28],[117,29],[118,30],[119,31],[120,32],[121,33],[122,33],[123,34],[124,35],[126,36],[125,37],[127,38],[128,39],[129,2],[130,40],[131,41],[132,42],[133,43],[134,44],[135,45],[136,46],[137,47],[138,48],[139,49],[140,50],[141,51],[70,2],[170,52],[63,53],[64,54],[168,55],[167,56],[65,57],[66,58],[68,59],[60,2],[171,2],[173,60],[172,2],[67,2],[144,2],[166,2],[77,61],[76,62],[148,63],[147,64],[150,65],[154,66],[151,64],[156,67],[153,68],[158,69],[163,2],[159,70],[162,71],[164,72],[152,73],[160,74],[161,75],[157,76],[149,63],[155,77],[145,2],[146,78],[62,2],[11,2],[13,2],[12,2],[2,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[20,2],[21,2],[3,2],[4,2],[25,2],[22,2],[23,2],[24,2],[26,2],[27,2],[28,2],[5,2],[29,2],[30,2],[31,2],[32,2],[6,2],[36,2],[33,2],[34,2],[35,2],[37,2],[7,2],[38,2],[43,2],[44,2],[39,2],[40,2],[41,2],[42,2],[8,2],[48,2],[45,2],[46,2],[47,2],[49,2],[9,2],[50,2],[51,2],[52,2],[53,2],[54,2],[1,2],[10,2],[55,2],[174,79],[87,80],[165,81],[83,82],[82,2],[84,83],[85,2],[86,84],[72,85],[169,86],[69,87],[73,88],[74,89],[58,90],[81,91],[80,92],[75,93],[71,94],[79,95],[89,96],[78,96],[88,97],[175,98]],"exportedModulesMap":[[61,2],[59,2],[56,2],[57,3],[90,4],[91,4],[93,5],[94,6],[95,7],[96,8],[97,9],[98,10],[99,11],[100,12],[101,13],[102,14],[103,14],[105,15],[104,16],[106,15],[107,17],[108,18],[92,19],[142,2],[109,20],[110,21],[111,22],[143,23],[112,24],[113,25],[114,26],[115,27],[116,28],[117,29],[118,30],[119,31],[120,32],[121,33],[122,33],[123,34],[124,35],[126,36],[125,37],[127,38],[128,39],[129,2],[130,40],[131,41],[132,42],[133,43],[134,44],[135,45],[136,46],[137,47],[138,48],[139,49],[140,50],[141,51],[70,2],[170,52],[63,99],[64,54],[168,100],[167,101],[65,57],[66,58],[68,59],[60,2],[171,2],[173,60],[172,2],[67,2],[144,2],[166,2],[77,61],[76,62],[148,63],[147,64],[150,65],[154,66],[151,64],[156,67],[153,68],[158,69],[163,2],[159,70],[162,71],[164,72],[152,73],[160,74],[161,75],[157,76],[149,63],[155,77],[145,2],[146,78],[62,2],[11,2],[13,2],[12,2],[2,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[20,2],[21,2],[3,2],[4,2],[25,2],[22,2],[23,2],[24,2],[26,2],[27,2],[28,2],[5,2],[29,2],[30,2],[31,2],[32,2],[6,2],[36,2],[33,2],[34,2],[35,2],[37,2],[7,2],[38,2],[43,2],[44,2],[39,2],[40,2],[41,2],[42,2],[8,2],[48,2],[45,2],[46,2],[47,2],[49,2],[9,2],[50,2],[51,2],[52,2],[53,2],[54,2],[1,2],[10,2],[55,2],[174,79],[87,80],[165,81],[83,82],[82,2],[84,83],[85,2],[86,84],[72,85],[169,86],[69,87],[73,88],[74,89],[58,102],[80,103],[75,104],[79,105],[89,106],[78,106],[88,97],[175,107]],"semanticDiagnosticsPerFile":[61,59,56,57,90,91,93,94,95,96,97,98,99,100,101,102,103,105,104,106,107,108,92,142,109,110,111,143,112,113,114,115,116,117,118,119,120,121,122,123,124,126,125,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,70,170,63,64,168,167,65,66,68,60,171,173,172,67,144,166,77,76,148,147,150,154,151,156,153,158,163,159,162,164,152,160,161,157,149,155,145,146,62,11,13,12,2,14,15,16,17,18,19,20,21,3,4,25,22,23,24,26,27,28,5,29,30,31,32,6,36,33,34,35,37,7,38,43,44,39,40,41,42,8,48,45,46,47,49,9,50,51,52,53,54,1,10,55,174,87,165,83,82,84,85,86,72,169,69,73,74,58,81,80,75,71,79,89,78,88,175],"latestChangedDtsFile":"./vite.config.d.ts"},"version":"4.9.4"}
--------------------------------------------------------------------------------
/updater.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.1.2",
3 | "notes": "Getdeck Desktop 0.1.2 is now available. Changelog: https://github.com/Getdeck/Getdeck-Desktop/releases/tag/0.1.2",
4 | "platforms": {
5 | "darwin-x86_64": {
6 | "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVRVFRkcVFNbnZ3ZXdxSXN3RzdGWVBDb1h2WEJiVnN2S056UmVROVozRUtOYU5CR1NPQ1VkRndFZjJYeTlwZ1RtdGhhNVUrb2daSC9CNFJYbGptVGxyV3ZIVFppQ2IzNVFvPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNjkwNDcwMjcwCWZpbGU6R2V0ZGVjay1EZXNrdG9wLmFwcC50YXIuZ3oKRVpNTEIyaU15WHVYWEptbDM2TGx3Ynl4TkVCTzFZZFh3SjAxWWJpSWRyUlZPY29sZVgwSTZpcUIxOXdaaXpuREFLWlFkOGo4cDJHalRhcG0wM240Q3c9PQo=",
7 | "url": "https://github.com/Getdeck/Getdeck-Desktop/releases/download/0.1.2/Getdeck-Desktop.app.tar.gz"
8 | },
9 | "linux-x86_64": {
10 | "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVRVFRkcVFNbnZ3ZXlyR3VNQzRmK0VORDExbGVUTVJyblQ5dm9QaXlCV0trU3AvUFlxYTJqOGY0NlNLUTN6aEVIMVR2YnJ5d2JyR3QwSElFTFFiZXFlaG5nMUxVcHpkY3c0PQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNjkwNDcwMTI5CWZpbGU6Z2V0ZGVjay1kZXNrdG9wXzAuMS4yX2FtZDY0LkFwcEltYWdlLnRhci5negpCOXJQNFordnM2S1JsL2p2WmEwekR3bHVta3ByWFFMVzYwUlRxNTRyaHVOd2NRd21zcVBRVzZ6Q2VsR3ltWjY4UjhYVjFUQzVPN2dkSHlZMGp4dFlDdz09Cg==",
11 | "url": "https://github.com/Getdeck/Getdeck-Desktop/releases/download/0.1.2/getdeck-desktop_0.1.2_amd64.AppImage.tar.gz"
12 | },
13 | "windows-x86_64": {
14 | "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVRVFRkcVFNbnZ3ZXdNNXQza3NwUDArcnpScEdwTnpXUHdsNGFBTzl0Q24wRVN0MSthZXFYUllSM3JrYlppVGt4MExITWh2SXJUY2t3MEpacWpKendmelpVSXFoSnJmY2dFPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNjkwNDcwMjQ2CWZpbGU6R2V0ZGVjay1EZXNrdG9wXzAuMS4yX3g2NF9lbi1VUy5tc2kuemlwClNBM2pySmM2Wi9hYXhaWmZWTFlUUHYzRWl0dFR6MjNVVnczMmUxSU1NMzhNQllFblpNejJUUFZqNU1LUmdDeXZVcThsV3loUHNGRFJvQmNqUlBuY0JnPT0K",
15 | "url": "https://github.com/Getdeck/Getdeck-Desktop/releases/download/0.1.2/getdeck-desktop_0.1.2_x64_en-US.msi.zip"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/vite.config.d.ts:
--------------------------------------------------------------------------------
1 | declare const _default: import("vite").UserConfigExport;
2 | export default _default;
3 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import vue from '@vitejs/plugin-vue'
3 | import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
4 | import { fileURLToPath, URL } from 'node:url'
5 |
6 | export default defineConfig({
7 | // prevent vite from obscuring rust errors
8 | clearScreen: false,
9 | // Tauri expects a fixed port, fail if that port is not available
10 | server: {
11 | strictPort: true,
12 | },
13 | define: { 'process.env': {} },
14 | // to make use of `TAURI_PLATFORM`, `TAURI_ARCH`, `TAURI_FAMILY`,
15 | // `TAURI_PLATFORM_VERSION`, `TAURI_PLATFORM_TYPE` and `TAURI_DEBUG`
16 | // env variables
17 | envPrefix: ["VITE_", "TAURI_"],
18 | resolve: {
19 | alias: {
20 | '@': fileURLToPath(new URL('./src', import.meta.url))
21 | },
22 | extensions: [
23 | '.js',
24 | '.json',
25 | '.jsx',
26 | '.mjs',
27 | '.ts',
28 | '.tsx',
29 | '.vue',
30 | ],
31 | },
32 | build: {
33 | // Tauri supports es2021
34 | target: ["es2021", "chrome100", "safari13"],
35 | // don't minify for debug builds
36 | minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
37 | // produce sourcemaps for debug builds
38 | sourcemap: !!process.env.TAURI_DEBUG,
39 | },
40 | plugins: [
41 | vue({
42 | template: { transformAssetUrls }
43 | }),
44 | // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin
45 | vuetify({
46 | autoImport: true,
47 | styles: {
48 | configFile: 'src/styles/settings.scss',
49 | },
50 | }),
51 | ],
52 | });
53 |
--------------------------------------------------------------------------------