dsh-enterprise-market 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -24,6 +24,9 @@ window.__ModuleLoader__.load({
24
24
  install: '安装',
25
25
  installing: '安装中…',
26
26
  installed: '已安装',
27
+ update: '更新',
28
+ pendingApproval: '待 npm 批准',
29
+ updating: '更新中…',
27
30
  installedDisabled: '已安装 · 未启用',
28
31
  uploader: '上传人',
29
32
  unknownUploader: '未记录上传人',
@@ -89,6 +92,9 @@ window.__ModuleLoader__.load({
89
92
  install: 'Install',
90
93
  installing: 'Installing…',
91
94
  installed: 'Installed',
95
+ update: 'Update',
96
+ pendingApproval: 'Pending npm approval',
97
+ updating: 'Updating…',
92
98
  installedDisabled: 'Installed · disabled',
93
99
  uploader: 'Uploaded by',
94
100
  unknownUploader: 'Uploader not recorded',
@@ -286,11 +292,24 @@ window.__ModuleLoader__.load({
286
292
  : h('span', null, t('unknownUploader')),
287
293
  item.publishedAt ? h('span', null, `${t('updated')} ${relativeTime(item.publishedAt, t)}`) : null,
288
294
  item.local ? h('span', { className: 'emk-tag' }, t('local')) : null,
295
+ item.pendingApproval ? h('span', { className: 'emk-tag' }, t('pendingApproval')) : null,
289
296
  ),
290
297
  h(
291
298
  'div',
292
299
  { className: 'emk-actions' },
293
- state !== null
300
+ state !== null && item.updateAvailable
301
+ ? h(
302
+ 'button',
303
+ {
304
+ className: 'emk-btn emk-btn-primary',
305
+ type: 'button',
306
+ 'data-update': item.name,
307
+ disabled: busy,
308
+ onClick: () => onInstall(item),
309
+ },
310
+ busy ? t('updating') : t('update'),
311
+ )
312
+ : state !== null
294
313
  ? h('button', { className: 'emk-btn', type: 'button', disabled: true }, state)
295
314
  : h(
296
315
  'button',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-enterprise-market",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "TranESS 企业插件市场:员工把自建插件发布到企业 npm 仓库,市场按企业身份显示上传人姓名,同事可直接下载安装。",
@@ -133,6 +133,17 @@ export async function buildCatalog(input) {
133
133
  const doc = await readPackument({ registry: input.registry, name, fetchImpl: input.fetchImpl })
134
134
  if (doc === null) return
135
135
  item.version = doc.latest ?? item.version
136
+ // 本地回执有、registry 里没有的版本:多半还在暂存区等人工批准。
137
+ // 这种状态不能显示成“已发布”,也不能拿它当可更新目标。
138
+ if (
139
+ item.local === true &&
140
+ typeof item.localVersion === 'string' &&
141
+ item.localVersion !== '' &&
142
+ !(Array.isArray(doc.publishedVersions) && doc.publishedVersions.includes(item.localVersion))
143
+ ) {
144
+ item.pendingApproval = true
145
+ item.updateAvailable = false
146
+ }
136
147
  item.description = item.description ?? doc.manifest?.description ?? null
137
148
  item.publishedAt = item.publishedAt ?? isoDay(doc.modified)
138
149
  item.uploader = uploaderOf(doc.manifest) ?? item.uploader
@@ -161,9 +172,14 @@ export async function buildCatalog(input) {
161
172
  const items = [...byName.values()]
162
173
  .map((item) => {
163
174
  const state = installed.get(item.name)
175
+ const installedVersion =
176
+ typeof state?.version === 'string' && state.version !== '' ? state.version : null
164
177
  return {
165
178
  ...item,
166
179
  installed: state?.installed === true,
180
+ installedVersion,
181
+ updateAvailable:
182
+ state?.installed === true && versionIsNewer(item.version, installedVersion),
167
183
  enabled: state?.enabled === true,
168
184
  installedVersion: state?.version ?? null,
169
185
  }
@@ -212,3 +228,26 @@ async function mapLimit(items, limit, worker) {
212
228
  })
213
229
  await Promise.all(runners)
214
230
  }
231
+
232
+
233
+ /**
234
+ * 判断仓库里的版本是否比本机已安装的新。只比较点分段数字,预发布后缀不参与;
235
+ * 任何无法解析的输入一律视为「不更新」,避免误报更新按钮。
236
+ *
237
+ * @param {string | null} candidate
238
+ * @param {string | null} current
239
+ */
240
+ export function versionIsNewer(candidate, current) {
241
+ if (typeof candidate !== 'string' || typeof current !== 'string') return false
242
+ const parse = (value) => value.split('-')[0].split('.').map((part) => Number.parseInt(part, 10))
243
+ const next = parse(candidate)
244
+ const have = parse(current)
245
+ if (next.some((n) => !Number.isFinite(n)) || have.some((n) => !Number.isFinite(n))) return false
246
+ const length = Math.max(next.length, have.length)
247
+ for (let index = 0; index < length; index += 1) {
248
+ const a = next[index] ?? 0
249
+ const b = have[index] ?? 0
250
+ if (a !== b) return a > b
251
+ }
252
+ return false
253
+ }
package/src/host/npm.js CHANGED
@@ -294,6 +294,7 @@ export async function readPackument(input) {
294
294
  if (manifest === undefined) return null
295
295
  return {
296
296
  latest,
297
+ publishedVersions: Object.keys(body?.versions ?? {}),
297
298
  manifest,
298
299
  modified: typeof body?.time?.modified === 'string' ? body.time.modified : undefined,
299
300
  }