diff --git a/CHANGELOG.md b/CHANGELOG.md index 9343aa69..0fed0f52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### New Features +* Adding a help button on top of the chat, that links to the online documentation on frama.io. * Implementing the [FEP-1970](https://codeberg.org/fediverse/fep/src/branch/main/fep/1970/fep-1970.md) draft for ActivityPub chat declaration. * Podcast RSS feed support (thanks to [Alecks Gates](https://github.com/agates)). @@ -12,6 +13,8 @@ * Translation updates. * Documentation can now also be translated using [Weblate](https://weblate.framasoft.org/projects/peertube-livechat/peertube-plugin-livechat/). * Documentation can use hugo shortcode livechat_label to get application strings. +* Replaced github.io documentation links by frama.io documentation. +* Adding links to the documentation in the diagnostic tool. ## 7.1.0 diff --git a/assets/images/help.svg b/assets/images/help.svg new file mode 100644 index 00000000..573c3166 --- /dev/null +++ b/assets/images/help.svg @@ -0,0 +1,70 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/client/@types/global.d.ts b/client/@types/global.d.ts index 12454a93..04cdd6cc 100644 --- a/client/@types/global.d.ts +++ b/client/@types/global.d.ts @@ -3,6 +3,7 @@ declare const PLUGIN_CHAT_SHORT_NAME: string // Constants that begins with "LOC_" are loaded by build-client.js, reading the english locale file. // See the online documentation: https://johnxlivingston.github.io/peertube-plugin-livechat/contributing/translate/ +declare const LOC_ONLINE_HELP: string declare const LOC_OPEN_CHAT: string declare const LOC_OPEN_CHAT_NEW_WINDOW: string declare const LOC_CLOSE_CHAT: string diff --git a/client/settings.ts b/client/settings.ts index 12fdacfa..7a33dbad 100644 --- a/client/settings.ts +++ b/client/settings.ts @@ -1,6 +1,10 @@ interface MessageWithLevel { level: 'info' | 'warning' | 'error' message: string + help?: { + url: string + text: string + } } interface Result { @@ -63,8 +67,15 @@ function launchTests (): void { } else if (message.level === 'error') { messageSpan.style.color = 'red' } - messageSpan.textContent = message.message + messageSpan.textContent = message.message + ' ' // adding a space, in case there is a help button messageLi.append(messageSpan) + + if (message.help) { + const helpButton = document.createElement('a') + helpButton.href = message.help.url + helpButton.textContent = message.help.text + messageLi.append(helpButton) + } } messageUl.append(messageLi) } diff --git a/client/videowatch-client-plugin.ts b/client/videowatch-client-plugin.ts index 2620f70e..224c1ca5 100644 --- a/client/videowatch-client-plugin.ts +++ b/client/videowatch-client-plugin.ts @@ -1,8 +1,9 @@ import type { Video } from '@peertube/peertube-types' import type { RegisterClientOptions } from '@peertube/peertube-types/client' import { videoHasWebchat, videoHasRemoteWebchat } from 'shared/lib/video' +import { helpUrl } from 'shared/lib/help' import { logger } from './videowatch/logger' -import { closeSVG, openBlankChatSVG, openChatSVG, shareChatUrlSVG } from './videowatch/buttons' +import { closeSVG, openBlankChatSVG, openChatSVG, shareChatUrlSVG, helpButtonSVG } from './videowatch/buttons' import { displayButton, displayButtonOptions } from './videowatch/button' import { shareChatUrl } from './videowatch/share' import { getIframeUri } from './videowatch/uri' @@ -79,12 +80,14 @@ function register (registerOptions: RegisterClientOptions): void { peertubeHelpers.translate(LOC_OPEN_CHAT), peertubeHelpers.translate(LOC_OPEN_CHAT_NEW_WINDOW), peertubeHelpers.translate(LOC_CLOSE_CHAT), - peertubeHelpers.translate(LOC_SHARE_CHAT_LINK) + peertubeHelpers.translate(LOC_SHARE_CHAT_LINK), + peertubeHelpers.translate(LOC_ONLINE_HELP) ]).then(labels => { const labelOpen = labels[0] const labelOpenBlank = labels[1] const labelClose = labels[2] const labelShareUrl = labels[3] + const labelHelp = labels[4] const iframeUri = getIframeUri(registerOptions, settings, video) if (!iframeUri) { @@ -130,6 +133,17 @@ function register (registerOptions: RegisterClientOptions): void { additionalClasses: [] }) } + groupButtons.push({ + buttonContainer, + name: 'help', + label: labelHelp, + href: helpUrl({ + page: 'documentation/user/viewers' + }), + targetBlank: true, + icon: helpButtonSVG, + additionalClasses: [] + }) // If more than one groupButtons: // - the first must have class 'peertube-plugin-livechat-multi-button-main' diff --git a/client/videowatch/button.ts b/client/videowatch/button.ts index 7711f7e2..298ce1d5 100644 --- a/client/videowatch/button.ts +++ b/client/videowatch/button.ts @@ -1,38 +1,49 @@ import type { SVGButton } from './buttons' import { logger } from './logger' -interface displayButtonOptions { +interface displayButtonOptionsBase { buttonContainer: HTMLElement name: string label: string - callback: () => void | boolean icon?: SVGButton additionalClasses?: string[] } -function displayButton ({ - name, - label, - callback, - buttonContainer, - additionalClasses, - icon -}: displayButtonOptions): void { +interface displayButtonOptionsCallback extends displayButtonOptionsBase { + callback: () => void | boolean +} + +interface displayButtonOptionsHref extends displayButtonOptionsBase { + href: string + targetBlank?: boolean +} + +type displayButtonOptions = displayButtonOptionsCallback | displayButtonOptionsHref + +function displayButton (dbo: displayButtonOptions): void { const button = document.createElement('a') button.classList.add( 'orange-button', 'peertube-button-link', 'peertube-plugin-livechat-button', - 'peertube-plugin-livechat-button-' + name + 'peertube-plugin-livechat-button-' + dbo.name ) - if (additionalClasses) { - for (let i = 0; i < additionalClasses.length; i++) { - button.classList.add(additionalClasses[i]) + if (dbo.additionalClasses) { + for (let i = 0; i < dbo.additionalClasses.length; i++) { + button.classList.add(dbo.additionalClasses[i]) } } - button.onclick = callback - if (icon) { + if ('callback' in dbo) { + button.onclick = dbo.callback + } + if ('href' in dbo) { + button.href = dbo.href + } + if (('targetBlank' in dbo) && dbo.targetBlank) { + button.target = '_blank' + } + if (dbo.icon) { try { - const svg = icon() + const svg = dbo.icon() const tmp = document.createElement('span') tmp.innerHTML = svg.trim() const svgDom = tmp.firstChild @@ -40,14 +51,14 @@ function displayButton ({ button.prepend(svgDom) } } catch (err) { - logger.error('Failed to generate the ' + name + ' button: ' + (err as string)) + logger.error('Failed to generate the ' + dbo.name + ' button: ' + (err as string)) } - button.setAttribute('title', label) + button.setAttribute('title', dbo.label) } else { - button.textContent = label + button.textContent = dbo.label } - buttonContainer.append(button) + dbo.buttonContainer.append(button) } export type { diff --git a/client/videowatch/buttons.ts b/client/videowatch/buttons.ts index 09e794fc..dae35ca5 100644 --- a/client/videowatch/buttons.ts +++ b/client/videowatch/buttons.ts @@ -99,11 +99,24 @@ const shareChatUrlSVG: SVGButton = () => { ` } +const helpButtonSVG: SVGButton = () => { + // This content comes from the file assets/images/help.svg, after svgo cleaning. + // To get the formated content, you can do: + // xmllint dist/client/images/url.svg --format + // Then replace the color by `currentColor` + return ` + + + +` +} + export { closeSVG, openChatSVG, openBlankChatSVG, - shareChatUrlSVG + shareChatUrlSVG, + helpButtonSVG } export type { SVGButton diff --git a/languages/en.yml b/languages/en.yml index 5c5d60a5..feeb99f6 100644 --- a/languages/en.yml +++ b/languages/en.yml @@ -1,3 +1,4 @@ +online_help: "Help" open_chat: "Open chat" open_chat_new_window: "Open chat in a new window" close_chat: "Close chat" @@ -31,7 +32,7 @@ connect_using_xmpp_help: "You can connect to the room using an external XMPP acc important_note_title: "

