@fleetbase/registry-bridge-engine 0.0.12 → 0.0.13

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.
Files changed (31) hide show
  1. package/addon/components/extension-card.js +8 -2
  2. package/addon/components/modals/extension-details.hbs +7 -4
  3. package/addon/controllers/installed.js +2 -0
  4. package/addon/engine.js +1 -1
  5. package/addon/routes/application.js +11 -0
  6. package/addon/routes/developers/analytics.js +11 -0
  7. package/addon/routes/developers/credentials.js +11 -0
  8. package/addon/routes/developers/extensions/edit.js +11 -0
  9. package/addon/routes/developers/extensions/index.js +11 -0
  10. package/addon/routes/developers/extensions/new.js +14 -1
  11. package/addon/routes/developers/extensions.js +14 -1
  12. package/addon/routes/developers/payments/index.js +11 -0
  13. package/addon/routes/developers/payments/onboard.js +8 -1
  14. package/addon/routes/developers/payments.js +14 -1
  15. package/addon/routes/explore/category.js +11 -0
  16. package/addon/routes/explore/index.js +11 -0
  17. package/addon/routes/installed.js +11 -0
  18. package/addon/routes/purchased.js +11 -0
  19. package/addon/styles/registry-bridge-engine.css +106 -0
  20. package/addon/templates/application.hbs +9 -15
  21. package/addon/templates/developers/analytics.hbs +2 -0
  22. package/addon/templates/developers/credentials.hbs +1 -1
  23. package/addon/templates/developers/extensions/edit.hbs +2 -1
  24. package/addon/templates/developers/extensions/index.hbs +1 -1
  25. package/addon/templates/developers/extensions/new.hbs +1 -1
  26. package/addon/templates/developers/payments/index.hbs +1 -1
  27. package/composer.json +2 -2
  28. package/extension.json +1 -1
  29. package/package.json +4 -3
  30. package/server/src/Auth/Schemas/RegistryBridge.php +215 -0
  31. package/translations/en-us.yaml +1 -0
