4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-11 17:55:51 +00:00

Fix syncstatus for external nodes

This commit is contained in:
AlphaX-Projects 2024-04-02 18:20:41 +02:00
parent f2d943e451
commit c5890f400f
3 changed files with 203 additions and 203 deletions

View File

@ -63,7 +63,7 @@ class AppInfo extends connect(store)(LitElement) {
super()
this.nodeInfo = []
this.coreInfo = []
this.nodeStatus = {}
this.nodeConfig = {}
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}

View File

@ -9,8 +9,10 @@ import '@material/mwc-icon'
class SyncIndicator extends connect(store)(LitElement) {
static get properties() {
return {
isBehind: { type: Boolean },
blocksBehind: { type: Number },
nodeUrl: { type: String },
address: { type: String },
isBehind: { type: Boolean },
isSynchronizing: { type: Boolean },
hasCoreRunning: { type: Boolean }
}
@ -18,12 +20,13 @@ class SyncIndicator extends connect(store)(LitElement) {
constructor() {
super()
this.isBehind = null
this.blocksBehind = 0
this.nodeUrl = this.getNodeUrl()
this.myNode = this.getMyNode()
this.interval = null
this.nodeUrl = ''
this.address = ''
this.isBehind = false
this.isSynchronizing = false
this.hasCoreRunning = true
this.interval = null
this.seenWelcomeSync = false
this.numberOfTries = 0
this.hasOpened = false
@ -68,6 +71,7 @@ class SyncIndicator extends connect(store)(LitElement) {
gap: 10px;
width: 100%;
}
.bootstrap-button {
font-family: Roboto, sans-serif;
font-size: 16px;
@ -86,42 +90,82 @@ class SyncIndicator extends connect(store)(LitElement) {
`
}
async firstUpdated() {
render() {
return html`
${!this.hasCoreRunning ? html`
<div class="parent">
<span>
<mwc-icon id="notification-general-icon" style="color: red; cursor:pointer;user-select:none">
priority_high
</mwc-icon>
</span>
<p>
${translate("tour.tour17")}
</p>
</div>
` : (this.blocksBehind > 1050 && this.isSynchronizing) ? html`
<div class="parent">
<div class="column">
<div class="row">
<span>
<img src="/img/syncing.png" style="height: 24px; width: 24px;" />
</span>
<p>
${this.blocksBehind} ${translate("tour.tour20")}
</p>
</div>
<div class="row" style="justify-content: center">
<button class="bootstrap-button" @click="${() => {this.bootstrap()}}">
${translate("tour.tour18")}
</button>
</div>
</div>
</div>
` : this.isSynchronizing ? html`
<div class="parent">
<span>
<img src="/img/syncing.png" style="height: 24px; width: 24px;" />
</span>
<p>
${translate("tour.tour19")} ${this.blocksBehind ? this.blocksBehind : ""} ${this.blocksBehind ? translate("tour.tour21"): ""}
</p>
</div>
` : "" }
`
}
firstUpdated() {
this.getNodeUrl()
this.address = store.getState().app.selectedAddress.address
this.seenWelcomeSync = JSON.parse(
localStorage.getItem(`welcome-sync-${this.address}`) || 'false'
)
setInterval(() => {
this.getNodeUrl()
}, 60000)
}
getNodeUrl() {
const myNode =
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
window.parent.reduxStore.getState().app.nodeConfig.node
]
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
}
getMyNode() {
return window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
window.parent.reduxStore.getState().app.nodeConfig.node
]
const syncInfoNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const syncInfoUrl = syncInfoNode.protocol + '://' + syncInfoNode.domain + ':' + syncInfoNode.port
this.nodeUrl = syncInfoUrl
}
async getDaySummary() {
try {
this.fetchingSummary = true
const endpointLastBlock = `${this.nodeUrl}/blocks/last`
const resLastBlock = await fetch(endpointLastBlock)
const dataLastBlock = await resLastBlock.json()
const timestampNow = Date.now()
const currentBlockTimestamp = dataLastBlock.timestamp
if (currentBlockTimestamp < timestampNow) {
const diff = timestampNow - currentBlockTimestamp
const inSeconds = diff / 1000 // millisecs to secs
const inSeconds = diff / 1000
const inBlocks = inSeconds / 70
this.blocksBehind = parseInt(inBlocks)
if (inBlocks >= 100) {
@ -141,7 +185,7 @@ class SyncIndicator extends connect(store)(LitElement) {
async checkHowManyBlocksBehind() {
try {
await this.getDaySummary();
await this.getDaySummary()
this.interval = setInterval(() => {
if(this.fetchingSummary) return
if (this.isBehind === false) {
@ -150,12 +194,33 @@ class SyncIndicator extends connect(store)(LitElement) {
}
this.getDaySummary()
}, 20000)
} catch (error) {}
} catch (error) {
// ...
}
}
async bootstrap() {
try {
const endpoint = `${this.nodeUrl}/admin/bootstrap/?apiKey=${this.getApiKey()}`
const res = await fetch(endpoint)
const data = await res.json()
if (data === true) {
parentEpml.request('showSnackBar', get('tour.tour22'))
}
} catch (error) {
// ...
}
}
getApiKey() {
const apiNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
return apiNode.apiKey
}
stateChanged(state) {
this.address = store.getState().app.selectedAddress.address
if(!this.seenWelcomeSync && state.app.nodeStatus && state.app.nodeStatus.syncPercent === 100 && this.hasOpened === false){
if (!this.seenWelcomeSync && state.app.nodeStatus && state.app.nodeStatus.syncPercent === 100 && this.hasOpened === false) {
this.hasOpened = true
this.dispatchEvent(
new CustomEvent('open-welcome-modal-sync', {
@ -164,22 +229,17 @@ class SyncIndicator extends connect(store)(LitElement) {
})
)
}
if (
state.app.nodeStatus &&
Object.keys(state.app.nodeStatus).length === 0
) {
if (state.app.nodeStatus && Object.keys(state.app.nodeStatus).length === 0) {
if (this.numberOfTries > 5) {
this.hasCoreRunning = false
} else {
this.numberOfTries = this.numberOfTries + 1
}
} else if(state.app.nodeStatus && state.app.nodeStatus.syncPercent === 100 && state.app.nodeStatus.syncPercent !== this.syncPercentage){
} else if (state.app.nodeStatus && state.app.nodeStatus.syncPercent === 100 && state.app.nodeStatus.syncPercent !== this.syncPercentage) {
this.syncPercentage = state.app.nodeStatus.syncPercent
this.isSynchronizing = false
} else if (
state.app.nodeStatus
) {
} else if (state.app.nodeStatus) {
this.hasCoreRunning = true
this.numberOfTries = 0
this.syncPercentage = state.app.nodeStatus.syncPercent
@ -188,95 +248,13 @@ class SyncIndicator extends connect(store)(LitElement) {
this.isSynchronizing = true
}
if (
!this.interval &&
this.isBehind === null &&
state.app.nodeStatus.isSynchronizing &&
state.app.nodeStatus.syncPercent !== 100
) {
if (!this.interval && this.isBehind === null && state.app.nodeStatus.isSynchronizing && state.app.nodeStatus.syncPercent !== 100) {
this.checkHowManyBlocksBehind()
}
} else {
this.hasCoreRunning = true
}
}
async bootstrap(){
try {
const endpoint = `${this.nodeUrl}/admin/bootstrap/?apiKey=${this.myNode.apiKey}`
const res = await fetch(endpoint)
const data = await res.json()
if (data === true) {
parentEpml.request('showSnackBar', get('tour.tour22'))
}
} catch (error) {
}
}
render() {
return html`
${!this.hasCoreRunning
? html`
<div class="parent">
<span
><mwc-icon
id="notification-general-icon"
style="color: red; cursor:pointer;user-select:none"
>priority_high</mwc-icon
></span
>
<p>
${translate("tour.tour17")}
</p>
</div>
`
: (this.blocksBehind > 1050 && this.isSynchronizing)
? html`
<div class="parent">
<div class="column">
<div class="row">
<span
><img
src="/img/syncing.png"
style="height: 24px; width: 24px;"
/></span>
<p>
${this.blocksBehind} ${translate("tour.tour20")}
</p>
</div>
<div
class="row"
style="justify-content: center"
>
<button
class="bootstrap-button"
@click="${() => {
this.bootstrap()
}}"
>
${translate("tour.tour18")}
</button>
</div>
</div>
</div>
`
: this.isSynchronizing
? html`
<div class="parent">
<span
><img
src="/img/syncing.png"
style="height: 24px; width: 24px;"
/></span>
<p>
${translate("tour.tour19")} ${this.blocksBehind ? this.blocksBehind : ""} ${this.blocksBehind ? translate("tour.tour21"): ""}
</p>
</div>
`
: "" }
`
}
}
customElements.define('sync-indicator', SyncIndicator)
customElements.define('sync-indicator', SyncIndicator)

View File

@ -6,123 +6,145 @@ import {translate} from '../../../translate'
class CoreSyncStatus extends connect(store)(LitElement) {
static get properties() {
return {
nodeStatus: {type: Object},
coreInfos: { type: Array }
nodeInfos: { type: Array },
coreInfos: { type: Array },
theme: { type: String, reflect: true }
}
}
constructor() {
super()
this.nodeStatus = {}
this.nodeInfos = []
this.coreInfos = []
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}
static styles = css`
.lineHeight {
line-height: 33%;
}
static get styles() {
return css`
.lineHeight {
line-height: 33%;
}
.tooltip {
display: inline-block;
position: relative;
text-align: left;
}
.tooltip {
display: inline-block;
position: relative;
text-align: left;
}
.tooltip .bottom {
min-width: 200px;
max-width: 250px;
top: 35px;
left: 50%;
transform: translate(-50%, 0);
padding: 10px 10px;
color: var(--black);
background-color: var(--white);
font-weight: normal;
font-size: 13px;
border-radius: 8px;
position: absolute;
z-index: 99999999;
box-sizing: border-box;
box-shadow: 0 1px 8px rgba(0,0,0,0.5);
border: 1px solid var(--black);
visibility: hidden;
opacity: 0;
transition: opacity 0.8s;
}
.tooltip .bottom {
min-width: 200px;
max-width: 250px;
top: 35px;
left: 50%;
transform: translate(-50%, 0);
padding: 10px 10px;
color: var(--black);
background-color: var(--white);
font-weight: normal;
font-size: 13px;
border-radius: 8px;
position: absolute;
z-index: 99999999;
box-sizing: border-box;
box-shadow: 0 1px 8px rgba(0,0,0,0.5);
border: 1px solid var(--black);
visibility: hidden;
opacity: 0;
transition: opacity 0.8s;
}
.tooltip:hover .bottom {
visibility: visible;
opacity: 1;
}
.tooltip:hover .bottom {
visibility: visible;
opacity: 1;
}
.tooltip .bottom i {
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -12px;
width: 24px;
height: 12px;
overflow: hidden;
}
.tooltip .bottom i {
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -12px;
width: 24px;
height: 12px;
overflow: hidden;
}
.tooltip .bottom i::after {
content: '';
position: absolute;
width: 12px;
height: 12px;
left: 50%;
transform: translate(-50%,50%) rotate(45deg);
background-color: var(--white);
border: 1px solid var(--black);
box-shadow: 0 1px 8px rgba(0,0,0,0.5);
}
`
.tooltip .bottom i::after {
content: '';
position: absolute;
width: 12px;
height: 12px;
left: 50%;
transform: translate(-50%,50%) rotate(45deg);
background-color: var(--white);
border: 1px solid var(--black);
box-shadow: 0 1px 8px rgba(0,0,0,0.5);
}
`
}
render() {
return html`
<div id="core-sync-status-id">
${this.renderSyncStatusIcon()}
${this.renderSyncStatusIcon()}
</div>
`
}
firstUpdated() {
this.getNodeInfos()
this.getCoreInfos()
setInterval(() => {
this.getNodeInfos()
this.getCoreInfos()
}, 60000)
}, 30000)
}
async getNodeInfos() {
const appInfoNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const appInfoUrl = appInfoNode.protocol + '://' + appInfoNode.domain + ':' + appInfoNode.port
const nodeInfoUrl = `${appInfoUrl}/admin/status`
await fetch(nodeInfoUrl).then(response => {
return response.json()
}).then(data => {
this.nodeInfos = data
}).catch(err => {
console.error('Request failed', err)
})
}
async getCoreInfos() {
const corInfo = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const coreInfoUrl = corInfo.protocol + '://' + corInfo.domain + ':' + corInfo.port
const infoUrl = `${coreInfoUrl}/admin/info`
await fetch(infoUrl).then(response => {
const appCoreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const appCoreUrl = appCoreNode.protocol + '://' + appCoreNode.domain + ':' + appCoreNode.port
const coreInfoUrl = `${appCoreUrl}/admin/info`
await fetch(coreInfoUrl).then(response => {
return response.json()
}).then(data => {
this.coreInfos = data
}).catch(err => {
console.error('Request failed', err)
})
}
renderSyncStatusIcon() {
if (this.nodeStatus.isSynchronizing === true && this.nodeStatus.syncPercent === 99) {
if (this.nodeInfos.isSynchronizing === true && this.nodeInfos.syncPercent === 99) {
return html`
<div class="tooltip" style="display: inline;">
<span><img src="/img/syncing.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
<div class="bottom">
<h3>${translate("walletprofile.wp3")}</h3>
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeStatus.syncPercent !== undefined ? this.nodeStatus.syncPercent + '%' : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeStatus.height ? this.nodeStatus.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeStatus.numberOfConnections ? this.nodeStatus.numberOfConnections : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeInfos.syncPercent !== undefined ? this.nodeInfos.syncPercent + '%' : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
<i></i>
</div>
</div>
`
} else if (this.nodeStatus.isSynchronizing === true && this.nodeStatus.isMintingPossible === false && this.nodeStatus.syncPercent === 100) {
} else if (this.nodeInfos.isSynchronizing === true && this.nodeInfos.isMintingPossible === false && this.nodeInfos.syncPercent === 100) {
return html`
<div class="tooltip" style="display: inline;">
<span><img src="/img/synced.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
@ -130,13 +152,13 @@ class CoreSyncStatus extends connect(store)(LitElement) {
<h3>${translate("walletprofile.wp3")}</h3>
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
<h4 class="lineHeight">${translate("walletprofile.wp4")} ${translate("walletprofile.wp2")}</h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeStatus.height ? this.nodeStatus.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeStatus.numberOfConnections ? this.nodeStatus.numberOfConnections : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
<i></i>
</div>
</div>
`
} else if (this.nodeStatus.isSynchronizing === false && this.nodeStatus.isMintingPossible === false && this.nodeStatus.syncPercent === 100) {
} else if (this.nodeInfos.isSynchronizing === false && this.nodeInfos.isMintingPossible === false && this.nodeInfos.syncPercent === 100) {
return html`
<div class="tooltip" style="display: inline;">
<span><img src="/img/synced.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
@ -144,13 +166,13 @@ class CoreSyncStatus extends connect(store)(LitElement) {
<h3>${translate("walletprofile.wp3")}</h3>
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
<h4 class="lineHeight">${translate("walletprofile.wp4")} ${translate("walletprofile.wp2")}</h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeStatus.height ? this.nodeStatus.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeStatus.numberOfConnections ? this.nodeStatus.numberOfConnections : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
<i></i>
</div>
</div>
`
} else if (this.nodeStatus.isSynchronizing === true && this.nodeStatus.isMintingPossible === true && this.nodeStatus.syncPercent === 100) {
} else if (this.nodeInfos.isSynchronizing === true && this.nodeInfos.isMintingPossible === true && this.nodeInfos.syncPercent === 100) {
return html`
<div class="tooltip" style="display: inline;">
<span><img src="/img/synced_minting.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
@ -158,13 +180,13 @@ class CoreSyncStatus extends connect(store)(LitElement) {
<h3>${translate("walletprofile.wp3")}</h3>
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
<h4 class="lineHeight">${translate("walletprofile.wp4")} <span style="color: #03a9f4">( ${translate("walletprofile.wp1")} )</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeStatus.height ? this.nodeStatus.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeStatus.numberOfConnections ? this.nodeStatus.numberOfConnections : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
<i></i>
</div>
</div>
`
} else if (this.nodeStatus.isSynchronizing === false && this.nodeStatus.isMintingPossible === true && this.nodeStatus.syncPercent === 100) {
} else if (this.nodeInfos.isSynchronizing === false && this.nodeInfos.isMintingPossible === true && this.nodeInfos.syncPercent === 100) {
return html`
<div class="tooltip" style="display: inline;">
<span><img src="/img/synced_minting.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
@ -172,8 +194,8 @@ class CoreSyncStatus extends connect(store)(LitElement) {
<h3>${translate("walletprofile.wp3")}</h3>
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
<h4 class="lineHeight">${translate("walletprofile.wp4")} <span style="color: #03a9f4">( ${translate("walletprofile.wp1")} )</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeStatus.height ? this.nodeStatus.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeStatus.numberOfConnections ? this.nodeStatus.numberOfConnections : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
<i></i>
</div>
</div>
@ -185,9 +207,9 @@ class CoreSyncStatus extends connect(store)(LitElement) {
<div class="bottom">
<h3>${translate("walletprofile.wp3")}</h3>
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeStatus.syncPercent !== undefined ? this.nodeStatus.syncPercent + '%' : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeStatus.height ? this.nodeStatus.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeStatus.numberOfConnections ? this.nodeStatus.numberOfConnections : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeInfos.syncPercent !== undefined ? this.nodeInfos.syncPercent + '%' : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
<i></i>
</div>
</div>
@ -196,9 +218,9 @@ class CoreSyncStatus extends connect(store)(LitElement) {
}
stateChanged(state) {
this.nodeStatus = state.app.nodeStatus
// ...
}
}
customElements.define('core-sync-status', CoreSyncStatus)
customElements.define('core-sync-status', CoreSyncStatus)