Important notes

" important_note_text: | You can find the plugin documentation here: - + Peertube Plugin Livechat documentation . diff --git a/server/lib/diagnostic/index.ts b/server/lib/diagnostic/index.ts index 56a3ae06..92885998 100644 --- a/server/lib/diagnostic/index.ts +++ b/server/lib/diagnostic/index.ts @@ -4,6 +4,7 @@ import { TestResult, newResult } from './utils' import { diagDebug } from './debug' import { diagProsody } from './prosody' import { diagVideo } from './video' +import { helpUrl } from '../../../shared/lib/help' export async function diag (test: string, options: RegisterServerOptions): Promise { let result: TestResult @@ -16,6 +17,20 @@ export async function diag (test: string, options: RegisterServerOptions): Promi result = await diagVideo(test, options) } else if (test === 'prosody') { result = await diagProsody(test, options) + } else if (test === 'everything-ok') { + result = newResult(test) + result.label = 'Everything seems fine' + result.messages = [{ + level: 'info', + message: 'If you still encounter issues with the plugin, check this documentation page:', + help: { + text: 'Plugin troubleshooting', + url: helpUrl({ + page: 'documentation/installation/troubleshooting' + }) + } + }] + result.ok = true } else { result = newResult(test) result.messages.push('Unknown test') diff --git a/server/lib/diagnostic/prosody.ts b/server/lib/diagnostic/prosody.ts index 50d93be5..a91300a7 100644 --- a/server/lib/diagnostic/prosody.ts +++ b/server/lib/diagnostic/prosody.ts @@ -3,6 +3,7 @@ import { getProsodyConfig, getProsodyConfigContentForDiagnostic, getWorkingDir } import { checkProsody, getProsodyAbout, testProsodyCorrectlyRunning } from '../prosody/ctl' import { newResult, TestResult } from './utils' import { getAPIKey } from '../apikey' +import { helpUrl } from '../../../shared/lib/help' import * as fs from 'fs' const got = require('got') @@ -190,7 +191,16 @@ export async function diagProsody (test: string, options: RegisterServerOptions) if (testResult.ok === true) { result.messages.push('API Prosody -> Peertube is OK') } else { - result.messages.push('API Prosody -> Peertube is KO. Response was: ' + JSON.stringify(testResult)) + result.messages.push({ + level: 'error', + message: 'API Prosody -> Peertube is KO. Response was: ' + JSON.stringify(testResult), + help: { + text: 'Check the troubleshooting documentation.', + url: helpUrl({ + page: 'documentation/installation/troubleshooting' + }) + } + }) return result } } catch (error) { @@ -226,5 +236,6 @@ export async function diagProsody (test: string, options: RegisterServerOptions) } result.ok = true + result.next = 'everything-ok' return result } diff --git a/server/lib/diagnostic/utils.ts b/server/lib/diagnostic/utils.ts index a7ccbbaa..97aef41e 100644 --- a/server/lib/diagnostic/utils.ts +++ b/server/lib/diagnostic/utils.ts @@ -1,8 +1,12 @@ -type nextValue = 'backend' | 'debug' | 'webchat-video' | 'prosody' +type nextValue = 'backend' | 'debug' | 'webchat-video' | 'prosody' | 'everything-ok' interface MessageWithLevel { level: 'info' | 'warning' | 'error' message: string + help?: { + url: string + text: string + } } export interface TestResult { label?: string diff --git a/shared/lib/help.ts b/shared/lib/help.ts new file mode 100644 index 00000000..469da82a --- /dev/null +++ b/shared/lib/help.ts @@ -0,0 +1,17 @@ +function helpUrl (options: { + lang?: string + page?: string +}): string { + let url = 'https://livingston.frama.io/peertube-plugin-livechat/' + if (options.lang && /^[a-zA-Z_-]+$/.test(options.lang)) { + url = url + options.lang + '/' + } + if (options.page && /^[\w/-]+$/.test(options.page)) { + url = url + options.page + '/' + } + return url +} + +export { + helpUrl +}