@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,43 @@
|
|
|
1
|
+
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
|
|
2
|
+
{{#if this.bundles}}
|
|
3
|
+
<div class="next-table-wrapper auto-height">
|
|
4
|
+
<table>
|
|
5
|
+
<thead>
|
|
6
|
+
<tr>
|
|
7
|
+
<th {{set-width "175px"}}>ID</th>
|
|
8
|
+
<th {{set-width "70px"}}>Bundle</th>
|
|
9
|
+
<th {{set-width "80px"}}>Version</th>
|
|
10
|
+
<th {{set-width "110px"}}>Uploaded</th>
|
|
11
|
+
<th {{set-width "100px"}}>Status</th>
|
|
12
|
+
<th></th>
|
|
13
|
+
</tr>
|
|
14
|
+
</thead>
|
|
15
|
+
<tbody>
|
|
16
|
+
{{#each this.bundles as |bundle|}}
|
|
17
|
+
<tr>
|
|
18
|
+
<td>{{bundle.bundle_id}}</td>
|
|
19
|
+
<td>{{bundle.bundle_number}}</td>
|
|
20
|
+
<td>{{bundle.version}}</td>
|
|
21
|
+
<td>{{bundle.createdAgo}}</td>
|
|
22
|
+
<td>
|
|
23
|
+
<Badge @status={{bundle.status}} />
|
|
24
|
+
</td>
|
|
25
|
+
<td>
|
|
26
|
+
{{#if (eq this.extension.next_bundle_uuid bundle.id)}}
|
|
27
|
+
<div class="flex flex-row items-center text-xs">
|
|
28
|
+
<FaIcon @icon="check" class="text-green-500" @size="md" />
|
|
29
|
+
<span class="ml-2 text-green-400">Selected</span>
|
|
30
|
+
</div>
|
|
31
|
+
{{else}}
|
|
32
|
+
<Button @text="Select" @size="xs" @type="primary" @onClick={{fn this.selectBundle bundle}} />
|
|
33
|
+
{{/if}}
|
|
34
|
+
</td>
|
|
35
|
+
</tr>
|
|
36
|
+
{{/each}}
|
|
37
|
+
</tbody>
|
|
38
|
+
</table>
|
|
39
|
+
</div>
|
|
40
|
+
{{else}}
|
|
41
|
+
<div>No bundles uploaded.</div>
|
|
42
|
+
{{/if}}
|
|
43
|
+
</Modal::Default>
|
|
@@ -0,0 +1,31 @@
|
|
|
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 ModalsSelectExtensionBundleComponent extends Component {
|
|
8
|
+
@service store;
|
|
9
|
+
@tracked extension;
|
|
10
|
+
@tracked options = {};
|
|
11
|
+
@tracked bundles = [];
|
|
12
|
+
|
|
13
|
+
constructor(owner, { options }) {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
const { extension } = options;
|
|
16
|
+
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.extension = extension;
|
|
19
|
+
this.loadExtensionBundles.perform(extension);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@task *loadExtensionBundles(extension) {
|
|
23
|
+
this.bundles = yield this.store.query('registry-extension-bundle', { extension_uuid: extension.id, status: 'pending' });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@action selectBundle(bundle) {
|
|
27
|
+
if (typeof this.options.onBundleSelected === 'function') {
|
|
28
|
+
this.options.onBundleSelected(bundle);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<div class="mb-2 flex justify-between items-center">
|
|
3
|
+
<h3 class="text-sm font-semibold text-gray-800 dark:text-white">{{@title}}</h3>
|
|
4
|
+
<span class="text-sm text-gray-800 dark:text-white">{{@percent}}%</span>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="flex w-full h-2 bg-gray-200 rounded-full overflow-hidden dark:bg-neutral-700" role="progressbar" aria-valuenow={{@percent}} aria-valuemin="0" aria-valuemax="100">
|
|
7
|
+
<div
|
|
8
|
+
class="flex flex-col justify-center rounded-full overflow-hidden bg-blue-600 text-xs text-white text-center whitespace-nowrap transition duration-500 dark:bg-blue-500"
|
|
9
|
+
{{did-update this.setProgress @percent}}
|
|
10
|
+
></div>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
import { inject as service } from '@ember/service';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class DevelopersAnalyticsController extends Controller {
|
|
8
|
+
@service fetch;
|
|
9
|
+
@service notifications;
|
|
10
|
+
@tracked selectedExtension;
|
|
11
|
+
@tracked extensions = [];
|
|
12
|
+
@tracked metrics = {};
|
|
13
|
+
|
|
14
|
+
@action selectExtension(extension) {
|
|
15
|
+
this.selectedExtension = extension;
|
|
16
|
+
this.getExtensionAnalytics.perform(extension);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@task *getExtensionAnalytics(extension) {
|
|
20
|
+
try {
|
|
21
|
+
this.metrics = yield this.fetch.get('registry-extensions/analytics', { id: extension.id }, { namespace: '~registry/v1' });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
this.notifications.serverError(error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { task } from 'ember-concurrency';
|
|
5
|
+
|
|
6
|
+
export default class DevelopersExtensionsEditBundlesController extends Controller {
|
|
7
|
+
@service store;
|
|
8
|
+
@service fetch;
|
|
9
|
+
@service hostRouter;
|
|
10
|
+
@service notifications;
|
|
11
|
+
@tracked extension;
|
|
12
|
+
@tracked lastError;
|
|
13
|
+
acceptedBundleTypes = [
|
|
14
|
+
'application/zip',
|
|
15
|
+
'application/x-zip',
|
|
16
|
+
'application/x-zip-compressed',
|
|
17
|
+
'application/x-compressed',
|
|
18
|
+
'multipart/x-zip',
|
|
19
|
+
'application/x-tar',
|
|
20
|
+
'application/gzip',
|
|
21
|
+
'application/x-gzip',
|
|
22
|
+
'application/x-tgz',
|
|
23
|
+
'application/x-bzip2',
|
|
24
|
+
'application/x-xz',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
@task *uploadBundle(file) {
|
|
28
|
+
this.lastError = undefined;
|
|
29
|
+
|
|
30
|
+
yield this.fetch.uploadFile.perform(
|
|
31
|
+
file,
|
|
32
|
+
{
|
|
33
|
+
path: `uploads/extensions/${this.extension.id}/bundles`,
|
|
34
|
+
subject_uuid: this.extension.id,
|
|
35
|
+
subject_type: 'registry-bridge:registry-extension',
|
|
36
|
+
type: 'extension_bundle',
|
|
37
|
+
meta: {
|
|
38
|
+
version: this.extension.version,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
(uploadedFile) => {
|
|
42
|
+
return this.createBundle.perform(uploadedFile);
|
|
43
|
+
},
|
|
44
|
+
() => {
|
|
45
|
+
// remove file from queue
|
|
46
|
+
if (file.queue && typeof file.queue.remove === 'function') {
|
|
47
|
+
file.queue.remove(file);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@task *createBundle(uploadedFile) {
|
|
54
|
+
const bundle = this.store.createRecord('registry-extension-bundle', {
|
|
55
|
+
extension_uuid: this.extension.id,
|
|
56
|
+
bundle_uuid: uploadedFile.id,
|
|
57
|
+
bundle: uploadedFile,
|
|
58
|
+
status: 'pending',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
yield bundle.save();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.lastError = error.message;
|
|
65
|
+
return this.notifications.serverError(error);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
yield this.hostRouter.refresh();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
|
|
4
|
+
export default class DevelopersExtensionsEditMonetizeController extends Controller {
|
|
5
|
+
@tracked subscriptionModelOptions = ['flat_rate', 'tiered', 'usage'];
|
|
6
|
+
@tracked billingPeriodOptions = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'];
|
|
7
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { isArray } from '@ember/array';
|
|
6
|
+
import { isBlank } from '@ember/utils';
|
|
7
|
+
import { task } from 'ember-concurrency';
|
|
8
|
+
import humanize from '@fleetbase/ember-core/utils/humanize';
|
|
9
|
+
|
|
10
|
+
export default class DevelopersExtensionsEditController extends Controller {
|
|
11
|
+
@service notifications;
|
|
12
|
+
@service intl;
|
|
13
|
+
@tracked isReady = false;
|
|
14
|
+
@tracked isReadyMessage = null;
|
|
15
|
+
|
|
16
|
+
@task *save() {
|
|
17
|
+
try {
|
|
18
|
+
yield this.model.save();
|
|
19
|
+
this.notifications.success('Extension details saved.');
|
|
20
|
+
const isReady = this.validateExtensionForReview();
|
|
21
|
+
if (isReady === true) {
|
|
22
|
+
this.isReady = isReady;
|
|
23
|
+
} else if (isArray(isReady) && isReady.length) {
|
|
24
|
+
this.isReadyMessage = isReady[0];
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
this.notifications.warning(error.message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@task *startReview() {
|
|
32
|
+
try {
|
|
33
|
+
yield this.model.submitForReview();
|
|
34
|
+
this.notifications.success(this.intl.t('registry-bridge.developers.extensions.extension-form.submission-success-message'));
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error && error.message) {
|
|
37
|
+
this.notifications.error(error.messsage);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@action onIconUploaded(uploadedFile) {
|
|
43
|
+
this.model.setProperties({
|
|
44
|
+
icon_uuid: uploadedFile.id,
|
|
45
|
+
icon_url: uploadedFile.url,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return this.model.save();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@action submitForReview() {
|
|
52
|
+
const result = this.validateExtensionForReview();
|
|
53
|
+
if (result === true) {
|
|
54
|
+
// send for review
|
|
55
|
+
return this.startReview.perform();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isArray(result)) {
|
|
59
|
+
this.notifications.warning(result.join('\n'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getValidations() {
|
|
64
|
+
const defaultValidationFn = (value) => !isBlank(value);
|
|
65
|
+
return {
|
|
66
|
+
name: (value) => {
|
|
67
|
+
return typeof value === 'string' && value.length > 3;
|
|
68
|
+
},
|
|
69
|
+
description: (value) => {
|
|
70
|
+
return typeof value === 'string' && value.length > 12;
|
|
71
|
+
},
|
|
72
|
+
tags: defaultValidationFn,
|
|
73
|
+
promotional_text: defaultValidationFn,
|
|
74
|
+
subtitle: defaultValidationFn,
|
|
75
|
+
copyright: defaultValidationFn,
|
|
76
|
+
website_url: defaultValidationFn,
|
|
77
|
+
support_url: defaultValidationFn,
|
|
78
|
+
privacy_policy_url: defaultValidationFn,
|
|
79
|
+
icon_uuid: defaultValidationFn,
|
|
80
|
+
next_bundle_uuid: defaultValidationFn,
|
|
81
|
+
category_uuid: defaultValidationFn,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
validateExtensionForReview() {
|
|
86
|
+
const extension = this.model;
|
|
87
|
+
const validations = this.getValidations();
|
|
88
|
+
const errors = [];
|
|
89
|
+
// next bundle and current bundle id cannot be equal
|
|
90
|
+
if (extension.next_bundle_uuid === extension.current_bundle_uuid) {
|
|
91
|
+
return ['New bundle must be selected fo review.'];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Object.keys(validations).forEach((property) => {
|
|
95
|
+
const isValid = validations[property](extension.get(property));
|
|
96
|
+
if (!isValid) {
|
|
97
|
+
errors.push(`${humanize(property)} is required for submission.`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (errors.length > 0) {
|
|
102
|
+
return errors;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
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 DevelopersExtensionsNewController extends Controller {
|
|
8
|
+
@service store;
|
|
9
|
+
@service universe;
|
|
10
|
+
@service hostRouter;
|
|
11
|
+
@service notifications;
|
|
12
|
+
@tracked extension = this.store.createRecord('registry-extension');
|
|
13
|
+
|
|
14
|
+
@task *save() {
|
|
15
|
+
try {
|
|
16
|
+
yield this.extension.save();
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return this.notifications.warning(error.message);
|
|
19
|
+
}
|
|
20
|
+
return this.hostRouter.transitionTo('console.extensions.developers.extensions.edit', this.extension);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@action cancel() {
|
|
24
|
+
this.reset();
|
|
25
|
+
return this.hostRouter.transitionTo('console.extensions.developers.extensions');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
reset() {
|
|
29
|
+
this.extension.destroyRecord();
|
|
30
|
+
this.extension = this.store.createRecord('registry-extension');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
|
|
4
|
+
export default class DevelopersPaymentsIndexController extends Controller {
|
|
5
|
+
@tracked hasStripeConnectAccount = true;
|
|
6
|
+
@tracked table;
|
|
7
|
+
@tracked page = 1;
|
|
8
|
+
@tracked limit = 30;
|
|
9
|
+
@tracked sort = '-created_at';
|
|
10
|
+
@tracked query = null;
|
|
11
|
+
queryParams = ['page', 'limit', 'sort', 'query'];
|
|
12
|
+
columns = [
|
|
13
|
+
{
|
|
14
|
+
label: 'Extension',
|
|
15
|
+
valuePath: 'extension.name',
|
|
16
|
+
width: '20%',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: 'Category',
|
|
20
|
+
valuePath: 'extension.category_name',
|
|
21
|
+
width: '20%',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
label: 'Customer',
|
|
25
|
+
valuePath: 'company.name',
|
|
26
|
+
width: '20%',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'Amount',
|
|
30
|
+
valuePath: 'locked_price',
|
|
31
|
+
width: '20%',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: 'Date',
|
|
35
|
+
valuePath: 'created_at',
|
|
36
|
+
width: '20%',
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
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
|
+
import { loadConnectAndInitialize } from '@stripe/connect-js';
|
|
7
|
+
import config from '../config/environment';
|
|
8
|
+
|
|
9
|
+
export default class DevelopersPaymentsOnboardController extends Controller {
|
|
10
|
+
@service fetch;
|
|
11
|
+
@service notifications;
|
|
12
|
+
@tracked connectedAccountId;
|
|
13
|
+
@tracked onboardInProgress = false;
|
|
14
|
+
@tracked onboardCompleted = false;
|
|
15
|
+
|
|
16
|
+
@task *startOnboard() {
|
|
17
|
+
try {
|
|
18
|
+
const { account } = yield this.fetch.post('payments/account', {}, { namespace: '~registry/v1' });
|
|
19
|
+
|
|
20
|
+
this.connectedAccountId = account;
|
|
21
|
+
this.onboardInProgress = true;
|
|
22
|
+
|
|
23
|
+
const instance = loadConnectAndInitialize({
|
|
24
|
+
publishableKey: config.stripe.publishableKey,
|
|
25
|
+
fetchClientSecret: this.fetchClientSecret.bind(this),
|
|
26
|
+
appearance: {
|
|
27
|
+
overlays: 'dialog',
|
|
28
|
+
variables: {
|
|
29
|
+
colorPrimary: '#635BFF',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const container = this.getTrackedElement('embeddedOnboardingContainer');
|
|
35
|
+
const embeddedOnboardingComponent = instance.create('account-onboarding');
|
|
36
|
+
embeddedOnboardingComponent.setOnExit(() => {
|
|
37
|
+
this.onboardInProgress = false;
|
|
38
|
+
this.onboardCompleted = true;
|
|
39
|
+
});
|
|
40
|
+
container.appendChild(embeddedOnboardingComponent);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
this.notifications.serverError(error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async fetchClientSecret() {
|
|
47
|
+
try {
|
|
48
|
+
const { clientSecret } = await this.fetch.post('payments/account-session', { account: this.connectedAccountId }, { namespace: '~registry/v1' });
|
|
49
|
+
|
|
50
|
+
return clientSecret;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
this.notifications.serverError(error);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@action createTrackedElement(name, el) {
|
|
57
|
+
this[name] = el;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getTrackedElement(name) {
|
|
61
|
+
if (this[name] instanceof HTMLElement) {
|
|
62
|
+
return this[name];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { task, timeout } from 'ember-concurrency';
|
|
5
|
+
|
|
6
|
+
export default class ExploreCategoryController extends Controller {
|
|
7
|
+
@service store;
|
|
8
|
+
@tracked extensions = [];
|
|
9
|
+
@tracked query;
|
|
10
|
+
queryParams = ['query'];
|
|
11
|
+
|
|
12
|
+
@task({ restartable: true }) *search(event) {
|
|
13
|
+
this.query = event.target.value;
|
|
14
|
+
yield timeout(300);
|
|
15
|
+
|
|
16
|
+
if (this.query) {
|
|
17
|
+
this.extensions = yield this.store.query('registry-extension', { explore: 1, category: this.model.id, query: this.query });
|
|
18
|
+
} else {
|
|
19
|
+
this.extensions = yield this.store.query('registry-extension', { explore: 1, category: this.model.id });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { task, timeout } from 'ember-concurrency';
|
|
4
|
+
|
|
5
|
+
export default class ExploreIndexController extends Controller {
|
|
6
|
+
@tracked query;
|
|
7
|
+
|
|
8
|
+
@task({ restartable: true }) *search(event) {
|
|
9
|
+
const query = event.target.value;
|
|
10
|
+
if (query) {
|
|
11
|
+
this.query = query;
|
|
12
|
+
yield timeout(300);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
import { later } from '@ember/runloop';
|
|
5
|
+
|
|
6
|
+
export default class InstalledController extends Controller {
|
|
7
|
+
@service modalsManager;
|
|
8
|
+
@service currentUser;
|
|
9
|
+
@service notifications;
|
|
10
|
+
@service socket;
|
|
11
|
+
@service hostRouter;
|
|
12
|
+
|
|
13
|
+
@action about(extension) {
|
|
14
|
+
this.modalsManager.show('modals/extension-details', {
|
|
15
|
+
titleComponent: 'extension-modal-title',
|
|
16
|
+
modalClass: 'flb--extension-modal modal-lg',
|
|
17
|
+
modalHeaderClass: 'flb--extension-modal-header',
|
|
18
|
+
acceptButtonText: 'Done',
|
|
19
|
+
hideDeclineButton: true,
|
|
20
|
+
extension,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@action uninstall(extension) {
|
|
25
|
+
const uninstallChannel = `uninstall.${this.currentUser.companyId}.${extension.id}`;
|
|
26
|
+
|
|
27
|
+
this.modalsManager.show('modals/extension-uninstall', {
|
|
28
|
+
title: `Uninstall ${extension.name}`,
|
|
29
|
+
modalClass: 'flb--extension-modal modal-lg',
|
|
30
|
+
modalHeaderClass: 'flb--extension-modal-header',
|
|
31
|
+
acceptButtonText: 'Uninstall',
|
|
32
|
+
acceptButtonIcon: 'trash',
|
|
33
|
+
acceptButtonScheme: 'danger',
|
|
34
|
+
process: null,
|
|
35
|
+
step: null,
|
|
36
|
+
stepDescription: 'Awaiting uninstall to begin...',
|
|
37
|
+
progress: 0,
|
|
38
|
+
extension,
|
|
39
|
+
confirm: async (modal) => {
|
|
40
|
+
modal.startLoading();
|
|
41
|
+
|
|
42
|
+
// Listen for uninstall progress
|
|
43
|
+
this.socket.listen(uninstallChannel, ({ process, step, progress }) => {
|
|
44
|
+
let stepDescription;
|
|
45
|
+
switch (step) {
|
|
46
|
+
case 'server.uninstall':
|
|
47
|
+
stepDescription = '(1/3) Uninstalling extension...';
|
|
48
|
+
break;
|
|
49
|
+
|
|
50
|
+
case 'engine.uninstall':
|
|
51
|
+
stepDescription = '(2/3) Uninstalling extension...';
|
|
52
|
+
break;
|
|
53
|
+
|
|
54
|
+
case 'console.build':
|
|
55
|
+
stepDescription = '(3/3) Completing uninstall...';
|
|
56
|
+
break;
|
|
57
|
+
|
|
58
|
+
default:
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
modal.setOptions({ process, step, progress, stepDescription });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Start uninstall progress
|
|
65
|
+
modal.setOption('progress', 5);
|
|
66
|
+
|
|
67
|
+
// Run uninstall
|
|
68
|
+
try {
|
|
69
|
+
await extension.uninstall();
|
|
70
|
+
await this.hostRouter.refresh();
|
|
71
|
+
this.notifications.info(`${extension.name} is now Uninstalled.`);
|
|
72
|
+
later(
|
|
73
|
+
this,
|
|
74
|
+
() => {
|
|
75
|
+
window.location.reload(true);
|
|
76
|
+
},
|
|
77
|
+
600
|
|
78
|
+
);
|
|
79
|
+
modal.done();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
this.notifications.serverError(error);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
|
|
5
|
+
export default class PurchasedController extends Controller {
|
|
6
|
+
@service modalsManager;
|
|
7
|
+
|
|
8
|
+
@action about(extension) {
|
|
9
|
+
this.modalsManager.show('modals/extension-details', {
|
|
10
|
+
titleComponent: 'extension-modal-title',
|
|
11
|
+
modalClass: 'flb--extension-modal modal-lg',
|
|
12
|
+
modalHeaderClass: 'flb--extension-modal-header',
|
|
13
|
+
acceptButtonText: 'Done',
|
|
14
|
+
hideDeclineButton: true,
|
|
15
|
+
extension,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
package/addon/engine.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import Engine from '@ember/engine';
|
|
2
|
+
import loadInitializers from 'ember-load-initializers';
|
|
3
|
+
import Resolver from 'ember-resolver';
|
|
4
|
+
import config from './config/environment';
|
|
5
|
+
import services from '@fleetbase/ember-core/exports/services';
|
|
6
|
+
import ExtensionReviewerControlComponent from './components/extension-reviewer-control';
|
|
7
|
+
import ExtensionPendingPublishViewerComponent from './components/extension-pending-publish-viewer';
|
|
8
|
+
|
|
9
|
+
const { modulePrefix } = config;
|
|
10
|
+
const externalRoutes = ['console', 'extensions'];
|
|
11
|
+
|
|
12
|
+
export default class RegistryBridgeEngine extends Engine {
|
|
13
|
+
modulePrefix = modulePrefix;
|
|
14
|
+
Resolver = Resolver;
|
|
15
|
+
dependencies = {
|
|
16
|
+
services,
|
|
17
|
+
externalRoutes,
|
|
18
|
+
};
|
|
19
|
+
setupExtension = function (app, engine, universe) {
|
|
20
|
+
// Register menu item in header
|
|
21
|
+
universe.registerHeaderMenuItem('Extensions', 'console.extensions', { icon: 'shapes', priority: 99 });
|
|
22
|
+
// Register admin controls
|
|
23
|
+
universe.registerAdminMenuPanel(
|
|
24
|
+
'Extensions Registry',
|
|
25
|
+
[
|
|
26
|
+
{
|
|
27
|
+
title: 'Extensions Awaiting Review',
|
|
28
|
+
icon: 'gavel',
|
|
29
|
+
component: ExtensionReviewerControlComponent,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
title: 'Extensions Pending Publish',
|
|
33
|
+
icon: 'rocket',
|
|
34
|
+
component: ExtensionPendingPublishViewerComponent,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
{
|
|
38
|
+
slug: 'extension-registry',
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
loadInitializers(RegistryBridgeEngine, modulePrefix);
|