@fleetbase/registry-bridge-engine 0.0.11 → 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 (42) hide show
  1. package/addon/components/extension-card.hbs +5 -0
  2. package/addon/components/extension-card.js +54 -3
  3. package/addon/components/extension-form.hbs +20 -2
  4. package/addon/components/extension-form.js +57 -0
  5. package/addon/components/modals/extension-details.hbs +40 -18
  6. package/addon/components/modals/self-managed-install-instructions.hbs +40 -0
  7. package/addon/controllers/installed.js +2 -0
  8. package/addon/engine.js +1 -1
  9. package/addon/models/registry-extension.js +2 -0
  10. package/addon/routes/application.js +11 -0
  11. package/addon/routes/developers/analytics.js +11 -0
  12. package/addon/routes/developers/credentials.js +11 -0
  13. package/addon/routes/developers/extensions/edit.js +11 -0
  14. package/addon/routes/developers/extensions/index.js +11 -0
  15. package/addon/routes/developers/extensions/new.js +14 -1
  16. package/addon/routes/developers/extensions.js +14 -1
  17. package/addon/routes/developers/payments/index.js +11 -0
  18. package/addon/routes/developers/payments/onboard.js +8 -1
  19. package/addon/routes/developers/payments.js +14 -1
  20. package/addon/routes/explore/category.js +11 -0
  21. package/addon/routes/explore/index.js +11 -0
  22. package/addon/routes/installed.js +11 -0
  23. package/addon/routes/purchased.js +11 -0
  24. package/addon/styles/registry-bridge-engine.css +137 -0
  25. package/addon/templates/application.hbs +9 -15
  26. package/addon/templates/developers/analytics.hbs +2 -0
  27. package/addon/templates/developers/credentials.hbs +1 -1
  28. package/addon/templates/developers/extensions/edit.hbs +2 -1
  29. package/addon/templates/developers/extensions/index.hbs +1 -1
  30. package/addon/templates/developers/extensions/new.hbs +1 -1
  31. package/addon/templates/developers/payments/index.hbs +1 -1
  32. package/app/components/modals/self-managed-install-instructions.js +1 -0
  33. package/composer.json +2 -2
  34. package/extension.json +1 -1
  35. package/package.json +4 -3
  36. package/server/migrations/2024_08_02_072214_add_self_managed_column_to_registry_extensions_table.php +28 -0
  37. package/server/src/Auth/Schemas/RegistryBridge.php +215 -0
  38. package/server/src/Http/Controllers/Internal/v1/RegistryController.php +46 -0
  39. package/server/src/Models/RegistryExtension.php +45 -0
  40. package/server/src/Models/RegistryExtensionBundle.php +2 -2
  41. package/server/src/routes.php +2 -1
  42. package/translations/en-us.yaml +14 -1
@@ -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' });
@@ -140,3 +140,140 @@ body[data-theme='dark'] .extension-card-container > .extension-card-body-contain
140
140
  margin-left: 2rem;
141
141
  margin-bottom: 2rem;
142
142
  }
143
+
144
+ .self-managed-install-instructions {
145
+ list-style: decimal;
146
+ color: #000;
147
+ padding-left: 30px;
148
+ font-size: 0.85rem;
149
+ line-height: 1rem;
150
+ }
151
+
152
+ .self-managed-install-instructions > li {
153
+ padding-bottom: 1.5rem;
154
+ }
155
+
156
+ body[data-theme='dark'] .self-managed-install-instructions {
157
+ list-style: decimal;
158
+ color: #fff;
159
+ padding-left: 30px;
160
+ }
161
+
162
+ .self-managed-install-instructions code {
163
+ display: flex;
164
+ font-family: monospace;
165
+ padding: 0.25rem 0.75rem;
166
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 5%);
167
+ background-color: #1f2937;
168
+ border: 1px #374151 solid;
169
+ color: #86efac;
170
+ border-radius: 0.5rem;
171
+ font-size: 0.75rem;
172
+ line-height: 1rem;
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>
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/registry-bridge-engine/components/modals/self-managed-install-instructions';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/registry-bridge",
3
- "version": "0.0.11",
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.11",
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.11",
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.20",
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,28 @@
1
+ <?php
2
+
3
+ use Illuminate\Database\Migrations\Migration;
4
+ use Illuminate\Database\Schema\Blueprint;
5
+ use Illuminate\Support\Facades\Schema;
6
+
7
+ return new class extends Migration
8
+ {
9
+ /**
10
+ * Run the migrations.
11
+ */
12
+ public function up(): void
13
+ {
14
+ Schema::table('registry_extensions', function (Blueprint $table) {
15
+ $table->boolean('self_managed')->after('subtitle')->default(0);
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Reverse the migrations.
21
+ */
22
+ public function down(): void
23
+ {
24
+ Schema::table('registry_extensions', function (Blueprint $table) {
25
+ $table->dropColumn('self_managed');
26
+ });
27
+ }
28
+ };
@@ -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
+ }
@@ -6,6 +6,7 @@ use Fleetbase\Http\Controllers\Controller;
6
6
  use Fleetbase\Http\Resources\Category as CategoryResource;
7
7
  use Fleetbase\Models\Category;
8
8
  use Fleetbase\RegistryBridge\Models\RegistryExtension;
9
+ use Illuminate\Http\Request;
9
10
 
10
11
  class RegistryController extends Controller
11
12
  {
@@ -51,4 +52,49 @@ class RegistryController extends Controller
51
52
 
52
53
  return response()->json($installedExtensions);
53
54
  }
55
+
56
+ /**
57
+ * Lookup and retrieve package information based on the provided package name.
58
+ *
59
+ * This method handles a request to lookup a package by its name. It utilizes the `RegistryExtension::lookup` method to find the
60
+ * corresponding registry extension. If no extension is found or if the extension does not have valid package or composer data,
61
+ * an error response is returned.
62
+ *
63
+ * If a valid extension and its associated bundle are found, the function extracts the package and composer names from the
64
+ * `package.json` and `composer.json` metadata. These names are then returned in a JSON response.
65
+ *
66
+ * @param Request $request the incoming HTTP request containing the 'package' input parameter
67
+ *
68
+ * @return \Illuminate\Http\JsonResponse a JSON response containing the package and composer names if found, or an error message otherwise
69
+ */
70
+ public function lookupPackage(Request $request)
71
+ {
72
+ $packageName = $request->input('package');
73
+ $registryExtension = RegistryExtension::lookup($packageName);
74
+ if (!$registryExtension) {
75
+ return response()->error('No extension found by this name for install');
76
+ }
77
+
78
+ if (!$registryExtension->currentBundle) {
79
+ return response()->error('No valid package data found for this extension install');
80
+ }
81
+
82
+ $packageJson = $registryExtension->currentBundle->meta['package.json'];
83
+ if (!$packageJson) {
84
+ return response()->error('No valid package data found for this extension install');
85
+ }
86
+
87
+ $composerJson = $registryExtension->currentBundle->meta['composer.json'];
88
+ if (!$composerJson) {
89
+ return response()->error('No valid package data found for this extension install');
90
+ }
91
+
92
+ $packageJsonName = data_get($packageJson, 'name');
93
+ $composerJsonName = data_get($composerJson, 'name');
94
+
95
+ return response()->json([
96
+ 'npm' => $packageJsonName,
97
+ 'composer' => $composerJsonName,
98
+ ]);
99
+ }
54
100
  }