@aglyn/plugins-marketplace 1.0.0-beta.149 → 1.0.0-beta.151
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/package.json +15 -11
- package/src/lib/components/edit-listing-dialog.component.d.ts +20 -0
- package/src/lib/components/edit-listing-dialog.component.js +51 -0
- package/src/lib/components/edit-listing-dialog.component.js.map +1 -0
- package/src/lib/components/listing-detail-editor.component.d.ts +24 -0
- package/src/lib/components/listing-detail-editor.component.js +457 -0
- package/src/lib/components/listing-detail-editor.component.js.map +1 -0
- package/src/lib/components/listing-detail-page.component.d.ts +28 -0
- package/src/lib/components/listing-detail-page.component.js +151 -0
- package/src/lib/components/listing-detail-page.component.js.map +1 -0
- package/src/lib/components/listing-review-status.component.d.ts +67 -0
- package/src/lib/components/listing-review-status.component.js +301 -0
- package/src/lib/components/listing-review-status.component.js.map +1 -0
- package/src/lib/components/listing-verification-request.component.d.ts +40 -0
- package/src/lib/components/listing-verification-request.component.js +170 -0
- package/src/lib/components/listing-verification-request.component.js.map +1 -0
- package/src/lib/components/marketplace-hub.component.d.ts +43 -0
- package/src/lib/components/marketplace-hub.component.js +244 -0
- package/src/lib/components/marketplace-hub.component.js.map +1 -0
- package/src/lib/components/marketplace-reports-page.component.d.ts +23 -0
- package/src/lib/components/marketplace-reports-page.component.js +324 -0
- package/src/lib/components/marketplace-reports-page.component.js.map +1 -0
- package/src/lib/components/org-licences-panel.component.d.ts +73 -0
- package/src/lib/components/org-licences-panel.component.js +318 -0
- package/src/lib/components/org-licences-panel.component.js.map +1 -0
- package/src/lib/components/org-publish-panel.component.d.ts +45 -0
- package/src/lib/components/org-publish-panel.component.js +402 -0
- package/src/lib/components/org-publish-panel.component.js.map +1 -0
- package/src/lib/components/org-seller-panel.component.d.ts +28 -0
- package/src/lib/components/org-seller-panel.component.js +956 -0
- package/src/lib/components/org-seller-panel.component.js.map +1 -0
- package/src/lib/components/plugin-review-detail.component.d.ts +16 -0
- package/src/lib/components/plugin-review-detail.component.js +1438 -0
- package/src/lib/components/plugin-review-detail.component.js.map +1 -0
- package/src/lib/components/plugin-reviews-queue.component.d.ts +13 -0
- package/src/lib/components/plugin-reviews-queue.component.js +385 -0
- package/src/lib/components/plugin-reviews-queue.component.js.map +1 -0
- package/src/lib/components/plugin-reviews-surface.component.d.ts +19 -0
- package/src/lib/components/plugin-reviews-surface.component.js +46 -0
- package/src/lib/components/plugin-reviews-surface.component.js.map +1 -0
- package/src/lib/components/publish-plugin-form.component.d.ts +61 -0
- package/src/lib/components/publish-plugin-form.component.js +857 -0
- package/src/lib/components/publish-plugin-form.component.js.map +1 -0
- package/src/lib/components/publish-plugin-page.component.d.ts +29 -0
- package/src/lib/components/publish-plugin-page.component.js +92 -0
- package/src/lib/components/publish-plugin-page.component.js.map +1 -0
- package/src/lib/components/publisher-profile-page.component.d.ts +13 -0
- package/src/lib/components/publisher-profile-page.component.js +261 -0
- package/src/lib/components/publisher-profile-page.component.js.map +1 -0
- package/src/lib/constants/listing-media.d.ts +28 -0
- package/src/lib/constants/listing-media.js +28 -0
- package/src/lib/constants/listing-media.js.map +1 -0
- package/src/lib/model/listing-social-card.d.ts +94 -0
- package/src/lib/model/listing-social-card.js +177 -0
- package/src/lib/model/listing-social-card.js.map +1 -0
- package/src/lib/model/marketplace-paths.d.ts +54 -0
- package/src/lib/model/marketplace-paths.js +59 -0
- package/src/lib/model/marketplace-paths.js.map +1 -0
- package/src/lib/model/payout-readiness.d.ts +81 -0
- package/src/lib/model/payout-readiness.js +52 -0
- package/src/lib/model/payout-readiness.js.map +1 -0
- package/src/lib/model/plugin-rejection-categories.d.ts +66 -0
- package/src/lib/model/plugin-rejection-categories.js +124 -0
- package/src/lib/model/plugin-rejection-categories.js.map +1 -0
- package/src/lib/model/plugin-review-checklist.d.ts +62 -0
- package/src/lib/model/plugin-review-checklist.js +131 -0
- package/src/lib/model/plugin-review-checklist.js.map +1 -0
- package/src/lib/model/plugin-review-status.d.ts +104 -0
- package/src/lib/model/plugin-review-status.js +126 -0
- package/src/lib/model/plugin-review-status.js.map +1 -0
- package/src/lib/model/seller-ledger-totals.d.ts +100 -0
- package/src/lib/model/seller-ledger-totals.js +96 -0
- package/src/lib/model/seller-ledger-totals.js.map +1 -0
- package/src/lib/plugin.js +170 -40
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/admin-reports.d.ts +18 -0
- package/src/lib/server/admin-reports.js +280 -0
- package/src/lib/server/admin-reports.js.map +1 -0
- package/src/lib/server/admin-reviews.d.ts +18 -0
- package/src/lib/server/admin-reviews.js +1341 -0
- package/src/lib/server/admin-reviews.js.map +1 -0
- package/src/lib/server/listing-social-card.server.d.ts +24 -0
- package/src/lib/server/listing-social-card.server.js +65 -0
- package/src/lib/server/listing-social-card.server.js.map +1 -0
- package/src/lib/server/publisher-review-email.d.ts +54 -0
- package/src/lib/server/publisher-review-email.js +85 -0
- package/src/lib/server/publisher-review-email.js.map +1 -0
- package/src/lib/server/revoke-cache-drop.d.ts +59 -0
- package/src/lib/server/revoke-cache-drop.js +74 -0
- package/src/lib/server/revoke-cache-drop.js.map +1 -0
- package/src/lib/server.js +47 -0
- package/src/lib/server.js.map +1 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { ICON_VARIANT_COMPONENT } from "@aglyn/shared-data-enums";
|
|
19
|
+
import { AppLink, CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
20
|
+
import { useFirestore, useFirestoreCollection, useUser } from "@aglyn/tenant-feature-instance";
|
|
21
|
+
import { Alert, Chip, Stack } from "@mui/material";
|
|
22
|
+
import { ListTable } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
23
|
+
import { collection, documentId, limit, orderBy, query, where } from "firebase/firestore";
|
|
24
|
+
import { useMemo } from "react";
|
|
25
|
+
import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
26
|
+
import { TABLE_ROW_HEIGHT } from "@aglyn/shared-ui-jsx/const/table-pagination";
|
|
27
|
+
import { listingPath } from "../model/marketplace-paths.js";
|
|
28
|
+
import EmptyState from "@aglyn/shared-ui-jsx/components/read-gated-empty-state.component";
|
|
29
|
+
/**
|
|
30
|
+
* WHICH WORKSPACE HOLDS A LICENCE (AGL-2331).
|
|
31
|
+
*
|
|
32
|
+
* A marketplace purchase licenses the installing ORGANIZATION, not the person
|
|
33
|
+
* who paid. That is the model the Publisher Agreement already publishes and
|
|
34
|
+
* the model the install routes now enforce — and it is unusable without a
|
|
35
|
+
* surface, because the two questions it creates have no answer anywhere else
|
|
36
|
+
* in the console:
|
|
37
|
+
*
|
|
38
|
+
* "Does THIS workspace own that component, or was it the other client's?"
|
|
39
|
+
* "I bought this once — which workspace did the licence land in?"
|
|
40
|
+
*
|
|
41
|
+
* An agency is the population this matters to most, and an agency is exactly
|
|
42
|
+
* the population that cannot answer either question from memory. Before this
|
|
43
|
+
* panel the only signal was a Buy button, and a Buy button is the same
|
|
44
|
+
* whether you own nothing or own three of them in other workspaces.
|
|
45
|
+
*
|
|
46
|
+
* TWO LISTS, deliberately, because they are two different facts:
|
|
47
|
+
*
|
|
48
|
+
* `This workspace` is the org's inventory — what any member with install
|
|
49
|
+
* rights may install here, including licences a colleague bought and
|
|
50
|
+
* licences bought by someone who has since left. It is the list that
|
|
51
|
+
* decides whether a Buy is needed.
|
|
52
|
+
*
|
|
53
|
+
* `Bought by you` is the buyer's own receipt trail across every workspace
|
|
54
|
+
* they belong to. It is what turns "I already bought this" into "…for
|
|
55
|
+
* Northwind, and this is Contoso".
|
|
56
|
+
*
|
|
57
|
+
* Both read `marketplacePurchases`, which is buyer/org/seller-gated — the org
|
|
58
|
+
* clause landed with AGL-2331 for exactly this list. Held at null until the
|
|
59
|
+
* org and uid resolve: a rules-shaped LIST is evaluated against the QUERY, so
|
|
60
|
+
* a sentinel value is a guaranteed denial retried on the refusal cadence
|
|
61
|
+
* (AGL-1440), not an empty list.
|
|
62
|
+
*
|
|
63
|
+
* ## Presentation (AGL-2486)
|
|
64
|
+
*
|
|
65
|
+
* Each list is a card, like every sibling Marketplace tab — it shipped as two
|
|
66
|
+
* bare `subtitle1` headings with a loose sentence under each, which on a page
|
|
67
|
+
* built from cards reads as an unfinished tab rather than an empty one.
|
|
68
|
+
*
|
|
69
|
+
* More than cosmetic: the sentences became `EmptyState`s, so they are now
|
|
70
|
+
* GATED on the read having succeeded (AGL-1066). "You have not bought
|
|
71
|
+
* anything" is a claim about someone's purchase history, and a refused or
|
|
72
|
+
* unfinished read supports no such claim — on a tab whose whole purpose is
|
|
73
|
+
* answering "do we already own this?", a zero-state produced by a dead
|
|
74
|
+
* session is an invitation to buy something twice. Both queries are held at
|
|
75
|
+
* `null` until the scope resolves, which reads as `loading` and can never
|
|
76
|
+
* reach the zero-state; a listen the server has REFUSED keeps painting from
|
|
77
|
+
* cache with `status: 'success'`, which is why `serverDenied` is checked
|
|
78
|
+
* alongside it rather than trusting the status alone.
|
|
79
|
+
*/ export function OrgLicencesPanel({ orgId, basePath, viewerOrgs }) {
|
|
80
|
+
const firestore = useFirestore();
|
|
81
|
+
const { data: user } = useUser();
|
|
82
|
+
const uid = user == null ? void 0 : user.uid;
|
|
83
|
+
/** The licences this workspace holds — whoever in it did the buying. */ const orgLicencesRead = useFirestoreCollection(()=>orgId ? query(collection(firestore, 'marketplacePurchases'), where('buyerOrgId', '==', orgId)) : null, [
|
|
84
|
+
firestore,
|
|
85
|
+
orgId
|
|
86
|
+
], {
|
|
87
|
+
idField: '$id'
|
|
88
|
+
});
|
|
89
|
+
/** Everything this person has ever bought, in any workspace. */ const myPurchasesRead = useFirestoreCollection(()=>uid ? query(collection(firestore, 'marketplacePurchases'), where('buyerUid', '==', uid)) : null, [
|
|
90
|
+
firestore,
|
|
91
|
+
uid
|
|
92
|
+
], {
|
|
93
|
+
idField: '$id'
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* Listing id → display name.
|
|
97
|
+
*
|
|
98
|
+
* One subscription rather than a read per row: `marketplaceListings` is
|
|
99
|
+
* world-readable (it is the catalogue), the browse grid on the sibling tab
|
|
100
|
+
* already listens to it, and a per-row hook would change the hook count
|
|
101
|
+
* between renders as licences arrive.
|
|
102
|
+
*/ const { data: listings } = useFirestoreCollection(/*
|
|
103
|
+
* ORDERED, so the window is a reachable 200 rather than a sample.
|
|
104
|
+
*
|
|
105
|
+
* A capped read with no `orderBy` is answered in document-id order
|
|
106
|
+
* anyway, so naming it changes no row — what it changes is that the
|
|
107
|
+
* ordering is a decision rather than an accident, and that the obvious
|
|
108
|
+
* next edit is caught: `orderBy('displayName')` would drop every listing
|
|
109
|
+
* saved without one out of the map, and a licence whose listing is
|
|
110
|
+
* missing from the map is a row that names itself by raw id.
|
|
111
|
+
*
|
|
112
|
+
* Ordering on the document NAME, which is what a listing id already is
|
|
113
|
+
* here, keeps the map's keys and the walk in the same space. Past 200
|
|
114
|
+
* listings a licence still renders — the fallback below prints the
|
|
115
|
+
* listing id — so the cap degrades the label and never the row.
|
|
116
|
+
*/ ()=>query(collection(firestore, 'marketplaceListings'), orderBy(documentId()), limit(200)), [
|
|
117
|
+
firestore
|
|
118
|
+
], {
|
|
119
|
+
idField: '$id'
|
|
120
|
+
});
|
|
121
|
+
const listingNames = useMemo(()=>{
|
|
122
|
+
const names = {};
|
|
123
|
+
for (const listing of listings != null ? listings : []){
|
|
124
|
+
var _listing_displayName;
|
|
125
|
+
names[listing.$id] = String((_listing_displayName = listing.displayName) != null ? _listing_displayName : listing.$id);
|
|
126
|
+
}
|
|
127
|
+
return names;
|
|
128
|
+
}, [
|
|
129
|
+
listings
|
|
130
|
+
]);
|
|
131
|
+
/** Workspace id → the name the member already sees in the org switcher. */ const orgNames = useMemo(()=>{
|
|
132
|
+
const names = {};
|
|
133
|
+
for (const workspace of viewerOrgs != null ? viewerOrgs : [])names[workspace.id] = workspace.name;
|
|
134
|
+
return names;
|
|
135
|
+
}, [
|
|
136
|
+
viewerOrgs
|
|
137
|
+
]);
|
|
138
|
+
/**
|
|
139
|
+
* A refunded purchase is not a licence (AGL-1546) and must not be listed as
|
|
140
|
+
* one — the whole point of this panel is deciding whether to buy, and a row
|
|
141
|
+
* that says "you own this" when the install route answers 402 is worse than
|
|
142
|
+
* no row.
|
|
143
|
+
*/ const live = (rows)=>(rows != null ? rows : []).filter((row)=>!(row == null ? void 0 : row.refundedAt));
|
|
144
|
+
const held = live(orgLicencesRead.data);
|
|
145
|
+
const mine = live(myPurchasesRead.data);
|
|
146
|
+
/*==========================================
|
|
147
|
+
* BOTH LISTS ARE WHOLE, so the grid pages them and its counts are TOTALS.
|
|
148
|
+
*
|
|
149
|
+
* Neither query is capped: each reads one workspace's purchases or one
|
|
150
|
+
* person's, whole. So the card holds the entire list it is describing, the
|
|
151
|
+
* refund filter above has already run over all of it, and the grid's
|
|
152
|
+
* footer counts the collection's real size rather than a window's length —
|
|
153
|
+
* the one case where a client page can state a total without qualifying it.
|
|
154
|
+
*
|
|
155
|
+
* Server-paging either one would break that. `refundedAt` is filtered after
|
|
156
|
+
* reading, so a ten-document page arrives holding anywhere from zero to ten
|
|
157
|
+
* licences, and an agency deciding whether to buy a component again is
|
|
158
|
+
* exactly the reader who must not be shown a short page as a complete
|
|
159
|
+
* answer.
|
|
160
|
+
*=========================================*/ const heldColumns = useMemo(()=>[
|
|
161
|
+
{
|
|
162
|
+
field: 'listingId',
|
|
163
|
+
headerName: 'Listing',
|
|
164
|
+
flex: 1,
|
|
165
|
+
minWidth: 220,
|
|
166
|
+
valueGetter: (_value, row)=>{
|
|
167
|
+
var _listingNames_String, _row_listingId, _row_listingId1;
|
|
168
|
+
return (_listingNames_String = listingNames[String((_row_listingId = row.listingId) != null ? _row_listingId : '')]) != null ? _listingNames_String : String((_row_listingId1 = row.listingId) != null ? _row_listingId1 : '');
|
|
169
|
+
},
|
|
170
|
+
renderCell: ({ row, value })=>{
|
|
171
|
+
var _row_listingId;
|
|
172
|
+
return /*#__PURE__*/ _jsx(AppLink, {
|
|
173
|
+
href: listingPath(basePath, String((_row_listingId = row.listingId) != null ? _row_listingId : '')),
|
|
174
|
+
children: value
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
field: 'buyerUid',
|
|
180
|
+
headerName: 'Bought by',
|
|
181
|
+
width: 150,
|
|
182
|
+
valueGetter: (_value, row)=>row.buyerUid === uid ? 'You' : 'A colleague'
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
field: 'amountCents',
|
|
186
|
+
headerName: 'Paid',
|
|
187
|
+
type: 'number',
|
|
188
|
+
align: 'right',
|
|
189
|
+
headerAlign: 'right',
|
|
190
|
+
width: 120,
|
|
191
|
+
// What the licence cost before tax, which is what a reader compares.
|
|
192
|
+
valueGetter: (_value, row)=>{
|
|
193
|
+
var _row_amountCents, _row_taxCents;
|
|
194
|
+
return (Number((_row_amountCents = row.amountCents) != null ? _row_amountCents : 0) - Number((_row_taxCents = row.taxCents) != null ? _row_taxCents : 0)) / 100;
|
|
195
|
+
},
|
|
196
|
+
valueFormatter: (value)=>`$${value.toFixed(2)}`
|
|
197
|
+
}
|
|
198
|
+
], [
|
|
199
|
+
listingNames,
|
|
200
|
+
basePath,
|
|
201
|
+
uid
|
|
202
|
+
]);
|
|
203
|
+
const mineColumns = useMemo(()=>[
|
|
204
|
+
{
|
|
205
|
+
field: 'listingId',
|
|
206
|
+
headerName: 'Listing',
|
|
207
|
+
flex: 1,
|
|
208
|
+
minWidth: 220,
|
|
209
|
+
valueGetter: (_value, row)=>{
|
|
210
|
+
var _listingNames_String, _row_listingId, _row_listingId1;
|
|
211
|
+
return (_listingNames_String = listingNames[String((_row_listingId = row.listingId) != null ? _row_listingId : '')]) != null ? _listingNames_String : String((_row_listingId1 = row.listingId) != null ? _row_listingId1 : '');
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
field: 'buyerOrgId',
|
|
216
|
+
headerName: 'Licensed to',
|
|
217
|
+
flex: 1,
|
|
218
|
+
minWidth: 220,
|
|
219
|
+
valueGetter: (_value, row)=>{
|
|
220
|
+
var _row_buyerOrgId, _orgNames_licensedOrg;
|
|
221
|
+
const licensedOrg = String((_row_buyerOrgId = row.buyerOrgId) != null ? _row_buyerOrgId : '');
|
|
222
|
+
if (!licensedOrg) return 'Every workspace you belong to';
|
|
223
|
+
return licensedOrg === orgId ? 'This workspace' : (_orgNames_licensedOrg = orgNames[licensedOrg]) != null ? _orgNames_licensedOrg : licensedOrg;
|
|
224
|
+
},
|
|
225
|
+
renderCell: ({ row, value })=>{
|
|
226
|
+
var _row_buyerOrgId;
|
|
227
|
+
const licensedOrg = String((_row_buyerOrgId = row.buyerOrgId) != null ? _row_buyerOrgId : '');
|
|
228
|
+
// A purchase made before AGL-2331 named no organization, so it is
|
|
229
|
+
// not reinterpreted as belonging to one — it keeps entitling this
|
|
230
|
+
// buyer everywhere, exactly as it did when they paid for it. Saying
|
|
231
|
+
// "every workspace" rather than guessing an org is the whole reason
|
|
232
|
+
// nobody loses access here.
|
|
233
|
+
if (!licensedOrg) return /*#__PURE__*/ _jsx(Chip, {
|
|
234
|
+
size: "small",
|
|
235
|
+
label: value
|
|
236
|
+
});
|
|
237
|
+
return licensedOrg === orgId ? /*#__PURE__*/ _jsx(Chip, {
|
|
238
|
+
size: "small",
|
|
239
|
+
color: "primary",
|
|
240
|
+
label: value
|
|
241
|
+
}) : /*#__PURE__*/ _jsx(Chip, {
|
|
242
|
+
size: "small",
|
|
243
|
+
variant: "outlined",
|
|
244
|
+
label: value
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
], [
|
|
249
|
+
listingNames,
|
|
250
|
+
orgId,
|
|
251
|
+
orgNames
|
|
252
|
+
]);
|
|
253
|
+
/**
|
|
254
|
+
* "You own nothing here" is a claim about this workspace's purchases, and a
|
|
255
|
+
* refused read supports no such claim (AGL-1066). Both queries are ALSO
|
|
256
|
+
* held at `null` until the org and the uid resolve, which the hook reports
|
|
257
|
+
* as `loading` — so an unresolved scope can never reach the zero-state
|
|
258
|
+
* either. `serverDenied` is folded in beside `status`: a listen the server
|
|
259
|
+
* has refused past its retry budget keeps painting whatever the local cache
|
|
260
|
+
* holds, and `status` alone still reads `success` for it.
|
|
261
|
+
*/ const outcome = (read)=>read.status === 'error' || read.serverDenied === true ? 'unavailable' : read.status === 'success' ? 'loaded' : 'loading';
|
|
262
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
263
|
+
spacing: 3,
|
|
264
|
+
children: [
|
|
265
|
+
/*#__PURE__*/ _jsx(Alert, {
|
|
266
|
+
severity: "info",
|
|
267
|
+
children: 'A marketplace purchase licenses one organization. Any member with ' + 'install permission can install what this workspace owns — and a ' + 'second workspace needs its own license.'
|
|
268
|
+
}),
|
|
269
|
+
held.length === 0 ? /*#__PURE__*/ _jsx(EmptyState, {
|
|
270
|
+
read: outcome(orgLicencesRead),
|
|
271
|
+
subject: "this workspace’s licenses",
|
|
272
|
+
iconPath: ICON_VARIANT_COMPONENT.path,
|
|
273
|
+
title: 'This workspace holds no licenses',
|
|
274
|
+
description: 'Anything bought for this workspace shows up here, whoever on ' + 'the team paid for it.'
|
|
275
|
+
}) : /*#__PURE__*/ _jsx(CardDisplay, {
|
|
276
|
+
header: 'This workspace',
|
|
277
|
+
help: pluginDocsHelp('publisherHandbook', {
|
|
278
|
+
anchor: '#how-installs-work-the-buyer-side',
|
|
279
|
+
excerpt: 'What this workspace owns — installable by any member with ' + 'install permission, whoever on the team paid for it.'
|
|
280
|
+
}),
|
|
281
|
+
subheader: 'Installable by any member with install permission, whoever ' + 'on the team bought it',
|
|
282
|
+
contentGutterX: true,
|
|
283
|
+
contentGutterY: true,
|
|
284
|
+
children: /*#__PURE__*/ _jsx(ListTable, {
|
|
285
|
+
"aria-label": "Licenses this workspace holds",
|
|
286
|
+
rows: held,
|
|
287
|
+
columns: heldColumns,
|
|
288
|
+
rowHeight: TABLE_ROW_HEIGHT
|
|
289
|
+
})
|
|
290
|
+
}),
|
|
291
|
+
mine.length === 0 ? /*#__PURE__*/ _jsx(EmptyState, {
|
|
292
|
+
read: outcome(myPurchasesRead),
|
|
293
|
+
subject: "your purchases",
|
|
294
|
+
iconPath: ICON_VARIANT_COMPONENT.path,
|
|
295
|
+
title: 'You have not bought anything yet',
|
|
296
|
+
description: 'Your own marketplace receipts appear here, across every ' + 'workspace you belong to.'
|
|
297
|
+
}) : /*#__PURE__*/ _jsx(CardDisplay, {
|
|
298
|
+
header: 'Bought by you',
|
|
299
|
+
help: pluginDocsHelp('publisherHandbook', {
|
|
300
|
+
anchor: '#how-installs-work-the-buyer-side',
|
|
301
|
+
excerpt: 'Your own purchases across every workspace you belong to — a ' + 'purchase licenses one organization, so this says which.'
|
|
302
|
+
}),
|
|
303
|
+
subheader: 'Your own receipts, and which workspace each license landed in',
|
|
304
|
+
contentGutterX: true,
|
|
305
|
+
contentGutterY: true,
|
|
306
|
+
children: /*#__PURE__*/ _jsx(ListTable, {
|
|
307
|
+
"aria-label": "Licenses you bought",
|
|
308
|
+
rows: mine,
|
|
309
|
+
columns: mineColumns,
|
|
310
|
+
rowHeight: TABLE_ROW_HEIGHT
|
|
311
|
+
})
|
|
312
|
+
})
|
|
313
|
+
]
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
export default OrgLicencesPanel;
|
|
317
|
+
|
|
318
|
+
//# sourceMappingURL=org-licences-panel.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/org-licences-panel.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { ICON_VARIANT_COMPONENT } from '@aglyn/shared-data-enums'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport {\n useFirestore,\n useFirestoreCollection,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport { Alert, Chip, Stack } from '@mui/material'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport {\n collection,\n documentId,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { TABLE_ROW_HEIGHT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport { listingPath } from '../model/marketplace-paths'\nimport EmptyState from '@aglyn/shared-ui-jsx/components/read-gated-empty-state.component'\nimport type { ReadOutcome } from '@aglyn/shared-ui-jsx/utils/read-outcome'\n\n/**\n * WHICH WORKSPACE HOLDS A LICENCE (AGL-2331).\n *\n * A marketplace purchase licenses the installing ORGANIZATION, not the person\n * who paid. That is the model the Publisher Agreement already publishes and\n * the model the install routes now enforce — and it is unusable without a\n * surface, because the two questions it creates have no answer anywhere else\n * in the console:\n *\n * \"Does THIS workspace own that component, or was it the other client's?\"\n * \"I bought this once — which workspace did the licence land in?\"\n *\n * An agency is the population this matters to most, and an agency is exactly\n * the population that cannot answer either question from memory. Before this\n * panel the only signal was a Buy button, and a Buy button is the same\n * whether you own nothing or own three of them in other workspaces.\n *\n * TWO LISTS, deliberately, because they are two different facts:\n *\n * `This workspace` is the org's inventory — what any member with install\n * rights may install here, including licences a colleague bought and\n * licences bought by someone who has since left. It is the list that\n * decides whether a Buy is needed.\n *\n * `Bought by you` is the buyer's own receipt trail across every workspace\n * they belong to. It is what turns \"I already bought this\" into \"…for\n * Northwind, and this is Contoso\".\n *\n * Both read `marketplacePurchases`, which is buyer/org/seller-gated — the org\n * clause landed with AGL-2331 for exactly this list. Held at null until the\n * org and uid resolve: a rules-shaped LIST is evaluated against the QUERY, so\n * a sentinel value is a guaranteed denial retried on the refusal cadence\n * (AGL-1440), not an empty list.\n *\n * ## Presentation (AGL-2486)\n *\n * Each list is a card, like every sibling Marketplace tab — it shipped as two\n * bare `subtitle1` headings with a loose sentence under each, which on a page\n * built from cards reads as an unfinished tab rather than an empty one.\n *\n * More than cosmetic: the sentences became `EmptyState`s, so they are now\n * GATED on the read having succeeded (AGL-1066). \"You have not bought\n * anything\" is a claim about someone's purchase history, and a refused or\n * unfinished read supports no such claim — on a tab whose whole purpose is\n * answering \"do we already own this?\", a zero-state produced by a dead\n * session is an invitation to buy something twice. Both queries are held at\n * `null` until the scope resolves, which reads as `loading` and can never\n * reach the zero-state; a listen the server has REFUSED keeps painting from\n * cache with `status: 'success'`, which is why `serverDenied` is checked\n * alongside it rather than trusting the status alone.\n */\nexport function OrgLicencesPanel({\n orgId,\n basePath,\n viewerOrgs,\n}: {\n orgId?: string | null\n /**\n * Where the marketplace hub is mounted under this organization, from the\n * shell (AGL-3080) — each row links to its listing beneath it. It replaced\n * an org slug and the console's route table, which a plugin may not\n * import.\n */\n basePath: string\n /**\n * Every workspace the reader belongs to, from the shell, so the \"Licensed\n * to\" column can name the one a purchase landed in instead of printing its\n * id. A purchase licenses an ORGANIZATION (AGL-2331), which is the whole\n * subject of this panel, and the reader's other workspaces are the answer\n * to half of it.\n */\n viewerOrgs?: readonly { id: string; name: string }[]\n}) {\n const firestore = useFirestore()\n const { data: user } = useUser()\n const uid = (user as { uid?: string } | null | undefined)?.uid\n\n /** The licences this workspace holds — whoever in it did the buying. */\n const orgLicencesRead = useFirestoreCollection<any>(\n () =>\n orgId\n ? query(\n collection(firestore, 'marketplacePurchases'),\n where('buyerOrgId', '==', orgId),\n )\n : null,\n [firestore, orgId],\n { idField: '$id' },\n )\n /** Everything this person has ever bought, in any workspace. */\n const myPurchasesRead = useFirestoreCollection<any>(\n () =>\n uid\n ? query(\n collection(firestore, 'marketplacePurchases'),\n where('buyerUid', '==', uid),\n )\n : null,\n [firestore, uid],\n { idField: '$id' },\n )\n\n /**\n * Listing id → display name.\n *\n * One subscription rather than a read per row: `marketplaceListings` is\n * world-readable (it is the catalogue), the browse grid on the sibling tab\n * already listens to it, and a per-row hook would change the hook count\n * between renders as licences arrive.\n */\n const { data: listings } = useFirestoreCollection<any>(\n /*\n * ORDERED, so the window is a reachable 200 rather than a sample.\n *\n * A capped read with no `orderBy` is answered in document-id order\n * anyway, so naming it changes no row — what it changes is that the\n * ordering is a decision rather than an accident, and that the obvious\n * next edit is caught: `orderBy('displayName')` would drop every listing\n * saved without one out of the map, and a licence whose listing is\n * missing from the map is a row that names itself by raw id.\n *\n * Ordering on the document NAME, which is what a listing id already is\n * here, keeps the map's keys and the walk in the same space. Past 200\n * listings a licence still renders — the fallback below prints the\n * listing id — so the cap degrades the label and never the row.\n */\n () =>\n query(\n collection(firestore, 'marketplaceListings'),\n orderBy(documentId()),\n limit(200),\n ),\n [firestore],\n { idField: '$id' },\n )\n const listingNames = useMemo(() => {\n const names: Record<string, string> = {}\n for (const listing of listings ?? []) {\n names[listing.$id] = String(listing.displayName ?? listing.$id)\n }\n return names\n }, [listings])\n\n /** Workspace id → the name the member already sees in the org switcher. */\n const orgNames = useMemo(() => {\n const names: Record<string, string> = {}\n for (const workspace of viewerOrgs ?? []) names[workspace.id] = workspace.name\n return names\n }, [viewerOrgs])\n\n /**\n * A refunded purchase is not a licence (AGL-1546) and must not be listed as\n * one — the whole point of this panel is deciding whether to buy, and a row\n * that says \"you own this\" when the install route answers 402 is worse than\n * no row.\n */\n const live = (rows: any[] | undefined) =>\n (rows ?? []).filter((row) => !row?.refundedAt)\n\n const held = live(orgLicencesRead.data)\n const mine = live(myPurchasesRead.data)\n\n /*==========================================\n * BOTH LISTS ARE WHOLE, so the grid pages them and its counts are TOTALS.\n *\n * Neither query is capped: each reads one workspace's purchases or one\n * person's, whole. So the card holds the entire list it is describing, the\n * refund filter above has already run over all of it, and the grid's\n * footer counts the collection's real size rather than a window's length —\n * the one case where a client page can state a total without qualifying it.\n *\n * Server-paging either one would break that. `refundedAt` is filtered after\n * reading, so a ten-document page arrives holding anywhere from zero to ten\n * licences, and an agency deciding whether to buy a component again is\n * exactly the reader who must not be shown a short page as a complete\n * answer.\n *=========================================*/\n const heldColumns = useMemo<GridColDef[]>(\n () => [\n {\n field: 'listingId',\n headerName: 'Listing',\n flex: 1,\n minWidth: 220,\n valueGetter: (_value, row) =>\n listingNames[String(row.listingId ?? '')] ?? String(row.listingId ?? ''),\n renderCell: ({ row, value }) => (\n <AppLink href={listingPath(basePath, String(row.listingId ?? ''))}>\n {value}\n </AppLink>\n ),\n },\n {\n field: 'buyerUid',\n headerName: 'Bought by',\n width: 150,\n valueGetter: (_value, row) => (row.buyerUid === uid ? 'You' : 'A colleague'),\n },\n {\n field: 'amountCents',\n headerName: 'Paid',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 120,\n // What the licence cost before tax, which is what a reader compares.\n valueGetter: (_value, row) =>\n (Number(row.amountCents ?? 0) - Number(row.taxCents ?? 0)) / 100,\n valueFormatter: (value: number) => `$${value.toFixed(2)}`,\n },\n ],\n [listingNames, basePath, uid],\n )\n const mineColumns = useMemo<GridColDef[]>(\n () => [\n {\n field: 'listingId',\n headerName: 'Listing',\n flex: 1,\n minWidth: 220,\n valueGetter: (_value, row) =>\n listingNames[String(row.listingId ?? '')] ?? String(row.listingId ?? ''),\n },\n {\n field: 'buyerOrgId',\n headerName: 'Licensed to',\n flex: 1,\n minWidth: 220,\n valueGetter: (_value, row) => {\n const licensedOrg = String(row.buyerOrgId ?? '')\n if (!licensedOrg) return 'Every workspace you belong to'\n return licensedOrg === orgId\n ? 'This workspace'\n : (orgNames[licensedOrg] ?? licensedOrg)\n },\n renderCell: ({ row, value }) => {\n const licensedOrg = String(row.buyerOrgId ?? '')\n // A purchase made before AGL-2331 named no organization, so it is\n // not reinterpreted as belonging to one — it keeps entitling this\n // buyer everywhere, exactly as it did when they paid for it. Saying\n // \"every workspace\" rather than guessing an org is the whole reason\n // nobody loses access here.\n if (!licensedOrg) return <Chip size=\"small\" label={value} />\n return licensedOrg === orgId ? (\n <Chip size=\"small\" color=\"primary\" label={value} />\n ) : (\n <Chip size=\"small\" variant=\"outlined\" label={value} />\n )\n },\n },\n ],\n [listingNames, orgId, orgNames],\n )\n\n /**\n * \"You own nothing here\" is a claim about this workspace's purchases, and a\n * refused read supports no such claim (AGL-1066). Both queries are ALSO\n * held at `null` until the org and the uid resolve, which the hook reports\n * as `loading` — so an unresolved scope can never reach the zero-state\n * either. `serverDenied` is folded in beside `status`: a listen the server\n * has refused past its retry budget keeps painting whatever the local cache\n * holds, and `status` alone still reads `success` for it.\n */\n const outcome = (read: {\n status: string\n serverDenied: boolean\n }): ReadOutcome =>\n read.status === 'error' || read.serverDenied === true\n ? 'unavailable'\n : read.status === 'success'\n ? 'loaded'\n : 'loading'\n\n return (\n <Stack spacing={3}>\n <Alert severity=\"info\">\n {'A marketplace purchase licenses one organization. Any member with ' +\n 'install permission can install what this workspace owns — and a ' +\n 'second workspace needs its own license.'}\n </Alert>\n\n {held.length === 0 ? (\n <EmptyState\n read={outcome(orgLicencesRead)}\n subject=\"this workspace’s licenses\"\n iconPath={ICON_VARIANT_COMPONENT.path}\n title={'This workspace holds no licenses'}\n description={\n 'Anything bought for this workspace shows up here, whoever on ' +\n 'the team paid for it.'\n }\n />\n ) : (\n <CardDisplay\n header={'This workspace'}\n help={pluginDocsHelp('publisherHandbook', {\n anchor: '#how-installs-work-the-buyer-side',\n excerpt:\n 'What this workspace owns — installable by any member with ' +\n 'install permission, whoever on the team paid for it.',\n })}\n subheader={\n 'Installable by any member with install permission, whoever ' +\n 'on the team bought it'\n }\n contentGutterX\n contentGutterY\n >\n <ListTable\n aria-label=\"Licenses this workspace holds\"\n rows={held}\n columns={heldColumns}\n rowHeight={TABLE_ROW_HEIGHT}\n />\n </CardDisplay>\n )}\n\n {mine.length === 0 ? (\n <EmptyState\n read={outcome(myPurchasesRead)}\n subject=\"your purchases\"\n iconPath={ICON_VARIANT_COMPONENT.path}\n title={'You have not bought anything yet'}\n description={\n 'Your own marketplace receipts appear here, across every ' +\n 'workspace you belong to.'\n }\n />\n ) : (\n <CardDisplay\n header={'Bought by you'}\n help={pluginDocsHelp('publisherHandbook', {\n anchor: '#how-installs-work-the-buyer-side',\n excerpt:\n 'Your own purchases across every workspace you belong to — a ' +\n 'purchase licenses one organization, so this says which.',\n })}\n subheader={\n 'Your own receipts, and which workspace each license landed in'\n }\n contentGutterX\n contentGutterY\n >\n <ListTable\n aria-label=\"Licenses you bought\"\n rows={mine}\n columns={mineColumns}\n rowHeight={TABLE_ROW_HEIGHT}\n />\n </CardDisplay>\n )}\n </Stack>\n )\n}\n\nexport default OrgLicencesPanel\n"],"names":["ICON_VARIANT_COMPONENT","AppLink","CardDisplay","useFirestore","useFirestoreCollection","useUser","Alert","Chip","Stack","ListTable","collection","documentId","limit","orderBy","query","where","useMemo","pluginDocsHelp","TABLE_ROW_HEIGHT","listingPath","EmptyState","OrgLicencesPanel","orgId","basePath","viewerOrgs","firestore","data","user","uid","orgLicencesRead","idField","myPurchasesRead","listings","listingNames","names","listing","$id","String","displayName","orgNames","workspace","id","name","live","rows","filter","row","refundedAt","held","mine","heldColumns","field","headerName","flex","minWidth","valueGetter","_value","listingId","renderCell","value","href","width","buyerUid","type","align","headerAlign","Number","amountCents","taxCents","valueFormatter","toFixed","mineColumns","licensedOrg","buyerOrgId","size","label","color","variant","outcome","read","status","serverDenied","spacing","severity","length","subject","iconPath","path","title","description","header","help","anchor","excerpt","subheader","contentGutterX","contentGutterY","aria-label","columns","rowHeight"],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { resolveMarketplaceFeePct } from '@aglyn/aglyn';
|
|
2
|
+
/**
|
|
3
|
+
* Org-level publish (AGL-776): pick a source site, then a component, a layout,
|
|
4
|
+
* or the whole site (as a template), and publish it under the org's publisher
|
|
5
|
+
* identity. This panel's whole job is choosing WHAT: it names the kind, the
|
|
6
|
+
* scope that holds it and the document, and hands that to the
|
|
7
|
+
* `hostArtifactPublish` zone (AGL-3080), whose widget owns the name/price
|
|
8
|
+
* form, the route and the POST. Plugins publish from their own bundle upload,
|
|
9
|
+
* not here.
|
|
10
|
+
*
|
|
11
|
+
* The per-site publish buttons (Components/Layouts/Setup pages) stay as
|
|
12
|
+
* in-context shortcuts; this is the one place that spans every site.
|
|
13
|
+
*/
|
|
14
|
+
export declare function OrgPublishPanel({ orgId, hosts, basePath, billingPath, org, orgReady, }: {
|
|
15
|
+
orgId: string;
|
|
16
|
+
hosts: ReadonlyArray<{
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Where the marketplace hub is mounted under this organization, from the
|
|
22
|
+
* shell (AGL-3080). The publish-a-plugin page hangs beneath it.
|
|
23
|
+
*/
|
|
24
|
+
basePath: string;
|
|
25
|
+
/**
|
|
26
|
+
* Where this organization manages its plan, from the shell's org mount.
|
|
27
|
+
* Absent on a deployment that bills nobody, and the fee notice then says
|
|
28
|
+
* the rate without offering a way to change it.
|
|
29
|
+
*/
|
|
30
|
+
billingPath?: string;
|
|
31
|
+
/**
|
|
32
|
+
* The org billing doc the shell already loaded, and whether it has
|
|
33
|
+
* settled. Read here rather than through the console's `useCurrentOrg`:
|
|
34
|
+
* the fee shown is a claim about this publisher's plan, and
|
|
35
|
+
* `resolveMarketplaceFeePct(undefined)` answers the FREE rate — so a
|
|
36
|
+
* number rendered during load accuses a paying publisher of the higher
|
|
37
|
+
* cut.
|
|
38
|
+
*/
|
|
39
|
+
org?: Parameters<typeof resolveMarketplaceFeePct>[0];
|
|
40
|
+
orgReady: boolean;
|
|
41
|
+
}): import("react").JSX.Element;
|
|
42
|
+
export declare namespace OrgPublishPanel {
|
|
43
|
+
var displayName: string;
|
|
44
|
+
}
|
|
45
|
+
export default OrgPublishPanel;
|