@@ -36,6 +36,17 @@ type DepChangeSummary = {
3636
3737type DepChangeFilters = Record < DepChangeType , boolean > ;
3838
39+ type PublishPackage = {
40+ id : number ;
41+ name : string ;
42+ deps ?: Record < string , string > ;
43+ } ;
44+
45+ type DepsChangePackage = {
46+ pkg : PublishPackage ;
47+ changes : DepChangeRow [ ] ;
48+ } ;
49+
3950function getDepsChangeSummary ( changes : DepChangeRow [ ] ) : DepChangeSummary {
4051 return changes . reduce (
4152 ( acc , item ) => {
@@ -304,44 +315,131 @@ const BindPackage = ({
304315 ( p ) => ! matchedPackageIds . has ( p . id ) ,
305316 ) ;
306317
307- const publishToPackage = (
308- pkg : { id : number ; name : string ; deps ?: Record < string , string > } ,
309- rollout ?: number ,
310- ) => {
311- const publish = ( ) =>
312- api . upsertBinding ( {
318+ const publishToPackages = ( pkgs : PublishPackage [ ] , rollout ?: number ) => {
319+ if ( pkgs . length === 0 ) {
320+ return ;
321+ }
322+
323+ const publish = ( ) => {
324+ if ( pkgs . length === 1 ) {
325+ return api . upsertBinding ( {
326+ appId,
327+ packageId : pkgs [ 0 ] . id ,
328+ versionId,
329+ rollout,
330+ } ) ;
331+ }
332+
333+ return api . upsertBindings ( {
313334 appId,
314- packageId : pkg . id ,
335+ packageIds : pkgs . map ( ( pkg ) => pkg . id ) ,
315336 versionId,
316337 rollout,
317338 } ) ;
339+ } ;
318340
319- const changes = getDepsChanges ( pkg . deps , versionDeps ) ;
320- if ( ! changes || changes . length === 0 ) {
341+ const depsChangedPackages = pkgs . reduce < DepsChangePackage [ ] > ( ( acc , pkg ) => {
342+ const changes = getDepsChanges ( pkg . deps , versionDeps ) ;
343+ if ( changes ?. length ) {
344+ acc . push ( { pkg, changes } ) ;
345+ }
346+ return acc ;
347+ } , [ ] ) ;
348+ if ( depsChangedPackages . length === 0 ) {
321349 void publish ( ) ;
322350 return ;
323351 }
324352
353+ const content =
354+ depsChangedPackages . length === 1 ? (
355+ < DepsChangeConfirmContent
356+ packageName = { depsChangedPackages [ 0 ] . pkg . name }
357+ versionDisplayName = { versionName || versionId }
358+ changes = { depsChangedPackages [ 0 ] . changes }
359+ />
360+ ) : (
361+ < div className = "max-h-96 space-y-6 overflow-y-auto pr-2" >
362+ { depsChangedPackages . map ( ( { pkg, changes } ) => (
363+ < DepsChangeConfirmContent
364+ key = { pkg . id }
365+ packageName = { pkg . name }
366+ versionDisplayName = { versionName || versionId }
367+ changes = { changes }
368+ />
369+ ) ) }
370+ </ div >
371+ ) ;
372+
325373 Modal . confirm ( {
326374 title : '检测到依赖变化,确认继续发布?' ,
327375 maskClosable : true ,
328376 okButtonProps : { danger : true } ,
329377 okText : '继续发布' ,
330378 cancelText : '取消' ,
331379 width : 820 ,
332- content : (
333- < DepsChangeConfirmContent
334- packageName = { pkg . name }
335- versionDisplayName = { versionName || versionId }
336- changes = { changes }
337- />
338- ) ,
380+ content,
339381 async onOk ( ) {
340382 await publish ( ) ;
341383 } ,
342384 } ) ;
343385 } ;
344386
387+ const publishToPackage = ( pkg : PublishPackage , rollout ?: number ) =>
388+ publishToPackages ( [ pkg ] , rollout ) ;
389+
390+ const publishMenuItems : MenuProps [ 'items' ] = [ ] ;
391+ if ( availablePackages . length > 1 ) {
392+ publishMenuItems . push (
393+ {
394+ key : 'all' ,
395+ label : '全部可用原生包' ,
396+ children : [
397+ {
398+ key : 'all-full' ,
399+ label : '全量' ,
400+ icon : < CloudDownloadOutlined /> ,
401+ onClick : ( ) => publishToPackages ( availablePackages ) ,
402+ } ,
403+ {
404+ key : 'all-gray' ,
405+ label : '灰度' ,
406+ icon : < ExperimentOutlined /> ,
407+ children : [ 1 , 2 , 5 , 10 , 20 , 50 ] . map ( ( percentage ) => ( {
408+ key : `all-gray-${ percentage } ` ,
409+ label : `${ percentage } %` ,
410+ onClick : ( ) => publishToPackages ( availablePackages , percentage ) ,
411+ } ) ) ,
412+ } ,
413+ ] ,
414+ } ,
415+ { type : 'divider' } ,
416+ ) ;
417+ }
418+ publishMenuItems . push (
419+ ...availablePackages . map ( ( p ) => ( {
420+ key : `pkg-${ p . id } ` ,
421+ label : p . name ,
422+ children : [
423+ {
424+ key : `pkg-${ p . id } -full` ,
425+ label : '全量' ,
426+ icon : < CloudDownloadOutlined /> ,
427+ onClick : ( ) => publishToPackage ( p ) ,
428+ } ,
429+ {
430+ key : `pkg-${ p . id } -gray` ,
431+ label : '灰度' ,
432+ icon : < ExperimentOutlined /> ,
433+ children : [ 1 , 2 , 5 , 10 , 20 , 50 ] . map ( ( percentage ) => ( {
434+ key : `pkg-${ p . id } -gray-${ percentage } ` ,
435+ label : `${ percentage } %` ,
436+ onClick : ( ) => publishToPackage ( p , percentage ) ,
437+ } ) ) ,
438+ } ,
439+ ] ,
440+ } ) ) ,
441+ ) ;
442+
345443 const bindedPackages = ( ( ) => {
346444 const result = [ ] ;
347445 if ( matchedBindings . length === 0 || allPackages . length === 0 ) return null ;
@@ -432,28 +530,7 @@ const BindPackage = ({
432530 { availablePackages . length !== 0 && (
433531 < Dropdown
434532 menu = { {
435- items : availablePackages . map ( ( p ) => ( {
436- key : `pkg-${ p . id } ` ,
437- label : p . name ,
438- children : [
439- {
440- key : `pkg-${ p . id } -full` ,
441- label : '全量' ,
442- icon : < CloudDownloadOutlined /> ,
443- onClick : ( ) => publishToPackage ( p ) ,
444- } ,
445- {
446- key : `pkg-${ p . id } -gray` ,
447- label : '灰度' ,
448- icon : < ExperimentOutlined /> ,
449- children : [ 1 , 2 , 5 , 10 , 20 , 50 ] . map ( ( percentage ) => ( {
450- key : `pkg-${ p . id } -gray-${ percentage } ` ,
451- label : `${ percentage } %` ,
452- onClick : ( ) => publishToPackage ( p , percentage ) ,
453- } ) ) ,
454- } ,
455- ] ,
456- } ) ) ,
533+ items : publishMenuItems ,
457534 } }
458535 className = "ant-typography-edit"
459536 >
0 commit comments