diff --git a/__tests__/unit/components/Plugin/PluginWrapper.spec.js b/__tests__/unit/components/Plugin/PluginWrapper.spec.js new file mode 100644 index 0000000000..7299d6fdbf --- /dev/null +++ b/__tests__/unit/components/Plugin/PluginWrapper.spec.js @@ -0,0 +1,89 @@ +import { createLocalVue, mount } from '@vue/test-utils' +import PluginWrapper from '@/components/Plugin/PluginWrapper' +import { Wormhole } from 'portal-vue' + +const vue = createLocalVue() + +jest.mock('portal-vue', () => ({ + Wormhole: { + open: jest.fn(), + close: jest.fn() + } +})) + +describe('PluginWrapper', () => { + const mountComponent = config => { + return mount(PluginWrapper, config) + } + + describe('when there is a footer slot', () => { + it('should open a Wormhole when mounted', done => { + const spy = jest.spyOn(Wormhole, 'open') + + const wrapper = mountComponent({ + slots: { + footer: '
' + } + }) + + vue.nextTick(() => { + expect(spy).toHaveBeenCalledWith({ + to: 'plugin-footer', + from: 'plugin-wrapper', + passengers: wrapper.vm.footerSlot + }) + done() + }) + + spy.mockRestore() + }) + + it('should close a Wormhole when destroyed', done => { + const spy = jest.spyOn(Wormhole, 'close') + + mountComponent({ + slots: { + footer: '' + } + }).destroy() + + vue.nextTick(() => { + expect(spy).toHaveBeenCalledWith({ + to: 'plugin-footer', + from: 'plugin-wrapper' + }) + done() + }) + + spy.mockRestore() + }) + }) + + describe('when there is no footer slot', () => { + it('should not open a Wormhole when mounted', done => { + const spy = jest.spyOn(Wormhole, 'open') + + mountComponent() + + vue.nextTick(() => { + expect(spy).not.toHaveBeenCalled() + done() + }) + + spy.mockRestore() + }) + + it('should not close a Wormhole when destroyed', done => { + const spy = jest.spyOn(Wormhole, 'close') + + mountComponent().destroy() + + vue.nextTick(() => { + expect(spy).not.toHaveBeenCalled() + done() + }) + + spy.mockRestore() + }) + }) +}) diff --git a/__tests__/unit/services/plugin-manager.spec.js b/__tests__/unit/services/plugin-manager.spec.js index 70f2292c0c..7efee55033 100644 --- a/__tests__/unit/services/plugin-manager.spec.js +++ b/__tests__/unit/services/plugin-manager.spec.js @@ -48,6 +48,7 @@ const app = { getters: { 'plugin/isEnabled': jest.fn((pluginId) => pluginId === 'plugin-test'), 'plugin/isInstalledSupported': jest.fn(() => true), + 'plugin/isGrant': jest.fn(() => true), 'plugin/lastFetched': jest.fn(() => 0), 'profile/byId': jest.fn(() => {}), 'session/pluginAdapter': 'npm' @@ -93,14 +94,14 @@ describe('Plugin Manager', () => { name: 'test-plugin-1', keywords: PLUGINS.keywords, 'desktop-wallet': { - minVersion: '1.0' + minimumVersion: '1.0' } } const invalidPlugin = { name: 'test-plugin-2', keywords: PLUGINS.keywords, 'desktop-wallet': { - minVersion: '3.0' + minimumVersion: '3.0' } } @@ -241,40 +242,19 @@ describe('Plugin Manager', () => { }) }) - describe('fetchBlacklist', () => { + describe('fetchPluginsList', () => { it('should fetch using cache-busted url', async () => { const spy = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(1234) const spyError = jest.spyOn(console, 'error') nock('https://raw.githubusercontent.com') - .get('/ark-ecosystem-desktop-plugins/config/master/blacklist.json') + .get('/ark-ecosystem-desktop-plugins/config/master/plugins.json') .query({ ts: 1234 }) .reply(200, []) - await pluginManager.fetchBlacklist() - - expect(spyError).not.toHaveBeenCalled() - - spy.mockRestore() - spyError.mockRestore() - }) - }) - - describe('fetchWhitelist', () => { - it('should fetch using cache-busted url', async () => { - const spy = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(1234) - const spyError = jest.spyOn(console, 'error') - - nock('https://raw.githubusercontent.com') - .get('/ark-ecosystem-desktop-plugins/config/master/whitelist.json') - .query({ - ts: 1234 - }) - .reply(200, []) - - await pluginManager.fetchWhitelist() + await pluginManager.fetchPluginsList() expect(spyError).not.toHaveBeenCalled() diff --git a/__tests__/unit/store/modules/plugin.spec.js b/__tests__/unit/store/modules/plugin.spec.js index 61df466f3e..d59a9faa24 100644 --- a/__tests__/unit/store/modules/plugin.spec.js +++ b/__tests__/unit/store/modules/plugin.spec.js @@ -148,7 +148,9 @@ describe('PluginModule', () => { }, whitelisted: { global: { - [availablePlugins[0].config.id]: availablePlugins[0].config.version + [availablePlugins[0].config.id]: { + version: availablePlugins[0].config.version + } } } } @@ -203,8 +205,12 @@ describe('PluginModule', () => { }, whitelisted: { global: { - [plugin1.config.id]: plugin1.config.version, - [plugin2.config.id]: plugin2.config.version + [plugin1.config.id]: { + version: plugin1.config.version + }, + [plugin2.config.id]: { + version: plugin2.config.version + } } } } @@ -242,8 +248,12 @@ describe('PluginModule', () => { }, whitelisted: { global: { - [plugin1.config.id]: plugin1.config.version, - [plugin2.config.id]: plugin2.config.version + [plugin1.config.id]: { + version: plugin1.config.version + }, + [plugin2.config.id]: { + version: plugin2.config.version + } } } } @@ -282,8 +292,12 @@ describe('PluginModule', () => { }, whitelisted: { global: { - [plugin1.config.id]: plugin1.config.version, - [plugin2.config.id]: plugin2.config.version + [plugin1.config.id]: { + version: plugin1.config.version + }, + [plugin2.config.id]: { + version: plugin2.config.version + } } } } @@ -626,7 +640,9 @@ describe('PluginModule', () => { store.dispatch('plugin/setWhitelisted', { scope: 'global', plugins: { - [availablePlugins[0].config.id]: availablePlugins[0].config.version + [availablePlugins[0].config.id]: { + version: availablePlugins[0].config.version + } } }) }) @@ -656,6 +672,39 @@ describe('PluginModule', () => { }) }) + describe('isGrant', () => { + beforeAll(() => { + store.replaceState(JSON.parse(JSON.stringify(initialState))) + + store.dispatch('plugin/setWhitelisted', { + scope: 'global', + plugins: { + [availablePlugins[0].config.id]: { + isGrant: true, + version: availablePlugins[0].config.version + }, + [availablePlugins[1].config.id]: { + version: availablePlugins[1].config.version + } + } + }) + }) + + it('should return true if the plugin is whitelisted and is a funded by ark grants', () => { + const pluginId = availablePlugins[0].config.id + expect(store.getters['plugin/isGrant'](pluginId)).toBe(true) + }) + + it('should return false if the plugin is whitelisted and is a not funded by ark grants', () => { + const pluginId = availablePlugins[1].config.id + expect(store.getters['plugin/isGrant'](pluginId)).toBe(false) + }) + + it('should return false if the plugin is not whitelisted and is a not funded by ark grants', () => { + expect(store.getters['plugin/isGrant']('plugin-not-grants')).toBe(false) + }) + }) + describe('isInstalledSupported', () => { let spy @@ -677,7 +726,7 @@ describe('PluginModule', () => { store.dispatch('plugin/setInstalled', { config: { ...installedPlugins[0].config, - minVersion: '1.0.0' + minimumVersion: '1.0.0' } }) expect(store.getters['plugin/isInstalledSupported'](installedPlugins[0].config.id)).toBe(true) @@ -687,7 +736,7 @@ describe('PluginModule', () => { store.dispatch('plugin/setInstalled', { config: { ...installedPlugins[0].config, - minVersion: '3.0.0' + minimumVersion: '3.0.0' } }) expect(store.getters['plugin/isInstalledSupported'](installedPlugins[0].config.id)).toBe(false) diff --git a/config/index.js b/config/index.js index 70e47f540b..2ccf516d39 100644 --- a/config/index.js +++ b/config/index.js @@ -115,8 +115,7 @@ exports.MARKET = { exports.PLUGINS = { adapters: ['npm'], - blacklistUrl: 'https://raw.githubusercontent.com/ark-ecosystem-desktop-plugins/config/master/blacklist.json', - whitelistUrl: 'https://raw.githubusercontent.com/ark-ecosystem-desktop-plugins/config/master/whitelist.json', + pluginsUrl: 'https://raw.githubusercontent.com/ark-ecosystem-desktop-plugins/config/master/plugins.json', categories: [ 'gaming', 'theme', diff --git a/src/renderer/App.vue b/src/renderer/App.vue index ce9fdcb050..37ed7a2ca0 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -332,7 +332,7 @@ export default { ipcRenderer.send('splashscreen:app-ready') - await Promise.all([this.$plugins.fetchPluginsFromAdapter(), this.$plugins.fetchBlacklist(), this.$plugins.fetchWhitelist()]) + await Promise.all([this.$plugins.fetchPluginsFromAdapter(), this.$plugins.fetchPluginsList()]) }, __watchProfile () { diff --git a/src/renderer/assets/svg/ark-checkmark.svg b/src/renderer/assets/svg/ark-checkmark.svg new file mode 100644 index 0000000000..af7966e73b --- /dev/null +++ b/src/renderer/assets/svg/ark-checkmark.svg @@ -0,0 +1,23 @@ + + + diff --git a/src/renderer/assets/svg/ark-grants.svg b/src/renderer/assets/svg/ark-grants.svg new file mode 100644 index 0000000000..15691da21e --- /dev/null +++ b/src/renderer/assets/svg/ark-grants.svg @@ -0,0 +1,25 @@ + + + diff --git a/src/renderer/components/Plugin/PluginWrapper.vue b/src/renderer/components/Plugin/PluginWrapper.vue index 75d9a80ce4..9fd5952418 100644 --- a/src/renderer/components/Plugin/PluginWrapper.vue +++ b/src/renderer/components/Plugin/PluginWrapper.vue @@ -3,14 +3,30 @@ import { Wormhole } from 'portal-vue' export default { name: 'PluginWrapper', + computed: { + footerSlot () { + return this.$slots.footer + } + }, + mounted () { - const footerSlot = this.$slots.footer - if (footerSlot) { + if (this.footerSlot) { this.$nextTick(() => { Wormhole.open({ to: 'plugin-footer', from: 'plugin-wrapper', - passengers: footerSlot + passengers: this.footerSlot + }) + }) + } + }, + + beforeDestroy () { + if (this.footerSlot) { + this.$nextTick(() => { + Wormhole.close({ + to: 'plugin-footer', + from: 'plugin-wrapper' }) }) } diff --git a/src/renderer/components/PluginManager/PluginManagerCheckmark.vue b/src/renderer/components/PluginManager/PluginManagerCheckmark.vue index aae6bf6906..828e681ae1 100644 --- a/src/renderer/components/PluginManager/PluginManagerCheckmark.vue +++ b/src/renderer/components/PluginManager/PluginManagerCheckmark.vue @@ -7,8 +7,8 @@ class="PluginManagerCheckmark" >