Skip to content

Commit

Permalink
[ENG-4964] Addon cards (#2092)
Browse files Browse the repository at this point in the history
## Purpose
- Add addon-cards component to configure, enable, and disable addons

## Summary of Changes
- Update adapters, addons route page, and manager
- Add addons card component
  • Loading branch information
futa-ikeda authored Dec 19, 2023
1 parent 302d825 commit afabc86
Show file tree
Hide file tree
Showing 29 changed files with 355 additions and 17 deletions.
2 changes: 1 addition & 1 deletion app/adapters/addon-service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import config from 'ember-osf-web/config/environment';

const addonServiceUrl = config.OSF.url;
const { addonServiceUrl } = config.OSF;

export const addonServiceNamespace = 'v1';
export const addonServiceAPIUrl = `${addonServiceUrl}${addonServiceNamespace}/`;
Expand Down
3 changes: 0 additions & 3 deletions app/adapters/external-storage-service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import AddonServiceAdapter from './addon-service';

export default class ExternalStorageServiceAdapter extends AddonServiceAdapter {
pathForType() {
return 'storage_providers';
}
}

declare module 'ember-data/types/registries/adapter' {
Expand Down
3 changes: 3 additions & 0 deletions app/guid-node/addons/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import Route from '@ember/routing/route';

export default class GuidNodeAddons extends Route {
async model() {
return await this.modelFor('guid-node').taskInstance;
}
}
4 changes: 4 additions & 0 deletions app/guid-node/addons/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.addon-cards-wrapper {
display: flex;
flex-wrap: wrap;
}
11 changes: 10 additions & 1 deletion app/guid-node/addons/template.hbs
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
{{!-- List all providers to choose from here --}}
<AddonsService::Manager
@node={{this.model}}
as |manager|
>
<div local-class='addon-cards-wrapper'>
{{#each manager.addonProviders as |addon|}}
<AddonCard @addon={{addon}} @manager={{manager}} />
{{/each}}
</div>
</AddonsService::Manager>
56 changes: 56 additions & 0 deletions lib/osf-components/addon/components/addon-card/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';

import LegacyProvider from 'ember-osf-web/packages/addons-service/legacy-provider';
import Provider from 'ember-osf-web/packages/addons-service/provider';
import AddonsServiceManagerComponent from 'osf-components/components/addons-service/manager/component';

interface Args {
addon: LegacyProvider | Provider;
manager: AddonsServiceManagerComponent;
}

const legacyAddonLogoMap: Record<string, string> = {
aws: '/assets/images/addons/logos/aws.png',
bitbucket: '/assets/images/addons/logos/bitbucket.png',
boa: '/assets/images/addons/logos/boa_color.png',
dataverse: '/assets/images/addons/logos/dataverse.png',
dropbox: '/assets/images/addons/logos/dropbox.png',
figshare: '/assets/images/addons/logos/figshare.png',
github: '/assets/images/addons/logos/github.png',
gitlab: '/assets/images/addons/logos/gitlab.png',
googledrive: '/assets/images/addons/logos/google.png',
mendeley: '/assets/images/addons/logos/mendeley.png',
onedrive: '/assets/images/addons/logos/onedrive.png',
owncloud: '/assets/images/addons/logos/owncloud.png',
zotero: '/assets/images/addons/logos/zotero.png',
};

export default class AddonsCardComponent extends Component<Args> {
@tracked deleteModalOpen = false;

@action
closeDeleteModal() {
this.deleteModalOpen = false;
}

@action
disableAddon() {
const { addon } = this.args;
addon.disableProjectAddon();
}

get assetLogo() {
if (this.args.addon instanceof LegacyProvider) {
return legacyAddonLogoMap[this.args.addon.provider.id];
} else {
return this.args.addon.provider.iconUri;
}
}

get addonIsConfigured() {
const { addon, manager } = this.args;
return manager.projectEnabledAddons.includes(addon);
}
}
47 changes: 47 additions & 0 deletions lib/osf-components/addon/components/addon-card/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.card-wrapper {
min-width: 208px;
border: solid 1px $color-border-gray;
margin: 5px 3px;
padding: 20px;
text-align: center;
}

.addon-card-logo {
height: 36px;
}

.provider-name {
font-weight: bold;
margin: 15px 0;
}

.button-looking-links {
composes: Button from '../button/styles.scss';
composes: MediumButton from '../button/styles.scss';
composes: SecondaryButton from '../button/styles.scss';
}

.buttons-wrapper {
display: flex;
justify-content: center;

.enable {
color: darken($brand-success, 10%);
}

.configure {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}

.disable {
color: darken($brand-danger, 10%);
border-left: 0;
border-bottom-left-radius: 0;
border-top-left-radius: 0;

&:hover {
text-decoration: underline;
}
}
}
85 changes: 85 additions & 0 deletions lib/osf-components/addon/components/addon-card/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<div
local-class='card-wrapper'
data-test-addon-card={{@addon.provider.name}}
data-analytics-scope={{concat 'Addon card' @addon.provider.name}}
>
<img
data-test-addon-card-logo
src={{this.assetLogo}}
alt={{t 'osf-components.addon-card.provider-logo-alt' provider=@addon.provider.name}}
local-class='addon-card-logo'
/>
<div
data-test-addon-card-title
local-class='provider-name'
>
{{@addon.provider.name}}
</div>

<div local-class='buttons-wrapper'>
{{#if this.addonIsConfigured}}
<OsfLink
data-test-addon-card-configure
data-analytics-name='Configure'
local-class='button-looking-links configure'
@route='guid-node.addons.addon.configure'
@models={{array @manager.node.id @addon.provider.id}}
>
{{t 'osf-components.addon-card.configure'}}
</OsfLink>
<Button
data-test-addon-card-disable
data-analytics-name='Disable'
local-class='disable'
{{on 'click' (action (mut this.deleteModalOpen) true)}}
>
{{t 'osf-components.addon-card.disable'}}
</Button>
{{else}}
<OsfLink
data-test-addon-card-enable
data-analytics-name='Enable'
local-class='button-looking-links enable'
@route='guid-node.addons.addon.terms'
@models={{array @manager.node.id @addon.provider.id}}
>
{{t 'osf-components.addon-card.enable'}}
</OsfLink>
{{/if}}
</div>
</div>
{{#if this.addonIsConfigured}}
<OsfDialog
@isOpen={{this.deleteModalOpen}}
@onClose={{action this.closeDeleteModal}}
as |dialog|
>
<dialog.heading>
{{t 'osf-components.addon-card.disable-modal-header'}}
</dialog.heading>
<dialog.main>
<p>
{{t 'osf-components.addon-card.disable-modal-body'}}
</p>
</dialog.main>
<dialog.footer data-analytics-scope='Disable addon modal'>
<Button
data-test-addon-disable-cancel
data-analytics-name='Cancel'
@type='secondary'
{{on 'click' dialog.close}}
>
{{t 'general.cancel'}}
</Button>
<Button
data-test-addon-disable-modal-disable
data-analytics-name='Disable'
@type='destroy'
{{on 'click' (queue this.disableAddon dialog.close)}}
>
{{t 'osf-components.addon-card.disable'}}
</Button>
</dialog.footer>
</OsfDialog>
{{/if}}

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { inject as service } from '@ember/service';
import { waitFor } from '@ember/test-waiters';
import Store from '@ember-data/store';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import { taskFor } from 'ember-concurrency-ts';

import NodeModel from 'ember-osf-web/models/node';
import LegacyProvider from 'ember-osf-web/packages/addons-service/legacy-provider';
Expand All @@ -19,31 +21,49 @@ export default class AddonsServiceManagerComponent extends Component<Args> {

node = this.args.node;

@tracked addonProviders: Array<LegacyProvider | Provider> = [];

constructor(owner: unknown, args: Args) {
super(owner, args);
taskFor(this.getAddonProviders).perform();
}

@task
@waitFor
async addonProviders(): Promise<(Array<LegacyProvider | Provider>)> {
const legacyProviders: LegacyProvider[] = await this.legacyProviders();
async getAddonProviders() {
const legacyProviders: LegacyProvider[] = await taskFor(this.legacyProviders).perform();
const serviceStorageProviders: Provider[] = this.serviceStorageProviders();

return [...legacyProviders, ...serviceStorageProviders]
const providers = [...legacyProviders, ...serviceStorageProviders]
.sort(this.providerSorter);
this.addonProviders = providers;
}

providerSorter(a: Provider, b: Provider) {
return a.provider.name.localeCompare(b.provider.name);
}

get projectEnabledAddons(): Array<LegacyProvider | Provider> {
const legacyAddons = this.legacyProjectEnabledAddons();
const serviceAddons = this.serviceProjectEnabledAddons();
return [...legacyAddons, ...serviceAddons];
}

// V2 API Methods

@task
@waitFor
async legacyProviders() {
const addons = await this.store.findAll('addon');
const addons = (await this.store.findAll('addon')).toArray();
const legacyAddons = [] as LegacyProvider[];
for (const addon of addons) {
legacyAddons.addObject(new LegacyProvider(addon, this.currentUser, this.node));
}
return addons;
return legacyAddons;
}

get isLoading() {
return taskFor(this.getAddonProviders).isRunning;
}

legacyProjectEnabledAddons() {
Expand All @@ -58,6 +78,6 @@ export default class AddonsServiceManagerComponent extends Component<Args> {
}

serviceProjectEnabledAddons() {
return;
return [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{yield (hash
node=this.node
addonProviders=this.addonProviders
loading=this.loading
projectEnabledAddons=this.projectEnabledAddons
)}}
1 change: 1 addition & 0 deletions lib/osf-components/app/components/addon-card/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'osf-components/components/addon-card/component';
1 change: 1 addition & 0 deletions lib/osf-components/app/components/addon-card/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'osf-components/components/addon-card/template';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'osf-components/components/addons-service/manager/template';
12 changes: 6 additions & 6 deletions mirage/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,12 +427,12 @@ export default function(this: Server) {
// Addon service
this.urlPrefix = addonServiceUrl;
this.namespace = addonServiceNamespace;
this.resource('external_storage_services', { only: ['index', 'show'] });
this.resource('internal_users', { only: ['show'] });
this.get('/internal_users/:userGuid/authorized_storage_accounts/', addons.internalUserAuthorizedStorageAccountList);
this.resource('internal_resources', { only: ['show'] });
this.resource('authorized_storage_accounts', { only: ['show', 'update'] });
this.resource('configured_storage_addons', { only: ['show', 'update'] });
this.resource('external-storage-services', { only: ['index', 'show'] });
this.resource('internal-users', { only: ['show'] });
this.get('/internal-users/:userGuid/authorized-storage-accounts/', addons.internalUserAuthorizedStorageAccountList);
this.resource('internal-resources', { only: ['show'] });
this.resource('authorized-storage-accounts', { only: ['show', 'update'] });
this.resource('configured-storage-addons', { only: ['show', 'update'] });

// Reset API url and namespace to use v2 endpoints for tests
this.urlPrefix = apiUrl;
Expand Down
Binary file added public/assets/images/addons/logos/aws.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/bitbucket.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/boa_color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/dataverse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/dropbox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/figshare.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/github.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/gitlab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/google.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/mendeley.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/onedrive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/owncloud.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/addons/logos/zotero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit afabc86

Please sign in to comment.