plugin-manager.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. const api = window.dshDesktop
  2. async function main() {
  3. const locale = await api.locale()
  4. const messages = locale.messages
  5. const message = (key, values = {}) => messages[key].replaceAll(/\{([^{}]+)\}/gu, (placeholder, name) => values[name] ?? placeholder)
  6. document.documentElement.lang = locale.id
  7. document.querySelector('#page-title').textContent = messages.pluginManagerTitle
  8. document.querySelector('#title').textContent = messages.pluginManagerTitle
  9. document.querySelector('#description').textContent = messages.pluginManagerDescription
  10. document.querySelector('#refresh').textContent = messages.refresh
  11. document.querySelector('#package-label').textContent = messages.npmPackage
  12. document.querySelector('#install').textContent = messages.install
  13. document.querySelector('#installed-heading').textContent = messages.installed
  14. document.querySelector('#empty').textContent = messages.noPlugins
  15. const list = document.querySelector('#plugins')
  16. const empty = document.querySelector('#empty')
  17. const status = document.querySelector('#status')
  18. const form = document.querySelector('#install-form')
  19. const input = document.querySelector('#package-spec')
  20. const refresh = document.querySelector('#refresh')
  21. function setBusy(busy, statusMessage = '') {
  22. for (const control of document.querySelectorAll('button, input')) control.disabled = busy
  23. status.textContent = statusMessage
  24. }
  25. async function render() {
  26. const plugins = await api.plugins.list()
  27. list.replaceChildren(...plugins.map(plugin => {
  28. const item = document.createElement('li')
  29. const identity = document.createElement('span')
  30. const version = document.createElement('span')
  31. version.className = 'package-version'
  32. version.textContent = plugin.version
  33. identity.append(document.createTextNode(plugin.name), version)
  34. const remove = document.createElement('button')
  35. remove.type = 'button'
  36. remove.textContent = messages.remove
  37. remove.addEventListener('click', () => void run(
  38. () => api.plugins.remove(plugin.name),
  39. message('removing', { name: plugin.name }),
  40. ))
  41. const update = document.createElement('button')
  42. update.type = 'button'
  43. update.textContent = messages.update
  44. update.addEventListener('click', () => {
  45. const next = window.prompt(message('targetVersion', { name: plugin.name }), plugin.version)?.trim()
  46. if (next === undefined || next === '' || next === plugin.version) return
  47. void run(() => api.plugins.update(plugin.name, next), message('updating', { name: plugin.name }))
  48. })
  49. const actions = document.createElement('span')
  50. actions.className = 'package-actions'
  51. actions.append(update, remove)
  52. item.append(identity, actions)
  53. return item
  54. }))
  55. empty.hidden = plugins.length !== 0
  56. }
  57. async function run(operation, statusMessage) {
  58. setBusy(true, statusMessage)
  59. try {
  60. await operation()
  61. await render()
  62. status.textContent = messages.operationComplete
  63. } catch (error) {
  64. status.textContent = error instanceof Error ? error.message : String(error)
  65. } finally {
  66. setBusy(false, status.textContent)
  67. }
  68. }
  69. async function load(statusMessage, success) {
  70. setBusy(true, statusMessage)
  71. try {
  72. await render()
  73. status.textContent = success
  74. } catch (error) {
  75. status.textContent = error instanceof Error ? error.message : String(error)
  76. } finally {
  77. setBusy(false, status.textContent)
  78. }
  79. }
  80. form.addEventListener('submit', (event) => {
  81. event.preventDefault()
  82. const spec = input.value.trim()
  83. if (spec === '') return
  84. void run(async () => {
  85. await api.plugins.add(spec)
  86. input.value = ''
  87. }, message('installing', { spec }))
  88. })
  89. refresh.addEventListener('click', () => void load(messages.refreshing, messages.refreshed))
  90. await load(messages.loadingPlugins, '')
  91. }
  92. void main()