Skip to content

Commit

Permalink
refactor: ts
Browse files Browse the repository at this point in the history
Signed-off-by: Grigorii K. Shartsev <me@shgk.me>
  • Loading branch information
ShGKme committed Aug 19, 2024
1 parent 68372c1 commit 0903dbc
Show file tree
Hide file tree
Showing 38 changed files with 276 additions and 246 deletions.
38 changes: 20 additions & 18 deletions src/app/AppData.js → src/app/AppData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@

// TODO: use safeStorage for credentials

type Nullable<T> = T | null
// type SertializedAppData = { [key in keyof typeof AppData]: (typeof AppData)[key] }

export class AppData {

serverUrl = null
userMetadata = null
capabilities = null
version = {
serverUrl: Nullable<string> = null
userMetadata: Nullable<any> = null
capabilities: Nullable<any> = null
version: { nextcloud: Nullable<string>, talk: Nullable<string>, desktop: Nullable<string> } = {
nextcloud: null,
talk: null,
desktop: null,
}

talkHash = null
talkHashDirty = false
talkHash: Nullable<string> = null
talkHashDirty: boolean = false

credentials = null
storageKey = 'AppData'
credentials: Nullable<string> = null
storageKey: string = 'AppData'

/**
* Persist appData to LocalStorage
Expand All @@ -36,7 +39,8 @@ export class AppData {
*/
restore() {
try {
const parsed = JSON.parse(localStorage.getItem(this.storageKey))
// @ts-expect-error Throws if JSON is invalid
const parsed: AppData = JSON.parse(localStorage.getItem(this.storageKey))
if (parsed) {
this.fromJSON(parsed)
}
Expand All @@ -48,7 +52,7 @@ export class AppData {
}

/**
* Convert appData to plain object to serialize to JSON
* Convert appData to a plain object to serialize to JSON
*
* @return {object}
*/
Expand All @@ -67,10 +71,10 @@ export class AppData {
/**
* Set appData values from plain object
*
* @param {object} obj plain object
* @param obj plain object
* @return {AppData} this
*/
fromJSON(obj) {
fromJSON(obj: AppData) {
this.serverUrl = obj.serverUrl
this.userMetadata = obj.userMetadata
this.capabilities = obj.capabilities
Expand All @@ -84,10 +88,10 @@ export class AppData {
/**
* Set TalkHash and reset dirty flag
*
* @param {string} hash new hash
* @param hash new hash
* @return {AppData} this
*/
setTalkHash(hash) {
setTalkHash(hash: string) {
if (this.talkHash) {
this.talkHashDirty = true
}
Expand All @@ -96,10 +100,10 @@ export class AppData {
}

/**
* @param {boolean} isDirty is talk hash dirty
* @param isDirty is talk hash dirty
* @return {AppData} this
*/
setTalkHashDirty(isDirty) {
setTalkHashDirty(isDirty: boolean) {
this.talkHashDirty = isDirty
return this
}
Expand Down Expand Up @@ -128,7 +132,5 @@ export class AppData {

/**
* Global application's appData
*
* @type {AppData}
*/
export const appData = new AppData()
22 changes: 14 additions & 8 deletions src/app/appData.service.js → src/app/appData.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { getCurrentUserData, getCapabilities } from '../shared/ocs.service.js'
import { AxiosError } from '@nextcloud/axios'
import { getCurrentUserData, getCapabilities } from '../shared/ocs.service.ts'
import packageJson from '../../package.json'
import type { AppData } from './AppData.ts'

/**
* Re-fetch capabilities and userMetadata and update appData
*
* @param {import('./AppData.js').appData} appData appData
* @param {boolean} [persist] Persist after re-fetch
* @param appData appData
* @param persist Persist after re-fetch
* @return {Promise<void>}
* @throws {Error}
*/
export async function refetchAppData(appData, persist = false) {
export async function refetchAppData(appData: AppData, persist = false) {
const [userMetadata, capabilitiesResponse] = await Promise.all([
getCurrentUserData(),
getCapabilities(),
Expand All @@ -35,17 +37,17 @@ export async function refetchAppData(appData, persist = false) {
/**
* If talk hash is dirty, re-fetch capabilities and userMetadata and update appData
*
* @param {import('./AppData.js').appData} appData appData
* @param appData appData
* @return {Promise<void>}
* @throws {Error}
*/
export async function refetchAppDataIfDirty(appData) {
export async function refetchAppDataIfDirty(appData: AppData) {
// Re-fetch on dirty Talk hash and any desktop client upgrade
if (!appData.talkHashDirty && packageJson.version === appData.version.desktop) {
return
}

await new Promise((resolve) => {
await new Promise<void>((resolve) => {
/**
* Try to re-fetch appData
*
Expand All @@ -56,7 +58,11 @@ export async function refetchAppDataIfDirty(appData) {
await refetchAppData(appData, true)
console.debug('AppData re-fetched')
return true
} catch (error) {
} catch (error: unknown) {
if (!(error instanceof AxiosError)) {
console.error('Unknown error', error)
return false
}
if (error.response?.status === 401) {
appData.reset().persist()
console.debug('AppData credentials are invalid... Resetting')
Expand Down
24 changes: 12 additions & 12 deletions src/authentication/renderer/AuthenticationApp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<script setup>
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { Ref } from 'vue'
import MdiArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import { translate as t } from '@nextcloud/l10n'
import { getCapabilities } from '../../shared/ocs.service.js'
import { appData } from '../../app/AppData.js'
import { getCapabilities } from '../../shared/ocs.service.ts'
import { appData } from '../../app/AppData.ts'
import { MIN_REQUIRED_NEXTCLOUD_VERSION, MIN_REQUIRED_TALK_VERSION } from '../../constants.js'
import { refetchAppData } from '../../app/appData.service.js'

const version = window.TALK_DESKTOP.packageInfo.version
const rawServerUrl = ref(process.env.NODE_ENV !== 'production' ? process.env.NEXTCLOUD_DEV_SERVER_HOSTS?.split?.(' ')?.[0] : '')
const rawServerUrl: Ref<string> = ref((process.env.NODE_ENV !== 'production' && process.env.NEXTCLOUD_DEV_SERVER_HOSTS?.split?.(' ')?.[0]) || '')

const serverUrl = computed(() => {
const addHTTPS = (url) => url.startsWith('http') ? url : `https://${url}`
const removeIndexPhp = (url) => url.includes('/index.php') ? url.slice(0, url.indexOf('/index.php')) : url
const removeTrailingSlash = (url) => url.endsWith('/') ? url.slice(0, -1) : url
const addHTTPS = (url: string) => url.startsWith('http') ? url : `https://${url}`
const removeIndexPhp = (url: string) => url.includes('/index.php') ? url.slice(0, url.indexOf('/index.php')) : url
const removeTrailingSlash = (url: string) => url.endsWith('/') ? url.slice(0, -1) : url
return removeTrailingSlash(removeIndexPhp(addHTTPS(rawServerUrl.value))).trim()
})

/** @type {import('vue').Ref<'idle'|'loading'|'error'|'success'>} */
const state = ref('idle')
const state: Ref<'idle'|'loading'|'error'|'success'> = ref('idle')
const stateText = ref('')

/**
Expand All @@ -47,9 +47,9 @@ function setLoading() {

/**
* Switch state to error
* @param {string} error - Error message
* @param error - Error message
*/
function setError(error) {
function setError(error: string) {
state.value = 'error'
stateText.value = error
}
Expand Down Expand Up @@ -90,7 +90,7 @@ async function login() {
}

// Check versions compatibilities
const createVersionError = (componentName, minRequiredVersion, foundVersion) => t('talk_desktop', '{componentName} {minRequiredVersion} or higher is required but {foundVersion} is installed', {
const createVersionError = (componentName: string, minRequiredVersion: number, foundVersion: number) => t('talk_desktop', '{componentName} {minRequiredVersion} or higher is required but {foundVersion} is installed', {
componentName,
minRequiredVersion,
foundVersion,
Expand Down
2 changes: 1 addition & 1 deletion src/help/renderer/HelpApp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import MdiWindowClose from 'vue-material-design-icons/WindowClose.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'

import { translate as t } from '@nextcloud/l10n'
import { appData } from '../../app/AppData.js'
import { appData } from '../../app/AppData.ts'

const packageInfo = window.TALK_DESKTOP.packageInfo

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import '../../shared/assets/global.styles.css'

import Vue from 'vue'
import HelpApp from './HelpApp.vue'
import { setupWebPage } from '../../shared/setupWebPage.js'
import { setupWebPage } from '../../shared/setupWebPage.ts'

await setupWebPage()

Expand Down
24 changes: 0 additions & 24 deletions src/shared/globals/OC/dialogs.js

This file was deleted.

27 changes: 27 additions & 0 deletions src/shared/globals/OC/dialogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import Vue from 'vue'
import type OcDialogsAdapter from './OcDialogsAdapter.vue'

type OcDialogsAdapterInstance = InstanceType<typeof OcDialogsAdapter>

let ocDialogsAdapter: OcDialogsAdapterInstance | null = null

document.addEventListener('DOMContentLoaded', async () => {
const { default: OcDialogsAdapter } = await import('./OcDialogsAdapter.vue')

const container = document.body.appendChild(document.createElement('oc-dialog-wrapper'))

ocDialogsAdapter = new Vue(OcDialogsAdapter).$mount(container) as OcDialogsAdapterInstance
})

export const dialogs = {
YES_NO_BUTTONS: 70,
OK_BUTTONS: 71,
alert: (...args: Parameters<OcDialogsAdapterInstance['alert']>) => ocDialogsAdapter?.alert(...args),
confirm: (...args: Parameters<OcDialogsAdapterInstance['confirm']>) => ocDialogsAdapter?.confirm(...args),
confirmDestructive: (...args: Parameters<OcDialogsAdapterInstance['confirmDestructive']>) => ocDialogsAdapter?.confirmDestructive(...args),
}
File renamed without changes.
40 changes: 21 additions & 19 deletions src/shared/globals/globals.js → src/shared/globals/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,30 @@
import { ref } from 'vue'

import { loadState } from '@nextcloud/initial-state'
import { translate, translatePlural } from '@nextcloud/l10n'
import { t, n } from '@nextcloud/l10n'

import { appData } from '../../app/AppData.js'
import { appData } from '../../app/AppData.ts'
import { dialogs } from './OC/dialogs.js'
import { MimeTypeList } from './OC/mimetype.js'
import { MimeTypeList } from './OC/mimetype.ts'
import { getDesktopMediaSource } from '../../talk/renderer/getDesktopMediaSource.js'

let enabledAbsoluteWebroot = false

/**
* Run a function with an absolute webroot enabled to not rely on window.location
*
* @param {Function} func - the function to run
* @param {...any} args - the arguments to pass to the function
* @param func - the function to run
* @param args - the arguments to pass to the function
* @return {any} the result of the function's run
*/
function runWithAbsoluteWebroot(func, ...args) {
function runWithAbsoluteWebroot<T extends(...args: any[]) => any>(this: unknown, func: T, ...args: Parameters<T>): ReturnType<T> { // eslint-disable-line @typescript-eslint/no-explicit-any
enabledAbsoluteWebroot = true
const result = func.call(this, ...args)
const result: ReturnType<T> = func.apply(this, args)
enabledAbsoluteWebroot = false
return result
}

const getMaybeAbsoluteWebroot = () => enabledAbsoluteWebroot ? appData.serverUrl : new URL(appData.serverUrl).pathname
const getMaybeAbsoluteWebroot = () => enabledAbsoluteWebroot ? appData.serverUrl : new URL(appData.serverUrl!).pathname

const OC = {
// Constant from: https://github.com/nextcloud/server/blob/master/core/src/OC/constants.js
Expand All @@ -43,13 +43,15 @@ const OC = {
MimeTypeList,
MimeType: {
// TODO: better to move this function from global to @nextcloud/files or @nextcloud/router
getIconUrl(mimeType) {
if (!mimeType) {
getIconUrl(mimeType?: string) {
if (mimeType === undefined) {
return undefined
}

while (MimeTypeList.aliases[mimeType]) {
mimeType = MimeTypeList.aliases[mimeType]
let resolvedMimeType = mimeType

while (MimeTypeList.aliases[resolvedMimeType] !== undefined) {
resolvedMimeType = MimeTypeList.aliases[resolvedMimeType]
}

let icon = mimeType.replaceAll('/', '-')
Expand Down Expand Up @@ -83,24 +85,24 @@ const OC = {

theme: {
get productName() {
return loadState('theming', 'data').name
return loadState<{ name: string }>('theming', 'data').name
},
},

getHost() {
return new URL(appData.serverUrl).host
return new URL(appData.serverUrl!).host
},

getHostname() {
return new URL(appData.serverUrl).hostname
return new URL(appData.serverUrl!).hostname
},

getProtocol() {
return new URL(appData.serverUrl).protocol
return new URL(appData.serverUrl!).protocol
},

getPort() {
return new URL(appData.serverUrl).port
return new URL(appData.serverUrl!).port
},
}

Expand All @@ -125,8 +127,8 @@ const OCP = {
* Init global variables similar to Server
*/
export function initGlobals() {
window.t = translate
window.n = translatePlural
window.t = t
window.n = n

window.OC = OC
window.OCA = OCA
Expand Down
Loading

0 comments on commit 0903dbc

Please sign in to comment.