@@ -26,6 +26,7 @@ export default class ExtensionCardComponent extends Component {
26
26
  @service fetch;
27
27
  @service stripe;
28
28
  @service urlSearchParams;
29
+ @service abilities;
29
30
  @tracked extension;
30
31
 
31
32
  constructor(owner, { extension }) {
@@ -45,6 +46,11 @@ export default class ExtensionCardComponent extends Component {
45
46
  const isAlreadyPurchased = this.extension.is_purchased === true;
46
47
  const isAlreadyInstalled = this.extension.is_installed === true;
47
48
  const isPaymentRequired = !isAuthor && this.extension.payment_required === true && isAlreadyPurchased === false;
49
+ const userCannotPurchase = isPaymentRequired && this.abilities.cannot('registry-bridge purchase extension');
50
+ let acceptButtonText = isPaymentRequired ? `Purchase for ${formatCurrency(this.extension.price, this.extension.currency)}` : isAlreadyInstalled ? 'Installed' : 'Install';
51
+ if (this.abilities.cannot('registry-bridge install extension')) {
52
+ acceptButtonText = 'Unauthorized to Install';
53
+ }
48
54
  const goBack = async (modal) => {
49
55
  await modal.done();
50
56
  later(
@@ -65,9 +71,9 @@ export default class ExtensionCardComponent extends Component {
65
71
  titleComponent: 'extension-modal-title',
66
72
  modalClass: 'flb--extension-modal modal-lg',
67
73
  modalHeaderClass: 'flb--extension-modal-header',
68
- acceptButtonText: isPaymentRequired ? `Purchase for ${formatCurrency(this.extension.price, this.extension.currency)}` : isAlreadyInstalled ? 'Installed' : 'Install',
74
+ acceptButtonText,
69
75
  acceptButtonIcon: isPaymentRequired ? 'credit-card' : isAlreadyInstalled ? 'check' : 'download',
70
- acceptButtonDisabled: isAlreadyInstalled,
76
+ acceptButtonDisabled: this.abilities.cannot('registry-bridge install extension') || isAlreadyInstalled || userCannotPurchase,
71
77
  acceptButtonScheme: isPaymentRequired ? 'success' : 'primary',
72
78
  declineButtonText: 'Done',
73
79
  process: null,
@@ -27,11 +27,14 @@
27
27
  </EmberWormhole>
28
28
  {{/if}}
29
29
  {{/if}}
30
- <div>
31
- <h3 class="dark:text-white font-semibold mb-1">{{t "registry-bridge.component.extension-details-modal.overview"}}</h3>
32
- <div class="space-y-1">
30
+ <div class="space-y-3">
31
+ <div>
32
+ <h3 class="dark:text-white font-semibold mb-1">{{t "registry-bridge.component.extension-details-modal.description"}}</h3>
33
33
  <p class="dark:text-gray-200 text-sm">{{this.extension.description}}</p>
34
- <p class="dark:text-gray-200 text-sm">{{html-safe this.extension.promotional_text}}</p>
34
+ </div>
35
+ <div>
36
+ <h3 class="dark:text-white font-semibold mb-1">{{t "registry-bridge.component.extension-details-modal.overview"}}</h3>
37
+ <div class="extension-details-promo-content dark:text-gray-200 text-sm">{{html-safe this.extension.promotional_text}}</div>
35
38
  </div>
36
39
  </div>
37
40
  <div>
@@ -9,6 +9,7 @@ export default class InstalledController extends Controller {
9
9
  @service notifications;
10
10
  @service socket;
11
11
  @service hostRouter;
12
+ @service abilities;
12
13
 
13
14
  @action about(extension) {
14
15
  this.modalsManager.show('modals/extension-details', {
@@ -31,6 +32,7 @@ export default class InstalledController extends Controller {
31
32
  acceptButtonText: 'Uninstall',
32
33
  acceptButtonIcon: 'trash',
33
34
  acceptButtonScheme: 'danger',
35
+ acceptButtonDisabled: this.abilities.cannot('registry-bridge uninstall extension'),
34
36
  process: null,
35
37
  step: null,
36
38
  stepDescription: 'Awaiting uninstall to begin...',
package/addon/engine.js CHANGED
@@ -19,7 +19,7 @@ export default class RegistryBridgeEngine extends Engine {
19
19
  };
20
20
  setupExtension = function (app, engine, universe) {
21
21
  // Register menu item in header
22
- universe.registerHeaderMenuItem('Extensions', 'console.extensions', { icon: 'shapes', priority: 99 });
22
+ universe.registerHeaderMenuItem('Extensions', 'console.extensions', { icon: 'shapes', priority: 99, slug: 'registry-bridge' });
23
23
  // Register admin controls
24
24
  universe.registerAdminMenuPanel(
25
25
  'Extensions Registry',
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class ApplicationRoute extends Route {
5
5
  @service fetch;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge see extension')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  async setupController(controller) {
8
19
  super.setupController(...arguments);
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class DevelopersAnalyticsRoute extends Route {
5
5
  @service store;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge list extension-analytic')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  model() {
8
19
  return this.store.query('registry-extension', { is_author: 1 });
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class DevelopersCredentialsRoute extends Route {
5
5
  @service fetch;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge list registry-token')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  model() {
8
19
  return this.fetch.get('auth/registry-tokens', {}, { namespace: '~registry/v1' });
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class DevelopersExtensionsEditRoute extends Route {
5
5
  @service store;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge update extension-bundle')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  model(params) {
8
19
  return this.store.queryRecord('registry-extension', { public_id: params.public_id, single: true });
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class DevelopersExtensionsIndexRoute extends Route {
5
5
  @service store;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge list extension-bundle')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  model() {
8
19
  return this.store.query('registry-extension', { is_author: 1 });
@@ -1,3 +1,16 @@
1
1
  import Route from '@ember/routing/route';
2
+ import { inject as service } from '@ember/service';
2
3
 
3
- export default class DevelopersExtensionsNewRoute extends Route {}
4
+ export default class DevelopersExtensionsNewRoute extends Route {
5
+ @service notifications;
6
+ @service hostRouter;
7
+ @service abilities;
8
+ @service intl;
9
+
10
+ beforeModel() {
11
+ if (this.abilities.cannot('registry-bridge create extension-bundle')) {
12
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
13
+ return this.hostRouter.transitionTo('console');
14
+ }
15
+ }
16
+ }
@@ -1,3 +1,16 @@
1
1
  import Route from '@ember/routing/route';
2
+ import { inject as service } from '@ember/service';
2
3
 
3
- export default class DevelopersExtensionsRoute extends Route {}
4
+ export default class DevelopersExtensionsRoute extends Route {
5
+ @service notifications;
6
+ @service hostRouter;
7
+ @service abilities;
8
+ @service intl;
9
+
10
+ beforeModel() {
11
+ if (this.abilities.cannot('registry-bridge list extension-bundle')) {
12
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
13
+ return this.hostRouter.transitionTo('console');
14
+ }
15
+ }
16
+ }
@@ -3,6 +3,10 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class DevelopersPaymentsIndexRoute extends Route {
5
5
  @service fetch;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
6
10
 
7
11
  queryParams = {
8
12
  page: { refreshModel: true },
@@ -11,6 +15,13 @@ export default class DevelopersPaymentsIndexRoute extends Route {
11
15
  query: { refreshModel: true },
12
16
  };
13
17
 
18
+ beforeModel() {
19
+ if (this.abilities.cannot('registry-bridge list extension-payment')) {
20
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
21
+ return this.hostRouter.transitionTo('console');
22
+ }
23
+ }
24
+
14
25
  model() {
15
26
  return this.fetch.get('payments/author-received', {}, { namespace: '~registry/v1' });
16
27
  }
@@ -3,10 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class DevelopersPaymentsOnboardRoute extends Route {
5
5
  @service fetch;
6
- @service hostRouter;
7
6
  @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
8
10
 
9
11
  async beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge onboard extension-payment')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+
10
17
  try {
11
18
  const { hasStripeConnectAccount } = await this.fetch.get('payments/has-stripe-connect-account', {}, { namespace: '~registry/v1' });
12
19
  if (hasStripeConnectAccount) {
@@ -1,3 +1,16 @@
1
1
  import Route from '@ember/routing/route';
2
+ import { inject as service } from '@ember/service';
2
3
 
3
- export default class DevelopersPaymentsRoute extends Route {}
4
+ export default class DevelopersPaymentsRoute extends Route {
5
+ @service notifications;
6
+ @service hostRouter;
7
+ @service abilities;
8
+ @service intl;
9
+
10
+ beforeModel() {
11
+ if (this.abilities.cannot('registry-bridge list extension-payment')) {
12
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
13
+ return this.hostRouter.transitionTo('console');
14
+ }
15
+ }
16
+ }
@@ -3,6 +3,10 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class ExploreCategoryRoute extends Route {
5
5
  @service store;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
6
10
 
7
11
  queryParams = {
8
12
  query: {
@@ -10,6 +14,13 @@ export default class ExploreCategoryRoute extends Route {
10
14
  },
11
15
  };
12
16
 
17
+ beforeModel() {
18
+ if (this.abilities.cannot('registry-bridge list extension')) {
19
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
20
+ return this.hostRouter.transitionTo('console');
21
+ }
22
+ }
23
+
13
24
  model({ slug }) {
14
25
  return this.store.queryRecord('category', { slug, for: 'extension_category', core_category: 1, single: 1 });
15
26
  }
@@ -3,6 +3,10 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class ExploreIndexRoute extends Route {
5
5
  @service store;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
6
10
 
7
11
  queryParams = {
8
12
  query: {
@@ -10,6 +14,13 @@ export default class ExploreIndexRoute extends Route {
10
14
  },
11
15
  };
12
16
 
17
+ beforeModel() {
18
+ if (this.abilities.cannot('registry-bridge list extension')) {
19
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
20
+ return this.hostRouter.transitionTo('console');
21
+ }
22
+ }
23
+
13
24
  model(params) {
14
25
  const { query } = params;
15
26
  return this.store.query('registry-extension', { explore: 1, query });
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class InstalledRoute extends Route {
5
5
  @service fetch;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge list extension-install')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  model(params = {}) {
8
19
  return this.fetch.get('registry-extensions/installed', params, { namespace: '~registry/v1', normalizeToEmberData: true, modelType: 'registry-extension' });
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
3
3
 
4
4
  export default class PurchasedRoute extends Route {
5
5
  @service fetch;
6
+ @service notifications;
7
+ @service hostRouter;
8
+ @service abilities;
9
+ @service intl;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('registry-bridge list extension-purchase')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console');
15
+ }
16
+ }
6
17
 
7
18
  model(params = {}) {
8
19
  return this.fetch.get('registry-extensions/purchased', params, { namespace: '~registry/v1', normalizeToEmberData: true, modelType: 'registry-extension' });
@@ -171,3 +171,109 @@ body[data-theme='dark'] .self-managed-install-instructions {
171
171
  font-size: 0.75rem;
172
172
  line-height: 1rem;
173
173
  }
174
+
175
+ .extension-details-promo-content {
176
+ padding: 0.5rem;
177
+ background-color: #f9fafb;
178
+ color: #000;
179
+ }
180
+
181
+ body[data-theme='dark'] .extension-details-promo-content {
182
+ padding: 0.5rem;
183
+ background-color: #111827;
184
+ color: #f9fafb;
185
+ }
186
+
187
+ .extension-details-promo-content hr {
188
+ border: none;
189
+ border-top: 1px solid #e5e7eb;
190
+ margin: 0.5rem 0;
191
+ }
192
+
193
+ body[data-theme='dark'] .extension-details-promo-content hr {
194
+ border-top: 1px solid #374151;
195
+ }
196
+
197
+ .extension-details-promo-content ol,
198
+ .extension-details-promo-content ul {
199
+ padding-left: 25px;
200
+ }
201
+
202
+ .extension-details-promo-content ol {
203
+ list-style: decimal;
204
+ }
205
+
206
+ .extension-details-promo-content ul {
207
+ list-style: disc;
208
+ }
209
+
210
+ .extension-details-promo-content blockquote {
211
+ border-left: 3px #e2e8f0 solid;
212
+ padding-left: 0.5rem;
213
+ margin-left: 0.25rem;
214
+ font-style: italic;
215
+ }
216
+
217
+ body[data-theme='dark'] .extension-details-promo-content blockquote {
218
+ border-left: 3px #4b5563 solid;
219
+ }
220
+
221
+ .extension-details-promo-content pre {
222
+ white-space: pre;
223
+ font-family: monospace;
224
+ padding: 0.25rem 0.75rem;
225
+ border-radius: 0.25rem;
226
+ background-color: #f3f4f6;
227
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 5%);
228
+ }
229
+
230
+ body[data-theme='dark'] .extension-details-promo-content pre {
231
+ background-color: #1f2937;
232
+ }
233
+
234
+ .extension-details-promo-content pre > code {
235
+ font-family: monospace;
236
+ }
237
+
238
+ .extension-details-promo-content table {
239
+ border-collapse: collapse;
240
+ margin: 0;
241
+ overflow: hidden;
242
+ table-layout: fixed;
243
+ width: 100%;
244
+ }
245
+
246
+ .extension-details-promo-content table td,
247
+ .extension-details-promo-content table th {
248
+ border: 1px solid #d1d5db;
249
+ box-sizing: border-box;
250
+ min-width: 1em;
251
+ padding: 6px 8px;
252
+ position: relative;
253
+ vertical-align: top;
254
+ }
255
+
256
+ body[data-theme='dark'] .extension-details-promo-content table td,
257
+ body[data-theme='dark'] .extension-details-promo-content table th {
258
+ border: 1px solid #374151;
259
+ }
260
+
261
+ .extension-details-promo-content table td > *,
262
+ .extension-details-promo-content table th > * {
263
+ margin-bottom: 0;
264
+ }
265
+
266
+ .extension-details-promo-content table th {
267
+ background-color: #e5e7eb;
268
+ font-weight: bold;
269
+ text-align: left;
270
+ }
271
+
272
+ body[data-theme='dark'] .extension-details-promo-content table th {
273
+ background-color: #1f2937;
274
+ }
275
+
276
+ .extension-details-promo-content .tableWrapper {
277
+ margin: 1.5rem 0;
278
+ overflow-x: auto;
279
+ }
@@ -1,23 +1,17 @@
1
1
  <EmberWormhole @to="sidebar-menu-items">
2
- <Layout::Sidebar::Item @route="console.extensions.installed" @icon="inbox">Installed</Layout::Sidebar::Item>
3
- <Layout::Sidebar::Item @route="console.extensions.purchased" @icon="bag-shopping">Purchased</Layout::Sidebar::Item>
4
- <Layout::Sidebar::Panel @open={{true}} @title="Explore">
5
- <Layout::Sidebar::Item @route="console.extensions.explore.index" @icon="shapes">Explore All</Layout::Sidebar::Item>
2
+ <Layout::Sidebar::Item @route="console.extensions.installed" @icon="inbox" @permission="registry-bridge list extension-install" @visible={{can "registry-bridge see extension-install"}}>Installed</Layout::Sidebar::Item>
3
+ <Layout::Sidebar::Item @route="console.extensions.purchased" @icon="bag-shopping" @permission="registry-bridge list extension-purchase" @visible={{can "registry-bridge see extension-purchase"}}>Purchased</Layout::Sidebar::Item>
4
+ <Layout::Sidebar::Panel @open={{true}} @title="Explore" @visible={{can "registry-bridge see extension"}}>
5
+ <Layout::Sidebar::Item @route="console.extensions.explore.index" @icon="shapes" @permission="registry-bridge list extension">Explore All</Layout::Sidebar::Item>
6
6
  {{#each this.categories as |category|}}
7
- <LinkTo @route="explore.category" @model={{category}} class="next-nav-item">
8
- <div class="next-nav-item-icon-container">
9
- <FaIcon @icon={{category.icon}} @size="sm" />
10
- </div>
11
- <div class="truncate w-10/12">{{category.name}}</div>
12
- <div class="next-nav-item-right-side"></div>
13
- </LinkTo>
7
+ <Layout::Sidebar::Item @route="console.extensions.explore.category" @model={{category}} @icon={{category.icon}} @permission="registry-bridge list extension">{{category.name}}</Layout::Sidebar::Item>
14
8
  {{/each}}
15
9
  </Layout::Sidebar::Panel>
16
10
  <Layout::Sidebar::Panel @open={{true}} @title="Developers">
17
- <Layout::Sidebar::Item @route="console.extensions.developers.extensions" @icon="box-archive">Extensions</Layout::Sidebar::Item>
18
- <Layout::Sidebar::Item @route="console.extensions.developers.analytics" @icon="chart-simple">Analytics</Layout::Sidebar::Item>
19
- <Layout::Sidebar::Item @route="console.extensions.developers.payments" @icon="cash-register">Payments</Layout::Sidebar::Item>
20
- <Layout::Sidebar::Item @route="console.extensions.developers.credentials" @icon="key">Credentials</Layout::Sidebar::Item>
11
+ <Layout::Sidebar::Item @route="console.extensions.developers.extensions" @icon="box-archive" @permission="registry-bridge list extension-bundle" @visible={{can "registry-bridge see extension-bundle"}}>Extensions</Layout::Sidebar::Item>
12
+ <Layout::Sidebar::Item @route="console.extensions.developers.analytics" @icon="chart-simple" @permission="registry-bridge list extension-analytic" @visible={{can "registry-bridge see extension-analytic"}}>Analytics</Layout::Sidebar::Item>
13
+ <Layout::Sidebar::Item @route="console.extensions.developers.payments" @icon="cash-register" @permission="registry-bridge list extension-payment" @visible={{can "registry-bridge see extension-payment"}}>Payments</Layout::Sidebar::Item>
14
+ <Layout::Sidebar::Item @route="console.extensions.developers.credentials" @icon="key" @permission="registry-bridge list registry-token" @visible={{can "registry-bridge see registry-token"}}>Credentials</Layout::Sidebar::Item>
21
15
  </Layout::Sidebar::Panel>
22
16
  <Spacer @height="200px" />
23
17
  </EmberWormhole>
@@ -9,6 +9,8 @@
9
9
  @size="xs"
10
10
  @iconPrefix="fas"
11
11
  @triggerClass="hidden md:flex"
12
+ @permission="registry-bridge list extension"
13
+ @disabled={{not @model}}
12
14
  as |dd|
13
15
  >
14
16
  <div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
@@ -1,5 +1,5 @@
1
1
  <Layout::Section::Header @title="Credentials">
2
- <Button @type="primary" @icon="plus" @iconPrefix="fas" @text="Create new credentials" class="mr-2" @onClick={{this.createCredentials}} />
2
+ <Button @type="primary" @icon="plus" @iconPrefix="fas" @text="Create new credentials" class="mr-2" @onClick={{this.createCredentials}} @permission="registry-bridge create registry-token" />
3
3
  </Layout::Section::Header>
4
4
 
5
5
  <Layout::Section::Body class="overflow-y-scroll h-full">
@@ -3,7 +3,7 @@
3
3
  <Badge @status={{@model.status}} />
4
4
  </div>
5
5
  <Button @type="default" @size="sm" @icon="arrow-left" @text={{t "common.back"}} @onClick={{transition-to "developers.extensions"}} @wrapperClass="mr-2" />
6
- <Button @type="primary" @size="sm" @icon="save" @text={{t "common.save"}} @onClick={{perform this.save}} @isLoading={{not this.save.isIdle}} @wrapperClass="mr-2" />
6
+ <Button @type="primary" @size="sm" @icon="save" @text={{t "common.save"}} @onClick={{perform this.save}} @isLoading={{not this.save.isIdle}} @wrapperClass="mr-2" @permission="registry-bridge update registry-bundle" />
7
7
  <Button
8
8
  @type="magic"
9
9
  @size="sm"
@@ -13,6 +13,7 @@
13
13
  @onClick={{this.submitForReview}}
14
14
  @disabled={{not this.isReady}}
15
15
  @isLoading={{not this.startReview.isIdle}}
16
+ @permission="registry-bridge submit registry-bundle"
16
17
  />
17
18
  </Layout::Section::Header>
18
19
 
@@ -1,5 +1,5 @@
1
1
  <Layout::Section::Header @title={{t "registry-bridge.developers.extensions.extensions"}}>
2
- <Button @type="primary" @size="sm" @icon="circle-plus" @text={{t "registry-bridge.developers.extensions.create-new-extension"}} @onClick={{transition-to "developers.extensions.new"}} />
2
+ <Button @type="primary" @size="sm" @icon="circle-plus" @text={{t "registry-bridge.developers.extensions.create-new-extension"}} @onClick={{transition-to "developers.extensions.new"}} @permission="registry-bridge create registry-bundle" />
3
3
  </Layout::Section::Header>
4
4
 
5
5
  <Layout::Section::Body class="overflow-y-scroll h-full">
@@ -29,7 +29,7 @@
29
29
  </InputGroup>
30
30
  </ContentPanel>
31
31
  <div class="mt-4 flex items-center space-x-4">
32
- <Button @size="lg" @type="primary" @text="Continue" @icon="check" @onClick={{perform this.save}} @isLoading={{not this.save.isIdle}} />
32
+ <Button @size="lg" @type="primary" @text="Continue" @icon="check" @onClick={{perform this.save}} @isLoading={{not this.save.isIdle}} @permission="registry-bridge create registry-bundle" />
33
33
  <Button @size="lg" @type="default" @text="Cancel" @icon="times" @onClick={{this.cancel}} />
34
34
  </div>
35
35
  </div>
@@ -32,7 +32,7 @@
32
32
  <div class="flex flex-col items-center justify-center">
33
33
  <h1 class="text-lg font-semibold mb-1">Your account is not setup to accept payments yet.</h1>
34
34
  <p class="text-sm mb-2">To accept payments for extensions, you must complete the onboard process via Stripe.</p>
35
- <Button @type="primary" @size="lg" @text="Start payments onboard" @onClick={{transition-to "developers.payments.onboard"}} />
35
+ <Button @type="primary" @size="lg" @text="Start payments onboard" @onClick={{transition-to "developers.payments.onboard"}} @permission="registry-bridge onboard extension-payment" />
36
36
  </div>
37
37
  </div>
38
38
  </div>
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/registry-bridge",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Internal Bridge between Fleetbase API and Extensions Registry",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "require": {
22
22
  "php": "^8.0",
23
- "fleetbase/core-api": "^1.5.1",
23
+ "fleetbase/core-api": "^1.5.3",
24
24
  "laravel/cashier": "^15.2.1",
25
25
  "php-http/guzzle7-adapter": "^1.0",
26
26
  "psr/http-factory-implementation": "*",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Registry Bridge",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Internal Bridge between Fleetbase API and Extensions Registry",
5
5
  "repository": "https://github.com/fleetbase/registry-bridge",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/registry-bridge-engine",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Internal Bridge between Fleetbase API and Extensions Registry",
5
5
  "fleetbase": {
6
6
  "route": "extensions"
@@ -39,11 +39,12 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@babel/core": "^7.23.2",
42
- "@fleetbase/ember-core": "^0.2.14",
43
- "@fleetbase/ember-ui": "^0.2.21",
42
+ "@fleetbase/ember-core": "^0.2.17",
43
+ "@fleetbase/ember-ui": "^0.2.24",
44
44
  "@fortawesome/ember-fontawesome": "^2.0.0",
45
45
  "@fortawesome/fontawesome-svg-core": "6.4.0",
46
46
  "@fortawesome/free-solid-svg-icons": "6.4.0",
47
+ "@fortawesome/free-brands-svg-icons": "6.4.0",
47
48
  "@stripe/connect-js": "^3.3.10",
48
49
  "ember-auto-import": "^2.6.3",
49
50
  "ember-cli-babel": "^8.2.0",
@@ -0,0 +1,215 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Auth\Schemas;
4
+
5
+ class RegistryBridge
6
+ {
7
+ /**
8
+ * The permission schema Name.
9
+ */
10
+ public string $name = 'registry-bridge';
11
+
12
+ /**
13
+ * The permission schema Polict Name.
14
+ */
15
+ public string $policyName = 'RegistryBridge';
16
+
17
+ /**
18
+ * Guards these permissions should apply to.
19
+ */
20
+ public array $guards = ['sanctum'];
21
+
22
+ /**
23
+ * The permission schema resources.
24
+ */
25
+ public array $resources = [
26
+ [
27
+ 'name' => 'registry-token',
28
+ 'actions' => ['export'],
29
+ ],
30
+ [
31
+ 'name' => 'extension',
32
+ 'actions' => ['uninstall', 'install', 'purchase'],
33
+ ],
34
+ [
35
+ 'name' => 'extension-bundle',
36
+ 'actions' => ['submit'],
37
+ 'remove_actions' => [],
38
+ ],
39
+ [
40
+ 'name' => 'extension-purchase',
41
+ 'actions' => [],
42
+ 'remove_actions' => ['create', 'update', 'delete'],
43
+ ],
44
+ [
45
+ 'name' => 'extension-install',
46
+ 'actions' => [],
47
+ 'remove_actions' => ['create', 'update', 'delete'],
48
+ ],
49
+ [
50
+ 'name' => 'extension-analytic',
51
+ 'actions' => [],
52
+ 'remove_actions' => ['create', 'update', 'delete'],
53
+ ],
54
+ [
55
+ 'name' => 'extension-payment',
56
+ 'actions' => ['onboard'],
57
+ 'remove_actions' => ['create', 'update', 'delete'],
58
+ ],
59
+ ];
60
+
61
+ /**
62
+ * Policies provided by this schema.
63
+ */
64
+ public array $policies = [
65
+ [
66
+ 'name' => 'ExtensionDeveloper',
67
+ 'description' => 'Policy for developing and publishing extensions.',
68
+ 'permissions' => [
69
+ 'see extension',
70
+ 'see registry-token',
71
+ 'list registry-token',
72
+ 'create registry-token',
73
+ 'see extension-bundle',
74
+ 'list extension-bundle',
75
+ 'view extension-bundle',
76
+ 'create extension-bundle',
77
+ 'update extension-bundle',
78
+ 'delete extension-bundle',
79
+ 'submit extension-bundle',
80
+ 'see extension-analytic',
81
+ 'view extension-analytic',
82
+ 'see extension-payment',
83
+ 'view extension-payment',
84
+ 'list extension',
85
+ ],
86
+ ],
87
+ [
88
+ 'name' => 'ExtensionMarketing',
89
+ 'description' => 'Policy to provide insight for marketing extensions.',
90
+ 'permissions' => [
91
+ 'see extension',
92
+ 'see extension-bundle',
93
+ 'list extension-bundle',
94
+ 'update extension-bundle',
95
+ 'see extension-analytic',
96
+ 'view extension-analytic',
97
+ 'list extension-analytic',
98
+ 'list extension',
99
+ ],
100
+ ],
101
+ [
102
+ 'name' => 'ExtensionFinance',
103
+ 'description' => 'Policy for managing finance and accounting for extensions.',
104
+ 'permissions' => [
105
+ 'see extension',
106
+ 'see extension-analytic',
107
+ 'view extension-analytic',
108
+ 'list extension-analytic',
109
+ 'see extension-payment',
110
+ 'view extension-payment',
111
+ 'list extension-payment',
112
+ 'onboard extension-payment',
113
+ 'list extension',
114
+ ],
115
+ ],
116
+ [
117
+ 'name' => 'ExtensionSales',
118
+ 'description' => 'Policy for managing sales reports of extensions.',
119
+ 'permissions' => [
120
+ 'see extension',
121
+ 'see extension-analytic',
122
+ 'view extension-analytic',
123
+ 'list extension-analytic',
124
+ 'see extension-payment',
125
+ 'view extension-payment',
126
+ 'list extension-payment',
127
+ 'see extension-purchase',
128
+ 'view extension-purchase',
129
+ 'list extension-purchase',
130
+ 'list extension',
131
+ ],
132
+ ],
133
+ [
134
+ 'name' => 'ExtensionManager',
135
+ 'description' => 'Policy for complete management of extensions.',
136
+ 'permissions' => [
137
+ 'see extension',
138
+ 'see extension-bundle',
139
+ 'list extension-bundle',
140
+ 'view extension-bundle',
141
+ 'create extension-bundle',
142
+ 'update extension-bundle',
143
+ 'delete extension-bundle',
144
+ 'submit extension-bundle',
145
+ 'see extension-analytic',
146
+ 'view extension-analytic',
147
+ 'list extension-analytic',
148
+ 'see extension-payment',
149
+ 'view extension-payment',
150
+ 'list extension-payment',
151
+ 'list extension',
152
+ ],
153
+ ],
154
+ ];
155
+
156
+ /**
157
+ * Roles provided by this schema.
158
+ */
159
+ public array $roles = [
160
+ [
161
+ 'name' => 'Extension Developer',
162
+ 'description' => 'Role for developing and publishing extensions.',
163
+ 'policies' => [
164
+ 'ExtensionDeveloper',
165
+ ],
166
+ ],
167
+ [
168
+ 'name' => 'Quality Assurance',
169
+ 'description' => 'Role for testing extensions.',
170
+ 'permissions' => [
171
+ 'see extension',
172
+ 'list extension',
173
+ 'view extension',
174
+ 'see extension-bundle',
175
+ 'list extension-bundle',
176
+ 'view extension-bundle',
177
+ 'create extension-bundle',
178
+ 'update extension-bundle',
179
+ 'delete extension-bundle',
180
+ 'submit extension-bundle',
181
+ ],
182
+ ],
183
+ [
184
+ 'name' => 'Extension Auditor',
185
+ 'description' => 'Role for auditing and creating reports for extensions.',
186
+ 'permissions' => [
187
+ 'see extension',
188
+ 'list extension',
189
+ 'view extension',
190
+ 'see extension-bundle',
191
+ 'list extension-bundle',
192
+ 'view extension-bundle',
193
+ 'see extension-analytic',
194
+ 'list extension-analytic',
195
+ 'view extension-analytic',
196
+ 'see extension-payment',
197
+ 'list extension-payment',
198
+ 'view extension-payment',
199
+ ],
200
+ ],
201
+ [
202
+ 'name' => 'Extension Admin',
203
+ 'description' => 'Role for full control of extensions.',
204
+ 'permissions' => [
205
+ '* extension',
206
+ '* extension-bundle',
207
+ '* extension-analytic',
208
+ '* extension-payment',
209
+ '* extension-purchase',
210
+ '* extension-install',
211
+ '* registry-token',
212
+ ],
213
+ ],
214
+ ];
215
+ }
@@ -12,6 +12,7 @@ registry-bridge:
12
12
  extension-details-modal:
13
13
  extension: Extension
14
14
  author: Author
15
+ description: Description
15
16
  overview: Overview
16
17
  details: Details
17
18
  version: Version