import * as electronRemote from '@electron/remote'; const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); import * as moment from 'moment'; import BaseElements from './require/base-elements'; import ElementsUtil from './require/elements-util'; import Util from '../util'; import ClientController from '../client-controller'; import { Member } from '../data-types'; import Q from '../q-module'; export default function createTokenLogOverlay(document: Document, q: Q, server: ClientController): HTMLElement { let element = BaseElements.createOverlay(document, { class: 'content token-log', content: [ { class: 'tokens', content: { tag: 'img', src: './img/loading.svg', alt: 'loading...' } }, ] }); (async () => { Util.withPotentialErrorWarnOnCancel(q, { taskFunc: async () => { let tokens = await server.queryTokens(); Q.clearChildren(q.$$$(element, '.tokens')); let displayed = 0; for (let token of tokens) { // if (token.member != null) { // continue; // } let expired = token.expires < new Date(); // NOTE: It may be nice to be able to click-to-copy the token let memberText: string; if (token.member instanceof Member) { memberText = token.member.displayName; } else if (token.member) { memberText = '#' + token.member.id; } else { memberText = 'Unused Token'; } let displayElement = q.create({ class: 'token-display', content: [ { class: 'instance', content: [ { class: 'left', content: [ { class: 'member', content: memberText }, { class: 'token', content: token.token }, ] }, { class: 'right', content: [ { class: 'created', content: 'Created ' + moment(token.created).fromNow() }, { class: 'expires', content: (expired ? 'Expired ' : 'Expires ') + moment(token.expires).fromNow() }, ] } ] }, { class: 'buttons', content: [ { class: 'revoke', content: BaseElements.TRASHCAN } ] } ] }) as HTMLElement; let revokeElement = q.$$$(displayElement, '.buttons .revoke'); let contextElement = q.create({ class: 'context', content: { class: 'above', content: [ { class: 'tab', content: BaseElements.TAB_ABOVE }, { class: 'content text', content: 'Revoke' }, ] } }) as HTMLElement; let alignment = { centerX: 'centerX', top: 'bottom' }; ElementsUtil.bindHoverableContextElement( revokeElement, contextElement, revokeElement, alignment ); let revoking = false; let hoverTimeout: any | null = null; revokeElement.addEventListener('click', async () => { if (revoking) return; revoking = true; if (hoverTimeout) clearTimeout(hoverTimeout); (contextElement as any).manualRemoval = true; q.$$$(contextElement, '.content').innerText = 'Revoking...'; ElementsUtil.alignContextElement(contextElement, revokeElement, alignment); try { await server.revokeToken(token.token); } catch (e) { LOG.error('unable to revoke token', e); q.$$$(contextElement, '.content').innerText = 'Unable to Revoke'; ElementsUtil.alignContextElement(contextElement, revokeElement, alignment); await ElementsUtil.shakeElement(revokeElement, 400); hoverTimeout = setTimeout(() => { (contextElement as any).manualRemoval = false; contextElement.parentElement?.removeChild(contextElement); q.$$$(contextElement, '.content').innerText = 'Revoke'; }, 2000); return; } finally { revoking = false; } contextElement.parentElement?.removeChild(contextElement); displayElement.parentElement?.removeChild(displayElement); displayed -= 1; if (displayed == 0) { q.$$$(element, '.tokens').appendChild(q.create({ class: 'empty', content: 'No outstanding tokens' })); } }); q.$$$(element, '.tokens').appendChild(displayElement); displayed += 1; } if (displayed == 0) { q.$$$(element, '.tokens').appendChild(q.create({ class: 'empty', content: 'No outstanding tokens' })); } }, errorIndicatorAddFunc: async (errorIndicatorElement) => { Q.clearChildren(q.$$$(element, '.tokens')); q.$$$(element, '.tokens').appendChild(errorIndicatorElement); }, errorContainer: q.$$$(element, '.tokens'), errorMessage: 'Error fetching tokens' }); })(); return element; }