@fleetbase/registry-bridge-engine 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.php-cs-fixer.php +29 -0
- package/LICENSE.md +651 -0
- package/README.md +122 -0
- package/addon/adapters/registry-bridge.js +5 -0
- package/addon/adapters/registry-extension-bundle.js +1 -0
- package/addon/adapters/registry-extension.js +1 -0
- package/addon/components/extension-card.hbs +12 -0
- package/addon/components/extension-card.js +235 -0
- package/addon/components/extension-form.hbs +237 -0
- package/addon/components/extension-form.js +123 -0
- package/addon/components/extension-modal-title.hbs +14 -0
- package/addon/components/extension-modal-title.js +20 -0
- package/addon/components/extension-monetize-form.hbs +56 -0
- package/addon/components/extension-monetize-form.js +7 -0
- package/addon/components/extension-pending-publish-viewer.hbs +52 -0
- package/addon/components/extension-pending-publish-viewer.js +37 -0
- package/addon/components/extension-reviewer-control.hbs +68 -0
- package/addon/components/extension-reviewer-control.js +68 -0
- package/addon/components/modals/confirm-extension-purchase.hbs +5 -0
- package/addon/components/modals/confirm-extension-purchase.js +3 -0
- package/addon/components/modals/extension-details.hbs +69 -0
- package/addon/components/modals/extension-details.js +33 -0
- package/addon/components/modals/extension-purchase-form.hbs +5 -0
- package/addon/components/modals/extension-purchase-form.js +3 -0
- package/addon/components/modals/extension-uninstall.hbs +25 -0
- package/addon/components/modals/extension-uninstall.js +11 -0
- package/addon/components/modals/select-extension-bundle.hbs +43 -0
- package/addon/components/modals/select-extension-bundle.js +31 -0
- package/addon/components/progress-bar.hbs +12 -0
- package/addon/components/progress-bar.js +8 -0
- package/addon/controllers/application.js +6 -0
- package/addon/controllers/developers/analytics.js +26 -0
- package/addon/controllers/developers/extensions/edit/bundles.js +70 -0
- package/addon/controllers/developers/extensions/edit/index.js +3 -0
- package/addon/controllers/developers/extensions/edit/monetize.js +7 -0
- package/addon/controllers/developers/extensions/edit.js +107 -0
- package/addon/controllers/developers/extensions/index.js +3 -0
- package/addon/controllers/developers/extensions/new.js +32 -0
- package/addon/controllers/developers/payments/index.js +39 -0
- package/addon/controllers/developers/payments/onboard.js +67 -0
- package/addon/controllers/explore/category.js +22 -0
- package/addon/controllers/explore/index.js +15 -0
- package/addon/controllers/installed.js +86 -0
- package/addon/controllers/purchased.js +18 -0
- package/addon/engine.js +44 -0
- package/addon/models/registry-extension-bundle.js +62 -0
- package/addon/models/registry-extension.js +215 -0
- package/addon/routes/application.js +12 -0
- package/addon/routes/developers/analytics.js +10 -0
- package/addon/routes/developers/credentials.js +3 -0
- package/addon/routes/developers/extensions/edit/bundles.js +21 -0
- package/addon/routes/developers/extensions/edit/details.js +3 -0
- package/addon/routes/developers/extensions/edit/index.js +3 -0
- package/addon/routes/developers/extensions/edit/monetize.js +3 -0
- package/addon/routes/developers/extensions/edit.js +18 -0
- package/addon/routes/developers/extensions/index.js +10 -0
- package/addon/routes/developers/extensions/new.js +3 -0
- package/addon/routes/developers/extensions.js +3 -0
- package/addon/routes/developers/payments/index.js +26 -0
- package/addon/routes/developers/payments/onboard.js +21 -0
- package/addon/routes/developers/payments.js +3 -0
- package/addon/routes/developers.js +3 -0
- package/addon/routes/explore/category.js +27 -0
- package/addon/routes/explore/index.js +17 -0
- package/addon/routes/explore.js +3 -0
- package/addon/routes/installed.js +10 -0
- package/addon/routes/purchased.js +10 -0
- package/addon/routes.js +28 -0
- package/addon/serializers/registry-extension-bundle.js +15 -0
- package/addon/serializers/registry-extension.js +21 -0
- package/addon/services/stripe.js +83 -0
- package/addon/styles/registry-bridge-engine.css +142 -0
- package/addon/templates/application.hbs +26 -0
- package/addon/templates/developers/analytics.hbs +83 -0
- package/addon/templates/developers/credentials.hbs +1 -0
- package/addon/templates/developers/extensions/edit/bundles.hbs +71 -0
- package/addon/templates/developers/extensions/edit/details.hbs +16 -0
- package/addon/templates/developers/extensions/edit/index.hbs +1 -0
- package/addon/templates/developers/extensions/edit/monetize.hbs +3 -0
- package/addon/templates/developers/extensions/edit.hbs +48 -0
- package/addon/templates/developers/extensions/index.hbs +27 -0
- package/addon/templates/developers/extensions/new.hbs +39 -0
- package/addon/templates/developers/extensions.hbs +1 -0
- package/addon/templates/developers/payments/index.hbs +33 -0
- package/addon/templates/developers/payments/onboard.hbs +48 -0
- package/addon/templates/developers/payments.hbs +1 -0
- package/addon/templates/developers.hbs +1 -0
- package/addon/templates/explore/category.hbs +12 -0
- package/addon/templates/explore/index.hbs +12 -0
- package/addon/templates/explore.hbs +1 -0
- package/addon/templates/installed.hbs +32 -0
- package/addon/templates/purchased.hbs +34 -0
- package/app/adapters/registry-bridge.js +1 -0
- package/app/adapters/registry-extension-bundle.js +1 -0
- package/app/adapters/registry-extension.js +1 -0
- package/app/components/extension-card.js +1 -0
- package/app/components/extension-form.js +1 -0
- package/app/components/extension-modal-title.js +1 -0
- package/app/components/extension-monetize-form.js +1 -0
- package/app/components/extension-pending-publish-viewer.js +1 -0
- package/app/components/extension-reviewer-control.js +1 -0
- package/app/components/modals/confirm-extension-purchase.js +1 -0
- package/app/components/modals/extension-details.js +1 -0
- package/app/components/modals/extension-purchase-form.js +1 -0
- package/app/components/modals/extension-uninstall.js +1 -0
- package/app/components/modals/select-extension-bundle.js +1 -0
- package/app/components/progress-bar.js +1 -0
- package/app/controllers/application.js +1 -0
- package/app/controllers/developers/analytics.js +1 -0
- package/app/controllers/developers/extensions/edit/bundles.js +1 -0
- package/app/controllers/developers/extensions/edit/index.js +1 -0
- package/app/controllers/developers/extensions/edit/monetize.js +1 -0
- package/app/controllers/developers/extensions/edit.js +1 -0
- package/app/controllers/developers/extensions/index.js +1 -0
- package/app/controllers/developers/extensions/new.js +1 -0
- package/app/controllers/developers/payments/index.js +1 -0
- package/app/controllers/developers/payments/onboard.js +1 -0
- package/app/controllers/explore/category.js +1 -0
- package/app/controllers/explore/index.js +1 -0
- package/app/controllers/installed.js +1 -0
- package/app/controllers/purchased.js +1 -0
- package/app/models/registry-extension-bundle.js +1 -0
- package/app/models/registry-extension.js +1 -0
- package/app/routes/developers/analytics.js +1 -0
- package/app/routes/developers/credentials.js +1 -0
- package/app/routes/developers/extensions/edit/bundles.js +1 -0
- package/app/routes/developers/extensions/edit/details.js +1 -0
- package/app/routes/developers/extensions/edit/index.js +1 -0
- package/app/routes/developers/extensions/edit/monetize.js +1 -0
- package/app/routes/developers/extensions/edit.js +1 -0
- package/app/routes/developers/extensions/index.js +1 -0
- package/app/routes/developers/extensions/new.js +1 -0
- package/app/routes/developers/extensions.js +1 -0
- package/app/routes/developers/payments/index.js +1 -0
- package/app/routes/developers/payments/onboard.js +1 -0
- package/app/routes/developers/payments.js +1 -0
- package/app/routes/developers.js +1 -0
- package/app/routes/explore/category.js +1 -0
- package/app/routes/explore/index.js +1 -0
- package/app/routes/explore.js +1 -0
- package/app/routes/installed.js +1 -0
- package/app/routes/purchased.js +1 -0
- package/app/serializers/registry-extension-bundle.js +1 -0
- package/app/serializers/registry-extension.js +1 -0
- package/app/services/stripe.js +1 -0
- package/app/templates/developers/analytics.js +1 -0
- package/app/templates/developers/credentials.js +1 -0
- package/app/templates/developers/extensions/edit/bundles.js +1 -0
- package/app/templates/developers/extensions/edit/details.js +1 -0
- package/app/templates/developers/extensions/edit/index.js +1 -0
- package/app/templates/developers/extensions/edit/monetize.js +1 -0
- package/app/templates/developers/extensions/edit.js +1 -0
- package/app/templates/developers/extensions/index.js +1 -0
- package/app/templates/developers/extensions/new.js +1 -0
- package/app/templates/developers/extensions.js +1 -0
- package/app/templates/developers/payments/index.js +1 -0
- package/app/templates/developers/payments/onboard.js +1 -0
- package/app/templates/developers/payments.js +1 -0
- package/app/templates/developers.js +1 -0
- package/app/templates/explore/category.js +1 -0
- package/app/templates/explore/index.js +1 -0
- package/app/templates/explore.js +1 -0
- package/app/templates/installed.js +1 -0
- package/app/templates/purchased.js +1 -0
- package/composer.json +95 -0
- package/config/environment.js +28 -0
- package/extension.json +10 -0
- package/index.js +26 -0
- package/package.json +129 -0
- package/phpstan.neon.dist +8 -0
- package/phpunit.xml.dist +16 -0
- package/server/.gitattributes +14 -0
- package/server/config/registry-bridge.php +32 -0
- package/server/migrations/2024_03_19_060627_create_registry_users_table.php +42 -0
- package/server/migrations/2024_03_21_051614_create_registry_extensions_table.php +76 -0
- package/server/migrations/2024_03_25_044537_create_registry_extension_bundles_table.php +54 -0
- package/server/migrations/2024_03_29_072101_registry_extension_installs.php +35 -0
- package/server/migrations/2024_07_16_155000_create_registry_extension_purchases.php +41 -0
- package/server/seeders/ExtensionsCategorySeeder.php +359 -0
- package/server/src/Console/Commands/Initialize.php +35 -0
- package/server/src/Console/Commands/PostInstallExtension.php +84 -0
- package/server/src/Exceptions/InstallFailedException.php +21 -0
- package/server/src/Expansions/CategoryExpansion.php +30 -0
- package/server/src/Http/Controllers/Internal/v1/ExtensionInstallerController.php +153 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php +230 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryController.php +54 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryExtensionBundleController.php +112 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryExtensionController.php +257 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryPaymentsController.php +227 -0
- package/server/src/Http/Controllers/RegistryBridgeController.php +13 -0
- package/server/src/Http/Filter/RegistryExtensionFilter.php +80 -0
- package/server/src/Http/Requests/AddRegistryUserRequest.php +47 -0
- package/server/src/Http/Requests/AuthenticateRegistryUserRequest.php +47 -0
- package/server/src/Http/Requests/CreateRegistryExtensionBundleRequest.php +42 -0
- package/server/src/Http/Requests/CreateRegistryExtensionRequest.php +31 -0
- package/server/src/Http/Requests/InstallExtensionRequest.php +30 -0
- package/server/src/Http/Requests/RegistryAuthRequest.php +46 -0
- package/server/src/Http/Requests/RegistryExtensionActionRequest.php +30 -0
- package/server/src/Http/Resources/RegistryUser.php +40 -0
- package/server/src/Models/RegistryExtension.php +656 -0
- package/server/src/Models/RegistryExtensionBundle.php +1015 -0
- package/server/src/Models/RegistryExtensionInstall.php +76 -0
- package/server/src/Models/RegistryExtensionPurchase.php +87 -0
- package/server/src/Models/RegistryUser.php +140 -0
- package/server/src/Providers/RegistryBridgeServiceProvider.php +117 -0
- package/server/src/Support/Bridge.php +53 -0
- package/server/src/Support/Utils.php +19 -0
- package/server/src/routes.php +58 -0
- package/server/tests/Feature.php +5 -0
- package/translations/en-us.yaml +119 -0
- package/tsconfig.declarations.json +10 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class ExtensionFormComponent extends Component {
|
|
8
|
+
@service store;
|
|
9
|
+
@service fetch;
|
|
10
|
+
@service notifications;
|
|
11
|
+
@service intl;
|
|
12
|
+
@service modalsManager;
|
|
13
|
+
@tracked subscriptionModelOptions = ['flat_rate', 'tiered', 'usage'];
|
|
14
|
+
@tracked billingPeriodOptions = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'];
|
|
15
|
+
@tracked uploadQueue = [];
|
|
16
|
+
acceptedImageTypes = ['image/jpeg', 'image/png', 'image/gif'];
|
|
17
|
+
acceptedBundleTypes = [
|
|
18
|
+
'application/zip',
|
|
19
|
+
'application/x-zip',
|
|
20
|
+
'application/x-zip-compressed',
|
|
21
|
+
'application/x-compressed',
|
|
22
|
+
'multipart/x-zip',
|
|
23
|
+
'application/x-tar',
|
|
24
|
+
'application/gzip',
|
|
25
|
+
'application/x-gzip',
|
|
26
|
+
'application/x-tgz',
|
|
27
|
+
'application/x-bzip2',
|
|
28
|
+
'application/x-xz',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
@task *uploadIcon(file) {
|
|
32
|
+
const { extension, onIconUploaded } = this.args;
|
|
33
|
+
|
|
34
|
+
yield this.fetch.uploadFile.perform(
|
|
35
|
+
file,
|
|
36
|
+
{
|
|
37
|
+
path: `uploads/extensions/${extension.id}/icons`,
|
|
38
|
+
subject_uuid: extension.id,
|
|
39
|
+
subject_type: 'registry-bridge:registry-extension',
|
|
40
|
+
type: 'extension_icon',
|
|
41
|
+
},
|
|
42
|
+
(uploadedFile) => {
|
|
43
|
+
extension.setProperties({
|
|
44
|
+
icon: uploadedFile,
|
|
45
|
+
icon_uuid: uploadedFile.id,
|
|
46
|
+
icon_url: uploadedFile.url,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (typeof onIconUploaded === 'function') {
|
|
50
|
+
onIconUploaded(uploadedFile);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return extension.save();
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@action queueFile(file) {
|
|
59
|
+
// since we have dropzone and upload button within dropzone validate the file state first
|
|
60
|
+
// as this method can be called twice from both functions
|
|
61
|
+
if (['queued', 'failed', 'timed_out', 'aborted'].indexOf(file.state) === -1) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { extension, onScreenshotUploaded } = this.args;
|
|
66
|
+
|
|
67
|
+
// Queue and upload immediatley
|
|
68
|
+
this.uploadQueue.pushObject(file);
|
|
69
|
+
this.fetch.uploadFile.perform(
|
|
70
|
+
file,
|
|
71
|
+
{
|
|
72
|
+
path: `uploads/extensions/${extension.id}/screenshots`,
|
|
73
|
+
subject_uuid: extension.id,
|
|
74
|
+
subject_type: 'registry-bridge:registry-extension',
|
|
75
|
+
type: 'extension_screenshot',
|
|
76
|
+
},
|
|
77
|
+
(uploadedFile) => {
|
|
78
|
+
extension.screenshots.pushObject(uploadedFile);
|
|
79
|
+
this.uploadQueue.removeObject(file);
|
|
80
|
+
if (typeof onScreenshotUploaded === 'function') {
|
|
81
|
+
onScreenshotUploaded(uploadedFile);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
() => {
|
|
85
|
+
this.uploadQueue.removeObject(file);
|
|
86
|
+
// remove file from queue
|
|
87
|
+
if (file.queue && typeof file.queue.remove === 'function') {
|
|
88
|
+
file.queue.remove(file);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@action selectBundle() {
|
|
95
|
+
const { extension, onBundleSelected } = this.args;
|
|
96
|
+
|
|
97
|
+
this.modalsManager.show('modals/select-extension-bundle', {
|
|
98
|
+
title: 'Select extension bundle',
|
|
99
|
+
modalClass: 'modal-md',
|
|
100
|
+
acceptButtonText: 'Done',
|
|
101
|
+
hideDeclineButton: true,
|
|
102
|
+
extension,
|
|
103
|
+
onBundleSelected: (bundle) => {
|
|
104
|
+
extension.setProperties({
|
|
105
|
+
next_bundle_uuid: bundle.id,
|
|
106
|
+
next_bundle_id: bundle.bundle_id,
|
|
107
|
+
next_bundle_filename: bundle.bundle_filename,
|
|
108
|
+
next_bundle: bundle,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (typeof onBundleSelected === 'function') {
|
|
112
|
+
onBundleSelected(bundle);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.modalsManager.done();
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@action removeFile(file) {
|
|
121
|
+
return file.destroyRecord();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="flex flex-row" ...attributes {{did-update this.handleExtensionChanged @extension}}>
|
|
2
|
+
<div class="modal-title--extension-icon-wrapper shadow-sm dark:border-gray-700">
|
|
3
|
+
<div class="flex items-center justify-center rounded-lg w-full" {{background-url this.extension.icon_url overlay=true}}>
|
|
4
|
+
<Image src={{this.extension.icon_url}} class="w-full rounded-lg" alt={{this.extension.name}} @fallbackSrc={{config "defaultValues.extensionIcon"}} />
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="flex-1">
|
|
8
|
+
<div class={{this.detailsContainerClass}}>
|
|
9
|
+
<h1 class="dark:text-white text-black font-semibold">{{this.extension.name}}</h1>
|
|
10
|
+
<div class="dark:text-gray-300 text-black">{{this.extension.subtitle}}</div>
|
|
11
|
+
<div class="dark:text-gray-300 text-black text-sm">{{concat "Published by " this.extension.publisher_name}}</div>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
|
|
5
|
+
export default class ExtensionModalTitleComponent extends Component {
|
|
6
|
+
@tracked extension;
|
|
7
|
+
@tracked detailsContainerClass = 'mb-4';
|
|
8
|
+
|
|
9
|
+
constructor(owner, { options, extension = null, detailsContainerClass = 'mb-4' }) {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.extension = options ? options.extension : extension;
|
|
12
|
+
this.detailsContainerClass = detailsContainerClass;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@action handleExtensionChanged(el, [extension]) {
|
|
16
|
+
if (extension) {
|
|
17
|
+
this.extension = extension;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<ContentPanel @title={{t "registry-bridge.developers.extensions.extension-form.extension-payment-details"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
|
2
|
+
<InputGroup @wrapperClass={{unless @extension.payment_required "mb-0i"}}>
|
|
3
|
+
<Toggle
|
|
4
|
+
@isToggled={{@extension.payment_required}}
|
|
5
|
+
@onToggle={{fn (mut @extension.payment_required)}}
|
|
6
|
+
@label={{t "registry-bridge.developers.extensions.extension-form.extension-payment-required"}}
|
|
7
|
+
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-payment-required-help-text"}}
|
|
8
|
+
/>
|
|
9
|
+
</InputGroup>
|
|
10
|
+
{{#if @extension.payment_required}}
|
|
11
|
+
<InputGroup>
|
|
12
|
+
<Toggle
|
|
13
|
+
@isToggled={{@extension.subscription_required}}
|
|
14
|
+
@onToggle={{fn (mut @extension.subscription_required)}}
|
|
15
|
+
@label={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-required"}}
|
|
16
|
+
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-required-help-text"}}
|
|
17
|
+
/>
|
|
18
|
+
</InputGroup>
|
|
19
|
+
{{#if @extension.subscription_required}}
|
|
20
|
+
<InputGroup
|
|
21
|
+
@name={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period"}}
|
|
22
|
+
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period-help-text"}}
|
|
23
|
+
>
|
|
24
|
+
<Select
|
|
25
|
+
@value={{@extension.subscription_billing_period}}
|
|
26
|
+
@options={{this.billingPeriodOptions}}
|
|
27
|
+
@onSelect={{fn (mut @extension.subscription_billing_period)}}
|
|
28
|
+
@placeholder={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period-placeholder"}}
|
|
29
|
+
class="w-full"
|
|
30
|
+
/>
|
|
31
|
+
</InputGroup>
|
|
32
|
+
<InputGroup
|
|
33
|
+
@name={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-amount"}}
|
|
34
|
+
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-amount-help-text"}}
|
|
35
|
+
@wrapperClass="mb-0i"
|
|
36
|
+
>
|
|
37
|
+
<MoneyInput @value={{@extension.subscription_amount}} @currency="USD" />
|
|
38
|
+
</InputGroup>
|
|
39
|
+
{{else}}
|
|
40
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-2">
|
|
41
|
+
<InputGroup
|
|
42
|
+
@name={{t "registry-bridge.developers.extensions.extension-form.extension-price"}}
|
|
43
|
+
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-price-help-text"}}
|
|
44
|
+
>
|
|
45
|
+
<MoneyInput @value={{@extension.price}} @currency="USD" />
|
|
46
|
+
</InputGroup>
|
|
47
|
+
<InputGroup
|
|
48
|
+
@name={{t "registry-bridge.developers.extensions.extension-form.extension-sale-price"}}
|
|
49
|
+
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-sale-price-help-text"}}
|
|
50
|
+
>
|
|
51
|
+
<MoneyInput @value={{@extension.sale_price}} @currency="USD" />
|
|
52
|
+
</InputGroup>
|
|
53
|
+
</div>
|
|
54
|
+
{{/if}}
|
|
55
|
+
{{/if}}
|
|
56
|
+
</ContentPanel>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
|
|
4
|
+
export default class ExtensionMonetizeFormComponent extends Component {
|
|
5
|
+
@tracked subscriptionModelOptions = ['flat_rate', 'tiered', 'usage'];
|
|
6
|
+
@tracked billingPeriodOptions = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'];
|
|
7
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<div class="space-y-4">
|
|
2
|
+
<ContentPanel @title={{t "registry-bridge.component.extension-pending-publish-viewer.content-panel-title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
|
3
|
+
<div class="grid grid-cols-1 lg:grid-cols-4">
|
|
4
|
+
{{#each this.extensions as |extension|}}
|
|
5
|
+
<div class="flex flex-col">
|
|
6
|
+
<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)}}>
|
|
7
|
+
<div class="flex items-center justify-center rounded-t-lg w-full h-36" {{background-url extension.icon_url overlay=true}}>
|
|
8
|
+
<Image src={{extension.icon_url}} class="w-full h-36 rounded-t-lg" alt={{extension.name}} @fallbackSrc={{config "defaultValues.extensionIcon"}} />
|
|
9
|
+
</div>
|
|
10
|
+
<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">
|
|
11
|
+
<span class="font-semibold text-sm block">{{extension.name}}</span>
|
|
12
|
+
<p class="text-xs">{{n-a extension.description}}</p>
|
|
13
|
+
<div>
|
|
14
|
+
<Badge @status={{extension.status}} />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</button>
|
|
18
|
+
<div class="space-y-2 mt-3">
|
|
19
|
+
<Button
|
|
20
|
+
@size="sm"
|
|
21
|
+
@icon="clipboard-list"
|
|
22
|
+
@text={{t "registry-bridge.component.extension-pending-publish-viewer.view-details"}}
|
|
23
|
+
@onClick={{fn this.focusExtension extension}}
|
|
24
|
+
class="w-full"
|
|
25
|
+
/>
|
|
26
|
+
<Button
|
|
27
|
+
@size="sm"
|
|
28
|
+
@icon="download"
|
|
29
|
+
@text={{t "registry-bridge.component.extension-pending-publish-viewer.download-bundle"}}
|
|
30
|
+
@onClick={{perform this.downloadBundle extension}}
|
|
31
|
+
class="w-full"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
{{else}}
|
|
36
|
+
<div class="col-span-4">
|
|
37
|
+
<div class="text-base italic">{{t "registry-bridge.component.extension-pending-publish-viewer.no-extensions-awaiting-publish"}}</div>
|
|
38
|
+
</div>
|
|
39
|
+
{{/each}}
|
|
40
|
+
</div>
|
|
41
|
+
</ContentPanel>
|
|
42
|
+
|
|
43
|
+
{{#if this.focusedExtension}}
|
|
44
|
+
<ContentPanel @title={{t "registry-bridge.component.extension-pending-publish-viewer.focused-extension-title" extensionName=this.focusedExtension.name}} @open={{true}} @pad={{true}}>
|
|
45
|
+
<div class="flex items-center mb-4 px-1">
|
|
46
|
+
<Button @type="primary" @size="sm" @icon="check" @text={{t "common.done"}} @onClick={{this.unfocusExtension}} class="w-full" />
|
|
47
|
+
</div>
|
|
48
|
+
<ExtensionForm @extension={{this.focusedExtension}} @withMonetizeForm={{true}} />
|
|
49
|
+
</ContentPanel>
|
|
50
|
+
{{/if}}
|
|
51
|
+
</div>
|
|
52
|
+
<Spacer @height="400px" />
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class ExtensionPendingPublishViewerComponent extends Component {
|
|
8
|
+
@service store;
|
|
9
|
+
@service notifications;
|
|
10
|
+
@tracked extensions = [];
|
|
11
|
+
@tracked focusedExtension;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.getExtensionsPendingPublish.perform();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@task *getExtensionsPendingPublish() {
|
|
19
|
+
this.extensions = yield this.store.query('registry-extension', { status: 'approved' });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@task *downloadBundle(extension) {
|
|
23
|
+
try {
|
|
24
|
+
yield extension.downloadBundle();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
this.notifications.error(error.message);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@action focusExtension(extension) {
|
|
31
|
+
this.focusedExtension = extension;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@action unfocusExtension() {
|
|
35
|
+
this.focusedExtension = undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<div class="space-y-4">
|
|
2
|
+
<ContentPanel @title={{t "registry-bridge.component.extension-reviewer-control.content-panel-title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
|
3
|
+
<div class="grid grid-cols-1 lg:grid-cols-4">
|
|
4
|
+
{{#each this.extensions as |extension|}}
|
|
5
|
+
<div class="flex flex-col">
|
|
6
|
+
<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)}}>
|
|
7
|
+
<div class="flex items-center justify-center rounded-t-lg w-full h-36" {{background-url extension.icon_url overlay=true}}>
|
|
8
|
+
<Image src={{extension.icon_url}} class="w-full h-36 rounded-t-lg" alt={{extension.name}} @fallbackSrc={{config "defaultValues.extensionIcon"}} />
|
|
9
|
+
</div>
|
|
10
|
+
<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">
|
|
11
|
+
<span class="font-semibold text-sm block">{{extension.name}}</span>
|
|
12
|
+
<p class="text-xs">{{n-a extension.description}}</p>
|
|
13
|
+
<div>
|
|
14
|
+
<Badge @status={{extension.status}} />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</button>
|
|
18
|
+
<div class="space-y-2 mt-3">
|
|
19
|
+
<Button
|
|
20
|
+
@size="sm"
|
|
21
|
+
@icon="clipboard-list"
|
|
22
|
+
@text={{t "registry-bridge.component.extension-reviewer-control.view-details"}}
|
|
23
|
+
@onClick={{fn this.focusExtension extension}}
|
|
24
|
+
class="w-full"
|
|
25
|
+
/>
|
|
26
|
+
<Button
|
|
27
|
+
@size="sm"
|
|
28
|
+
@icon="download"
|
|
29
|
+
@text={{t "registry-bridge.component.extension-reviewer-control.download-bundle"}}
|
|
30
|
+
@onClick={{perform this.downloadBundle extension}}
|
|
31
|
+
class="w-full"
|
|
32
|
+
/>
|
|
33
|
+
<Button
|
|
34
|
+
@type="success"
|
|
35
|
+
@size="sm"
|
|
36
|
+
@icon="check"
|
|
37
|
+
@text={{t "registry-bridge.component.extension-reviewer-control.approve"}}
|
|
38
|
+
@onClick={{fn this.approve extension}}
|
|
39
|
+
class="w-full"
|
|
40
|
+
/>
|
|
41
|
+
<Button
|
|
42
|
+
@type="danger"
|
|
43
|
+
@size="sm"
|
|
44
|
+
@icon="ban"
|
|
45
|
+
@text={{t "registry-bridge.component.extension-reviewer-control.reject"}}
|
|
46
|
+
@onClick={{fn this.reject extension}}
|
|
47
|
+
class="w-full"
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
{{else}}
|
|
52
|
+
<div class="col-span-4">
|
|
53
|
+
<div class="text-base italic">{{t "registry-bridge.component.extension-reviewer-control.no-extensions-awaiting-review"}}</div>
|
|
54
|
+
</div>
|
|
55
|
+
{{/each}}
|
|
56
|
+
</div>
|
|
57
|
+
</ContentPanel>
|
|
58
|
+
|
|
59
|
+
{{#if this.focusedExtension}}
|
|
60
|
+
<ContentPanel @title={{t "registry-bridge.component.extension-reviewer-control.focused-extension-title" extensionName=this.focusedExtension.name}} @open={{true}} @pad={{true}}>
|
|
61
|
+
<div class="flex items-center mb-4 px-1">
|
|
62
|
+
<Button @type="primary" @size="sm" @icon="check" @text={{t "common.done"}} @onClick={{this.unfocusExtension}} class="w-full" />
|
|
63
|
+
</div>
|
|
64
|
+
<ExtensionForm @extension={{this.focusedExtension}} @withMonetizeForm={{true}} />
|
|
65
|
+
</ContentPanel>
|
|
66
|
+
{{/if}}
|
|
67
|
+
</div>
|
|
68
|
+
<Spacer @height="400px" />
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class ExtensionReviewerControlComponent extends Component {
|
|
8
|
+
@service store;
|
|
9
|
+
@service modalsManager;
|
|
10
|
+
@service notifications;
|
|
11
|
+
@service intl;
|
|
12
|
+
@tracked extensions = [];
|
|
13
|
+
@tracked focusedExtension;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.getExtensionsPendingReview.perform();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@task *getExtensionsPendingReview() {
|
|
21
|
+
this.extensions = yield this.store.query('registry-extension', { status: 'awaiting_review' });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@task *downloadBundle(extension) {
|
|
25
|
+
try {
|
|
26
|
+
yield extension.downloadBundle();
|
|
27
|
+
} catch (error) {
|
|
28
|
+
this.notifications.error(error.message);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@action focusExtension(extension) {
|
|
33
|
+
this.focusedExtension = extension;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@action unfocusExtension() {
|
|
37
|
+
this.focusedExtension = undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@action approve(extension) {
|
|
41
|
+
return this.modalsManager.confirm({
|
|
42
|
+
title: this.intl.t('registry-bridge.component.extension-reviewer-control.approve-confirm-title', { extensionName: extension.name }),
|
|
43
|
+
body: this.intl.t('registry-bridge.component.extension-reviewer-control.approve-confirm-body'),
|
|
44
|
+
acceptButtonText: this.intl.t('registry-bridge.component.extension-reviewer-control.approve'),
|
|
45
|
+
confirm: () => {
|
|
46
|
+
this.unfocusExtension();
|
|
47
|
+
return extension.approve().finally(() => {
|
|
48
|
+
this.getExtensionsPendingReview.perform();
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@action reject(extension) {
|
|
55
|
+
return this.modalsManager.confirm({
|
|
56
|
+
title: this.intl.t('registry-bridge.component.extension-reviewer-control.decline-confirm-title', { extensionName: extension.name }),
|
|
57
|
+
body: this.intl.t('registry-bridge.component.extension-reviewer-control.decline-confirm-body'),
|
|
58
|
+
acceptButtonText: this.intl.t('registry-bridge.component.extension-reviewer-control.reject'),
|
|
59
|
+
acceptButtonIcon: 'ban',
|
|
60
|
+
acceptButtonScheme: 'danger',
|
|
61
|
+
confirm: () => {
|
|
62
|
+
return extension.reject().finally(() => {
|
|
63
|
+
this.getExtensionsPendingReview.perform();
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
|
|
2
|
+
<div class="pt-4 pb-6 px-4">
|
|
3
|
+
<Spinner @loadingMessage={{@options.loadingMessage}} @loadingMessageClass="ml-2 text-black dark:text-white" @wrapperClass="flex flex-row items-center" />
|
|
4
|
+
</div>
|
|
5
|
+
</Modal::Default>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
|
|
2
|
+
<div class="modal-body-container space-y-3">
|
|
3
|
+
<div class="flex flex-row items-center space-x-2">
|
|
4
|
+
<div class="flb--extension-tag shadow-sm border dark:bg-gray-800 dark:border-gray-800 dark:text-gray-200">
|
|
5
|
+
Extension
|
|
6
|
+
</div>
|
|
7
|
+
<div class="flb--extension-tag shadow-sm border dark:bg-gray-800 dark:border-gray-800 dark:text-gray-200">
|
|
8
|
+
{{this.extension.category_name}}
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
{{#if @options.progress}}
|
|
12
|
+
<div class="my-4">
|
|
13
|
+
<ProgressBar @title={{@options.stepDescription}} @percent={{@options.progress}} />
|
|
14
|
+
</div>
|
|
15
|
+
{{/if}}
|
|
16
|
+
{{#if this.extension.screenshots}}
|
|
17
|
+
<div class="grid grid-cols-4 gap-2">
|
|
18
|
+
{{#each this.extension.screenshots as |screenshot|}}
|
|
19
|
+
<Image src={{screenshot.url}} class="flb--extension-screenshot" {{on "click" (fn this.lightboxScreenshot screenshot)}} />
|
|
20
|
+
{{/each}}
|
|
21
|
+
</div>
|
|
22
|
+
{{#if this.screenshotInLightbox}}
|
|
23
|
+
<EmberWormhole @to="console-wormhole">
|
|
24
|
+
<div class="flb--extension-screenshot-lightbox" {{did-insert this.setupScreenshotLightbox}}>
|
|
25
|
+
<Image src={{this.screenshotInLightbox.url}} class="flb--extension-screenshot" {{on "click" this.lightboxScreenshot}} />
|
|
26
|
+
</div>
|
|
27
|
+
</EmberWormhole>
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{/if}}
|
|
30
|
+
<div>
|
|
31
|
+
<h3 class="dark:text-white font-semibold mb-1">Overview</h3>
|
|
32
|
+
<div class="space-y-1">
|
|
33
|
+
<p class="dark:text-gray-200 text-sm">{{this.extension.description}}</p>
|
|
34
|
+
<p class="dark:text-gray-200 text-sm">{{this.extension.promotional_text}}</p>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div>
|
|
38
|
+
<h3 class="dark:text-white font-semibold mb-1">Details</h3>
|
|
39
|
+
<div class="space-y-2">
|
|
40
|
+
<div class="grid grid-cols-4 gap-2">
|
|
41
|
+
<div class="space-y-2">
|
|
42
|
+
<div>
|
|
43
|
+
<div class="text-sm font-semibold dark:text-gray-100">Version</div>
|
|
44
|
+
<div class="text-sm dark:text-gray-200">{{this.extension.version}}</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
<div class="text-sm font-semibold dark:text-gray-100">Updated</div>
|
|
48
|
+
<div class="text-sm dark:text-gray-200">{{this.extension.updatedAt}}</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="space-y-2">
|
|
52
|
+
<div>
|
|
53
|
+
<div class="text-sm font-semibold dark:text-gray-100">Author</div>
|
|
54
|
+
<div class="text-sm dark:text-gray-200">{{this.extension.publisher_name}}</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div>
|
|
57
|
+
<div class="text-sm font-semibold dark:text-gray-100">Website</div>
|
|
58
|
+
<a
|
|
59
|
+
class="text-sm dark:text-gray-200"
|
|
60
|
+
href={{this.extension.website_url}}
|
|
61
|
+
target={{dasherize (concat this.extension.name "-website")}}
|
|
62
|
+
>{{this.extension.website_url}}</a>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</Modal::Default>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
import { later } from '@ember/runloop';
|
|
5
|
+
|
|
6
|
+
export default class ModalsExtensionDetailsComponent extends Component {
|
|
7
|
+
@tracked extension;
|
|
8
|
+
@tracked screenshotInLightbox;
|
|
9
|
+
|
|
10
|
+
constructor(owner, { options }) {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.extension = options.extension;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@action lightboxScreenshot(screenshot) {
|
|
16
|
+
this.screenshotInLightbox = screenshot;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@action setupScreenshotLightbox() {
|
|
20
|
+
const listener = () => {
|
|
21
|
+
this.screenshotInLightbox = undefined;
|
|
22
|
+
window.removeEventListener('click', listener);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
later(
|
|
26
|
+
this,
|
|
27
|
+
() => {
|
|
28
|
+
window.addEventListener('click', listener);
|
|
29
|
+
},
|
|
30
|
+
600
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
|
|
2
|
+
<div class="modal-body-container">
|
|
3
|
+
<div class="flex flex-row py-4">
|
|
4
|
+
<div class="w-60 flex justify-center">
|
|
5
|
+
<FaIcon @icon="triangle-exclamation" @size="3x" class="text-red-500" />
|
|
6
|
+
</div>
|
|
7
|
+
<div class="flex flex-col">
|
|
8
|
+
<h2 class="dark:text-white font-bold mb-2">Proceed with Uninstall?</h2>
|
|
9
|
+
<p class="dark:text-gray-200 text-sm">
|
|
10
|
+
Do you really want to uninstall the
|
|
11
|
+
{{this.extension.name}}? By proceeding, you will permanently delete all settings and data related to this extension. You can reinstall the extension anytime in the
|
|
12
|
+
future, but configuration and data will not be recovered.
|
|
13
|
+
</p>
|
|
14
|
+
<div class="mt-6 px-4 py-3 border border-gray-200 dark:border-gray-900 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
15
|
+
<ExtensionModalTitle @options={{@options}} @detailsContainerClass="mb-0" />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
{{#if @options.progress}}
|
|
20
|
+
<div class="my-4">
|
|
21
|
+
<ProgressBar @title={{@options.stepDescription}} @percent={{@options.progress}} />
|
|
22
|
+
</div>
|
|
23
|
+
{{/if}}
|
|
24
|
+
</div>
|
|
25
|
+
</Modal::Default>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
|
|
4
|
+
export default class ModalsExtensionUninstallComponent extends Component {
|
|
5
|
+
@tracked extension;
|
|
6
|
+
|
|
7
|
+
constructor(owner, { options }) {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.extension = options.extension;
|
|
10
|
+
}
|
|
11
|
+
}
|