Skip to content

Commit

Permalink
authentication and manual review dlow completed, next is to complete,…
Browse files Browse the repository at this point in the history
… explorer, install/uninstall flags etc
  • Loading branch information
roncodes committed Mar 22, 2024
1 parent 5807453 commit 9aed538
Show file tree
Hide file tree
Showing 43 changed files with 1,886 additions and 249 deletions.
187 changes: 187 additions & 0 deletions addon/components/extension-form.hbs

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions addon/components/extension-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';

export default class ExtensionFormComponent extends Component {
@service store;
@service fetch;
@service notifications;
@service intl;
@tracked subscriptionModelOptions = ['flat_rate', 'tiered', 'usage'];
@tracked billingPeriodOptions = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'];
@tracked uploadQueue = [];
acceptedImageTypes = ['image/jpeg', 'image/png', 'image/gif'];
acceptedBundleTypes = [
'application/zip',
'application/x-zip',
'application/x-zip-compressed',
'application/x-compressed',
'multipart/x-zip',
'application/x-tar',
'application/gzip',
'application/x-gzip',
'application/x-tgz',
'application/x-bzip2',
'application/x-xz',
];

@task *uploadIcon(file) {
const { extension, onIconUploaded } = this.args;

yield this.fetch.uploadFile.perform(
file,
{
path: `uploads/extensions/${extension.id}/icons`,
subject_uuid: extension.id,
subject_type: 'registry-bridge:registry-extension',
type: 'extension_icon',
},
(uploadedFile) => {
extension.setProperties({
icon: uploadedFile,
icon_uuid: uploadedFile.id,
icon_url: uploadedFile.url,
});

if (typeof onIconUploaded === 'function') {
onIconUploaded(uploadedFile);
}

return extension.save();
}
);
}

@task *uploadBundle(file) {
const { extension, onBundleUploaded } = this.args;

yield this.fetch.uploadFile.perform(
file,
{
path: `uploads/extensions/${this.args.extension.id}/bundles`,
subject_uuid: this.args.extension.id,
subject_type: 'registry-bridge:registry-extension',
type: 'extension_bundle',
meta: {
version: this.args.extension.version,
},
},
(uploadedFile) => {
extension.setProperties({
latest_bundle: uploadedFile,
latest_bundle_uuid: uploadedFile.id,
latest_bundle_filename: uploadedFile.original_filename,
});

if (typeof onBundleUploaded === 'function') {
onBundleUploaded(uploadedFile);
}

return extension.save();
}
);
}

@action queueFile(file) {
// since we have dropzone and upload button within dropzone validate the file state first
// as this method can be called twice from both functions
if (['queued', 'failed', 'timed_out', 'aborted'].indexOf(file.state) === -1) {
return;
}

const { extension, onScreenshotUploaded } = this.args;

// Queue and upload immediatley
this.uploadQueue.pushObject(file);
this.fetch.uploadFile.perform(
file,
{
path: `uploads/extensions/${this.args.extension.id}/screenshots`,
subject_uuid: this.args.extension.id,
subject_type: 'registry-bridge:registry-extension',
type: 'extension_screenshot',
},
(uploadedFile) => {
extension.screenshots.pushObject(uploadedFile);
this.uploadQueue.removeObject(file);
if (typeof onScreenshotUploaded === 'function') {
onScreenshotUploaded(uploadedFile);
}
},
() => {
this.uploadQueue.removeObject(file);
// remove file from queue
if (file.queue && typeof file.queue.remove === 'function') {
file.queue.remove(file);
}
}
);
}

@action removeFile(file) {
return file.destroyRecord();
}
}
40 changes: 40 additions & 0 deletions addon/components/extension-pending-publish-viewer.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<div class="space-y-4">
<ContentPanel @title={{t "registry-bridge.component.extension-pending-publish-viewer.content-panel-title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<div class="grid grid-cols-1 lg:grid-cols-4">
{{#each this.extensions as |extension|}}
<div class="flex flex-col">
<button type="button" class="rounded-lg border border-gray-200 dark:border-gray-700 shadow-sm w-full hover:opacity-50" {{on "click" (fn this.focusExtension extension)}}>
<div class="flex items-center justify-center rounded-t-lg w-full h-36" {{background-url extension.icon_url overlay=true}}>
<Image src={{extension.icon_url}} class="w-full h-36 rounded-t-lg" alt={{extension.name}} @fallbackSrc={{config "defaultValues.extensionIcon"}} />
</div>
<div class="text-left px-3 py-2 rounded-b-lg bg-white border-t border-gray-200 dark:border-gray-700 dark:bg-gray-900">
<span class="font-semibold text-sm block">{{extension.name}}</span>
<p class="text-xs">{{n-a extension.description}}</p>
<div>
<Badge @status={{extension.status}} />
</div>
</div>
</button>
<div class="space-y-2 mt-3">
<Button @size="sm" @icon="clipboard-list" @text={{t "registry-bridge.component.extension-pending-publish-viewer.view-details"}} @onClick={{fn this.focusExtension extension}} class="w-full" />
<Button @size="sm" @icon="download" @text={{t "registry-bridge.component.extension-pending-publish-viewer.download-bundle"}} @onClick={{perform this.downloadBundle extension}} class="w-full" />
</div>
</div>
{{else}}
<div class="col-span-4">
<div class="text-base italic">{{t "registry-bridge.component.extension-pending-publish-viewer.no-extensions-awaiting-publish"}}</div>
</div>
{{/each}}
</div>
</ContentPanel>

{{#if this.focusedExtension}}
<ContentPanel @title={{t "registry-bridge.component.extension-pending-publish-viewer.focused-extension-title" extensionName=this.focusedExtension.name}} @open={{true}} @pad={{true}}>
<div class="flex items-center mb-4 px-1">
<Button @type="primary" @size="sm" @icon="check" @text={{t "common.done"}} @onClick={{this.unfocusExtension}} class="w-full" />
</div>
<ExtensionForm @extension={{this.focusedExtension}} />
</ContentPanel>
{{/if}}
</div>
<Spacer @height="400px" />
37 changes: 37 additions & 0 deletions addon/components/extension-pending-publish-viewer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';

export default class ExtensionPendingPublishViewerComponent extends Component {
@service store;
@service notifications;
@tracked extensions = [];
@tracked focusedExtension;

constructor() {
super(...arguments);
this.getExtensionsPendingPublish.perform();
}

@task *getExtensionsPendingPublish() {
this.extensions = yield this.store.query('registry-extension', { status: 'approved' });
}

@task *downloadBundle(extension) {
try {
yield extension.downloadBundle();
} catch (error) {
this.notifications.error(error.message);
}
}

@action focusExtension(extension) {
this.focusedExtension = extension;
}

@action unfocusExtension() {
this.focusedExtension = undefined;
}
}
42 changes: 42 additions & 0 deletions addon/components/extension-reviewer-control.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div class="space-y-4">
<ContentPanel @title={{t "registry-bridge.component.extension-reviewer-control.content-panel-title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<div class="grid grid-cols-1 lg:grid-cols-4">
{{#each this.extensions as |extension|}}
<div class="flex flex-col">
<button type="button" class="rounded-lg border border-gray-200 dark:border-gray-700 shadow-sm w-full hover:opacity-50" {{on "click" (fn this.focusExtension extension)}}>
<div class="flex items-center justify-center rounded-t-lg w-full h-36" {{background-url extension.icon_url overlay=true}}>
<Image src={{extension.icon_url}} class="w-full h-36 rounded-t-lg" alt={{extension.name}} @fallbackSrc={{config "defaultValues.extensionIcon"}} />
</div>
<div class="text-left px-3 py-2 rounded-b-lg bg-white border-t border-gray-200 dark:border-gray-700 dark:bg-gray-900">
<span class="font-semibold text-sm block">{{extension.name}}</span>
<p class="text-xs">{{n-a extension.description}}</p>
<div>
<Badge @status={{extension.status}} />
</div>
</div>
</button>
<div class="space-y-2 mt-3">
<Button @size="sm" @icon="clipboard-list" @text={{t "registry-bridge.component.extension-reviewer-control.view-details"}} @onClick={{fn this.focusExtension extension}} class="w-full" />
<Button @size="sm" @icon="download" @text={{t "registry-bridge.component.extension-reviewer-control.download-bundle"}} @onClick={{perform this.downloadBundle extension}} class="w-full" />
<Button @type="success" @size="sm" @icon="check" @text={{t "registry-bridge.component.extension-reviewer-control.approve"}} @onClick={{fn this.approve extension}} class="w-full" />
<Button @type="danger" @size="sm" @icon="ban" @text={{t "registry-bridge.component.extension-reviewer-control.reject"}} @onClick={{fn this.reject extension}} class="w-full" />
</div>
</div>
{{else}}
<div class="col-span-4">
<div class="text-base italic">{{t "registry-bridge.component.extension-reviewer-control.no-extensions-awaiting-review"}}</div>
</div>
{{/each}}
</div>
</ContentPanel>

{{#if this.focusedExtension}}
<ContentPanel @title={{t "registry-bridge.component.extension-reviewer-control.focused-extension-title" extensionName=this.focusedExtension.name}} @open={{true}} @pad={{true}}>
<div class="flex items-center mb-4 px-1">
<Button @type="primary" @size="sm" @icon="check" @text={{t "common.done"}} @onClick={{this.unfocusExtension}} class="w-full" />
</div>
<ExtensionForm @extension={{this.focusedExtension}} />
</ContentPanel>
{{/if}}
</div>
<Spacer @height="400px" />
67 changes: 67 additions & 0 deletions addon/components/extension-reviewer-control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';

export default class ExtensionReviewerControlComponent extends Component {
@service store;
@service modalsManager;
@service notifications;
@service intl;
@tracked extensions = [];
@tracked focusedExtension;

constructor() {
super(...arguments);
this.getExtensionsPendingReview.perform();
}

@task *getExtensionsPendingReview() {
this.extensions = yield this.store.query('registry-extension', { status: 'awaiting_review' });
}

@task *downloadBundle(extension) {
try {
yield extension.downloadBundle();
} catch (error) {
this.notifications.error(error.message);
}
}

@action focusExtension(extension) {
this.focusedExtension = extension;
}

@action unfocusExtension() {
this.focusedExtension = undefined;
}

@action approve(extension) {
return this.modalsManager.confirm({
title: this.intl.t('registry-bridge.component.extension-reviewer-control.approve-confirm-title', { extensionName: extension.name }),
body: this.intl.t('registry-bridge.component.extension-reviewer-control.approve-confirm-body'),
acceptButtonText: this.intl.t('registry-bridge.component.extension-reviewer-control.approve'),
confirm: () => {
return extension.approve().finally(() => {
this.getExtensionsPendingReview.perform();
});
},
});
}

@action reject(extension) {
return this.modalsManager.confirm({
title: this.intl.t('registry-bridge.component.extension-reviewer-control.decline-confirm-title', { extensionName: extension.name }),
body: this.intl.t('registry-bridge.component.extension-reviewer-control.decline-confirm-body'),
acceptButtonText: this.intl.t('registry-bridge.component.extension-reviewer-control.reject'),
acceptButtonIcon: 'ban',
acceptButtonScheme: 'danger',
confirm: () => {
return extension.reject().finally(() => {
this.getExtensionsPendingReview.perform();
});
},
});
}
}
Loading

0 comments on commit 9aed538

Please sign in to comment.