diff --git a/.github/workflows/codeql-analyze.yaml b/.github/workflows/codeql-analyze.yaml index 18796f2..54d3b7e 100644 --- a/.github/workflows/codeql-analyze.yaml +++ b/.github/workflows/codeql-analyze.yaml @@ -12,6 +12,7 @@ name: "CodeQL" on: + workflow_dispatch: push: branches: [ main ] pull_request: diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml deleted file mode 100644 index 8f75b36..0000000 --- a/.github/workflows/docker.yaml +++ /dev/null @@ -1,56 +0,0 @@ -name: Docker Scan and Build - -on: - push: - branches: [ main ] - schedule: - - cron: "0 0 * * *" # Daily at midnight UTC - workflow_dispatch: - inputs: - trigger-build: - description: 'Trigger a manual build and push' - default: 'true' - -env: - DOCKER_IMAGE: donaldzou/wgdashboard - -jobs: - docker_build_analyze: - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_PASSWORD }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and export (multi-arch) - uses: docker/build-push-action@v6 - with: - context: . - file: ./docker/Dockerfile - push: true - tags: ${{ env.DOCKER_IMAGE }}:latest - platforms: linux/amd64,linux/arm64,linux/arm/v7 #ARM v6 no longer support by go image. - - - name: Docker Scout - id: docker-scout - uses: docker/scout-action@v1 - with: - command: cves - image: ${{ env.DOCKER_IMAGE }}:latest - only-severities: critical,high,medium,low,unspecified - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..06c6002 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,105 @@ +name: Docker Build and Push + +on: + workflow_dispatch: + push: + branches: + - 'main' + tags: + - '*' + release: + types: [ published ] + +env: + DOCKERHUB_PREFIX: docker.io + GITHUB_CONTAINER_PREFIX: ghcr.io + DOCKER_IMAGE: donaldzou/wgdashboard + +jobs: + docker_build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKERHUB_PREFIX }} + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_CONTAINER_PREFIX }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: | + - linux/amd64 + - linux/arm64 + - linux/arm/v7 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta by docs https://github.com/docker/metadata-action + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_PREFIX }}/${{ env.DOCKER_IMAGE }} + ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }} + tags: | + type=ref,event=branch + type=ref,event=tag + + - name: Build and export (multi-arch) + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 + + docker_scan: + if: ${{ github.event_name != 'pull_request' }} + runs-on: ubuntu-latest + needs: docker_build + steps: + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKERHUB_PREFIX }} + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Docker Scout CVEs + uses: docker/scout-action@v1 + with: + command: cves + image: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }}:main + only-severities: critical,high + only-fixed: true + write-comment: true + github-token: ${{ secrets.GITHUB_TOKEN }} + exit-code: true + + - name: Docker Scout Compare + uses: docker/scout-action@v1 + with: + command: compare + # Set to Github for maximum compat + image: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }}:main + to: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }}:latest + only-severities: critical,high + ignore-unchanged: true + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml deleted file mode 100644 index 7bdf543..0000000 --- a/.github/workflows/qodana_code_quality.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Qodana -on: - workflow_dispatch: - pull_request: - push: - branches: # Specify your branches here - - main # The 'main' branch - - v4.2-dev - -jobs: - qodana: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - checks: write - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit - fetch-depth: 0 # a full history is required for pull request analysis - - name: 'Qodana Scan' - uses: JetBrains/qodana-action@v2024.3 - with: - pr-mode: false - env: - QODANA_TOKEN: ${{ secrets.QODANA_TOKEN_2090978292 }} - QODANA_ENDPOINT: 'https://qodana.cloud' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..bc64ad1 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,24 @@ +# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. +# +# You can adjust the behavior by modifying this file. +# For more information, see: +# https://github.com/actions/stale +name: Mark stale issues and pull requests + +on: + schedule: + - cron: '00 08 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue has not been update for 20 days' + stale-pr-message: 'Stale pull request message' + stale-issue-label: 'stale' + days-before-stale: 30 diff --git a/.gitignore b/.gitignore index 8461e6a..df24dc4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ src/db/wgdashboard.db node_modules/** */proxy.js src/static/app/proxy.js +.secrets # Logs logs diff --git a/README.md b/README.md index 3a1b026..4cf05a1 100644 --- a/README.md +++ b/README.md @@ -4,20 +4,21 @@ > [!NOTE] > **Help Wanted 🎉**: Localizing WGDashboard to other languages! If you're willing to help, please visit https://github.com/donaldzou/WGDashboard/issues/397. Many thanks! + + 
-
-
-
-
-
+
+
+
@@ -37,43 +38,40 @@
This project is not affiliate to the official WireGuard Project
- +- Join our Discord Server for quick help, or you wanna chat about this project! + You can reach out at
+
+ You can support via
- Alternatively, you can also reach out at our Matrix.org Chatroom :) -
-
- Matrix.org Chatroom
+
+
+
+ or, visit our merch store and support us by purchasing a merch for only $USD 17.00 (Including shipping worldwide & duties) +
+
-
\ No newline at end of file
+
diff --git a/src/dashboard.py b/src/dashboard.py
index 40d66c4..a9063f8 100644
--- a/src/dashboard.py
+++ b/src/dashboard.py
@@ -28,9 +28,9 @@ from modules.DashboardConfig import DashboardConfig
from modules.WireguardConfiguration import WireguardConfiguration
from modules.AmneziaWireguardConfiguration import AmneziaWireguardConfiguration
-
SystemStatus = SystemStatus()
+
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
app = Flask("WGDashboard", template_folder=os.path.abspath("./static/app/dist"))
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928
@@ -107,7 +107,7 @@ def auth_req():
else:
DashboardConfig.APIAccessed = False
whiteList = [
- '/static/', 'validateAuthentication', 'authenticate', 'getDashboardConfiguration',
+ '/static/', 'validateAuthentication', 'authenticate',
'getDashboardTheme', 'getDashboardVersion', 'sharePeer/get', 'isTotpEnabled', 'locale',
'/fileDownload'
]
@@ -1190,13 +1190,19 @@ def peerInformationBackgroundThread():
time.sleep(10)
while True:
with app.app_context():
- for c in WireguardConfigurations.values():
- if c.getStatus():
- c.getPeersTransfer()
- c.getPeersLatestHandshake()
- c.getPeersEndpoint()
- c.getPeersList()
- c.getRestrictedPeersList()
+ try:
+ curKeys = list(WireguardConfigurations.keys())
+ for name in curKeys:
+ if name in WireguardConfigurations.keys() and WireguardConfigurations.get(name) is not None:
+ c = WireguardConfigurations.get(name)
+ if c.getStatus():
+ c.getPeersTransfer()
+ c.getPeersLatestHandshake()
+ c.getPeersEndpoint()
+ c.getPeersList()
+ c.getRestrictedPeersList()
+ except Exception as e:
+ print(f"[WGDashboard] Background Thread #1 Error: {str(e)}", flush=True)
time.sleep(10)
def peerJobScheduleBackgroundThread():
diff --git a/src/static/app/dist/assets/configuration-Cy9CklRW.js b/src/static/app/dist/assets/configuration-qGYhSc1H.js
similarity index 86%
rename from src/static/app/dist/assets/configuration-Cy9CklRW.js
rename to src/static/app/dist/assets/configuration-qGYhSc1H.js
index 9e26044..1a8fde1 100644
--- a/src/static/app/dist/assets/configuration-Cy9CklRW.js
+++ b/src/static/app/dist/assets/configuration-qGYhSc1H.js
@@ -1 +1 @@
-import{_ as r,c as i,d as o,w as e,k as l,a as t,j as _,i as a,l as d,S as u}from"./index-DAYCBooh.js";const m={name:"configuration"},p={class:"mt-md-5 mt-3 text-body"};function f(k,x,h,w,$,v){const n=l("RouterView");return t(),i("div",p,[o(n,null,{default:e(({Component:s,route:c})=>[o(_,{name:"fade2",mode:"out-in"},{default:e(()=>[(t(),a(u,null,{default:e(()=>[(t(),a(d(s),{key:c.path}))]),_:2},1024))]),_:2},1024)]),_:1})])}const B=r(m,[["render",f]]);export{B as default};
+import{_ as r,c as i,d as o,w as e,k as l,a as t,j as _,i as a,l as d,S as u}from"./index-DZliHkQD.js";const m={name:"configuration"},p={class:"mt-md-5 mt-3 text-body"};function f(k,x,h,w,$,v){const n=l("RouterView");return t(),i("div",p,[o(n,null,{default:e(({Component:s,route:c})=>[o(_,{name:"fade2",mode:"out-in"},{default:e(()=>[(t(),a(u,null,{default:e(()=>[(t(),a(d(s),{key:c.path}))]),_:2},1024))]),_:2},1024)]),_:1})])}const B=r(m,[["render",f]]);export{B as default};
diff --git a/src/static/app/dist/assets/configurationList-DcvZI8bv.js b/src/static/app/dist/assets/configurationList-Cznk60kB.js
similarity index 98%
rename from src/static/app/dist/assets/configurationList-DcvZI8bv.js
rename to src/static/app/dist/assets/configurationList-Cznk60kB.js
index 4d4c180..a630729 100644
--- a/src/static/app/dist/assets/configurationList-DcvZI8bv.js
+++ b/src/static/app/dist/assets/configurationList-Cznk60kB.js
@@ -1 +1 @@
-import{_ as D,D as M,g as I,a as i,c as a,b as t,d as r,w as S,n as m,t as u,f as v,i as _,e as y,m as U,v as V,p as B,k as p,r as O,q as K,s as w,j as G,o as R,x as W,F as k,h as C,W as q,G as $,T as F,y as z}from"./index-DAYCBooh.js";import{L as x}from"./localeText-BL2XSmCp.js";import{_ as j}from"./protocolBadge-BPNBzt01.js";import{C as J}from"./storageMount.vue_vue_type_style_index_0_scoped_9509d7a0_lang-B3oT3k60.js";const N={name:"configurationCard",components:{ProtocolBadge:j,LocaleText:x},props:{c:{Name:String,Status:Boolean,PublicKey:String,PrivateKey:String},delay:String,display:String},data(){return{configurationToggling:!1}},setup(){return{dashboardConfigurationStore:M()}},methods:{toggle(){this.configurationToggling=!0,I("/api/toggleWireguardConfiguration",{configurationName:this.c.Name},s=>{s.status?this.dashboardConfigurationStore.newMessage("Server",`${this.c.Name} ${s.data?"is on":"is off"}`):this.dashboardConfigurationStore.newMessage("Server",s.message,"danger"),this.c.Status=s.data,this.configurationToggling=!1})}}},T=()=>{B(s=>({"7d032b58":s.delay}))},P=N.setup;N.setup=P?(s,e)=>(T(),P(s,e)):T;const E={class:"card conf_card rounded-3 shadow text-decoration-none"},H={class:"mb-0"},Y={class:"card-title mb-0 d-flex align-items-center gap-2"},A={class:"card-footer d-flex gap-2 flex-column"},Q={class:"row"},X={class:"d-flex gap-2 align-items-center"},Z={class:"text-muted"},tt={class:"mb-0 d-block d-lg-inline-block"},et={style:{"line-break":"anywhere"}},st={class:"form-check form-switch ms-auto"},ot=["for"],it={key:4,class:"spinner-border spinner-border-sm ms-2","aria-hidden":"true"},nt=["disabled","id"];function at(s,e,o,f,n,g){const c=p("ProtocolBadge"),l=p("RouterLink"),d=p("LocaleText");return i(),a("div",{class:m(["col-12",{"col-lg-6 col-xl-4":this.display==="Grid"}])},[t("div",E,[r(l,{to:"/configuration/"+o.c.Name+"/peers",class:"card-body d-flex align-items-center gap-3 flex-wrap text-decoration-none"},{default:S(()=>[t("h6",H,[t("span",{class:m(["dot",{active:o.c.Status}])},null,2)]),t("h6",Y,[t("samp",null,u(o.c.Name),1),t("small",null,[r(c,{protocol:o.c.Protocol,mini:!0},null,8,["protocol"])])]),e[2]||(e[2]=t("h6",{class:"mb-0 ms-auto"},[t("i",{class:"bi bi-chevron-right"})],-1))]),_:1},8,["to"]),t("div",A,[t("div",Q,[t("small",{class:m(["col-6",{"col-md-3":this.display==="List"}])},[e[3]||(e[3]=t("i",{class:"bi bi-arrow-down-up me-2"},null,-1)),v(u(o.c.DataUsage.Total>0?o.c.DataUsage.Total.toFixed(4):0)+" GB ",1)],2),t("small",{class:m(["text-primary-emphasis col-6",{"col-md-3":this.display==="List"}])},[e[4]||(e[4]=t("i",{class:"bi bi-arrow-down me-2"},null,-1)),v(u(o.c.DataUsage.Receive>0?o.c.DataUsage.Receive.toFixed(4):0)+" GB ",1)],2),t("small",{class:m(["text-success-emphasis col-6",{"col-md-3":this.display==="List"}])},[e[5]||(e[5]=t("i",{class:"bi bi-arrow-up me-2"},null,-1)),v(u(o.c.DataUsage.Sent>0?o.c.DataUsage.Sent.toFixed(4):0)+" GB ",1)],2),t("small",{class:m(["col-6",{"col-md-3 text-md-end ":this.display==="List"}])},[t("span",{class:m(["dot me-2",{active:o.c.ConnectedPeers>0}])},null,2),v(" "+u(o.c.ConnectedPeers)+" / "+u(o.c.TotalPeers)+" ",1),r(d,{t:"Peers"})],2)]),t("div",{class:m(["d-flex gap-2",[this.display==="Grid"?"flex-column":"gap-lg-3 flex-column flex-lg-row"]])},[t("div",X,[t("small",Z,[t("strong",null,[r(d,{t:"Public Key"})])]),t("small",tt,[t("samp",et,u(o.c.PublicKey),1)])]),t("div",st,[t("label",{class:"form-check-label",style:{cursor:"pointer"},for:"switch"+o.c.PrivateKey},[!o.c.Status&&this.configurationToggling?(i(),_(d,{key:0,t:"Turning Off..."})):o.c.Status&&this.configurationToggling?(i(),_(d,{key:1,t:"Turning On..."})):o.c.Status&&!this.configurationToggling?(i(),_(d,{key:2,t:"On"})):!o.c.Status&&!this.configurationToggling?(i(),_(d,{key:3,t:"Off"})):y("",!0),this.configurationToggling?(i(),a("span",it)):y("",!0)],8,ot),U(t("input",{class:"form-check-input",style:{cursor:"pointer"},disabled:this.configurationToggling,type:"checkbox",role:"switch",id:"switch"+o.c.PrivateKey,onChange:e[0]||(e[0]=L=>this.toggle()),"onUpdate:modelValue":e[1]||(e[1]=L=>o.c.Status=L)},null,40,nt),[[V,o.c.Status]])])],2)])])],2)}const rt=D(N,[["render",at],["__scopeId","data-v-dafd6275"]]),lt={class:"text-muted me-2"},ct={class:"fw-bold"},dt={__name:"storageMount",props:{mount:Object,align:Boolean,square:Boolean},setup(s){B(n=>({"2dc8ab7e":f.value}));const e=s,o=O(!1),f=K(()=>e.square?"40px":"25px");return(n,g)=>(i(),a("div",{class:"flex-grow-1 square rounded-3 border position-relative",onMouseenter:g[0]||(g[0]=c=>o.value=!0),onMouseleave:g[1]||(g[1]=c=>o.value=!1),style:w({"background-color":`rgb(25 135 84 / ${s.mount.percent}%)`})},[r(G,{name:"zoomReversed"},{default:S(()=>[o.value?(i(),a("div",{key:0,style:w([{"white-space":"nowrap"},{top:f.value}]),class:m(["floatingLabel z-3 border position-absolute d-block p-1 px-2 bg-body text-body rounded-3 border shadow d-flex",[s.align?"end-0":"start-0"]])},[t("small",lt,[t("samp",null,u(s.mount.mountPoint),1)]),t("small",ct,u(s.mount.percent)+"% ",1)],6)):y("",!0)]),_:1})],36))}},ut=D(dt,[["__scopeId","data-v-9509d7a0"]]),mt={class:"row text-body g-3 mb-5"},gt={class:"col-md-6 col-sm-12 col-xl-3"},ht={class:"d-flex align-items-center"},ft={class:"text-muted"},_t={class:"ms-auto"},pt={key:0},yt={key:1,class:"spinner-border spinner-border-sm"},bt={class:"progress",role:"progressbar",style:{height:"6px"}},St={class:"d-flex mt-2 gap-1"},vt={class:"col-md-6 col-sm-12 col-xl-3"},xt={class:"d-flex align-items-center"},wt={class:"text-muted"},kt={class:"ms-auto"},Ct={key:0},Lt={key:1,class:"spinner-border spinner-border-sm"},Dt={class:"progress",role:"progressbar",style:{height:"6px"}},$t={class:"d-flex mt-2 gap-1"},Nt={class:"col-md-6 col-sm-12 col-xl-3"},Tt={class:"d-flex align-items-center"},Pt={class:"text-muted"},Mt={class:"ms-auto"},It={key:0},Ut={key:1,class:"spinner-border spinner-border-sm"},Bt={class:"progress",role:"progressbar",style:{height:"6px"}},Kt={class:"col-md-6 col-sm-12 col-xl-3"},Gt={class:"d-flex align-items-center"},Vt={class:"text-muted"},Ot={class:"ms-auto"},Rt={key:0},Wt={key:1,class:"spinner-border spinner-border-sm"},qt={__name:"systemStatusWidget",setup(s){const e=M();let o=null;R(()=>{f(),o=setInterval(()=>{f()},5e3)}),W(()=>{clearInterval(o)});const f=()=>{I("/api/systemStatus",{},g=>{e.SystemStatus=g.data})},n=K(()=>e.SystemStatus);return(g,c)=>(i(),a("div",mt,[t("div",gt,[t("div",ht,[t("h6",ft,[c[0]||(c[0]=t("i",{class:"bi bi-cpu-fill me-2"},null,-1)),r(x,{t:"CPU"})]),t("h6",_t,[n.value?(i(),a("span",pt,u(n.value.CPU.cpu_percent)+"% ",1)):(i(),a("span",yt))])]),t("div",bt,[t("div",{class:"progress-bar",style:w({width:`${n.value?.CPU.cpu_percent}%`})},null,4)]),t("div",St,[(i(!0),a(k,null,C(n.value?.CPU.cpu_percent_per_cpu,(l,d)=>(i(),_(J,{key:d,align:d+1>Math.round(n.value?.CPU.cpu_percent_per_cpu.length/2),core_number:d,percentage:l},null,8,["align","core_number","percentage"]))),128))])]),t("div",vt,[t("div",xt,[t("h6",wt,[c[1]||(c[1]=t("i",{class:"bi bi-device-ssd-fill me-2"},null,-1)),r(x,{t:"Storage"})]),t("h6",kt,[n.value?(i(),a("span",Ct,u(n.value.Disks.find(l=>l.mountPoint==="/")?n.value?.Disks.find(l=>l.mountPoint==="/").percent:n.value?.Disks[0].percent)+"% ",1)):(i(),a("span",Lt))])]),t("div",Dt,[t("div",{class:"progress-bar bg-success",style:w({width:`${n.value?.Disks.find(l=>l.mountPoint==="/").percent}%`})},null,4)]),t("div",$t,[n.value?(i(!0),a(k,{key:0},C(n.value?.Disks,(l,d)=>(i(),_(ut,{key:l.mountPoint,align:d+1>Math.round(n.value?.Disks.length/2),mount:l},null,8,["align","mount"]))),128)):y("",!0)])]),t("div",Nt,[t("div",Tt,[t("h6",Pt,[c[2]||(c[2]=t("i",{class:"bi bi-memory me-2"},null,-1)),r(x,{t:"Memory"})]),t("h6",Mt,[n.value?(i(),a("span",It,u(n.value?.Memory.VirtualMemory.percent)+"% ",1)):(i(),a("span",Ut))])]),t("div",Bt,[t("div",{class:"progress-bar bg-info",style:w({width:`${n.value?.Memory.VirtualMemory.percent}%`})},null,4)])]),t("div",Kt,[t("div",Gt,[t("h6",Vt,[c[3]||(c[3]=t("i",{class:"bi bi-memory me-2"},null,-1)),r(x,{t:"Swap Memory"})]),t("h6",Ot,[n.value?(i(),a("span",Rt,u(n.value?.Memory.SwapMemory.percent)+"% ",1)):(i(),a("span",Wt))])]),c[4]||(c[4]=t("div",{class:"progress",role:"progressbar",style:{height:"6px"}},[t("div",{class:"progress-bar bg-warning",style:{width:"$ data?.Memory.SwapMemory.percent}%"}})],-1))])]))}},Ft=D(qt,[["__scopeId","data-v-c20f1a80"]]),zt={name:"configurationList",components:{SystemStatus:Ft,LocaleText:x,ConfigurationCard:rt},async setup(){return{wireguardConfigurationsStore:q()}},data(){return{configurationLoaded:!1,sort:{Name:$("Name"),Status:$("Status"),"DataUsage.Total":$("Total Usage")},currentSort:{key:"Name",order:"asc"},currentDisplay:"List",searchKey:""}},async mounted(){window.localStorage.getItem("ConfigurationListSort")?this.currentSort=JSON.parse(window.localStorage.getItem("ConfigurationListSort")):window.localStorage.setItem("ConfigurationListSort",JSON.stringify(this.currentSort)),window.localStorage.getItem("ConfigurationListDisplay")?this.currentDisplay=window.localStorage.getItem("ConfigurationListDisplay"):window.localStorage.setItem("ConfigurationListDisplay",this.currentDisplay),await this.wireguardConfigurationsStore.getConfigurations(),this.configurationLoaded=!0,this.wireguardConfigurationsStore.ConfigurationListInterval=setInterval(()=>{this.wireguardConfigurationsStore.getConfigurations()},1e4)},beforeUnmount(){clearInterval(this.wireguardConfigurationsStore.ConfigurationListInterval)},computed:{configurations(){return[...this.wireguardConfigurationsStore.Configurations].filter(s=>s.Name.toLowerCase().includes(this.searchKey)||s.PublicKey.includes(this.searchKey)||!this.searchKey).sort((s,e)=>this.currentSort.order==="desc"?this.dotNotation(s,this.currentSort.key)