@@ -69,6 +69,7 @@ import { docsPath, EnvironmentParamSchema, v3BillingPath } from "~/utils/pathBui
6969import { PauseEnvironmentService } from "~/v3/services/pauseEnvironment.server" ;
7070import { PauseQueueService } from "~/v3/services/pauseQueue.server" ;
7171import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route" ;
72+ import { Header3 } from "~/components/primitives/Headers" ;
7273import { Input } from "~/components/primitives/Input" ;
7374import { useThrottle } from "~/hooks/useThrottle" ;
7475
@@ -257,13 +258,30 @@ export default function Page() {
257258 suffix = { env . paused && environment . queued > 0 ? "paused" : undefined }
258259 animate
259260 accessory = { < EnvironmentPauseResumeButton env = { env } /> }
260- valueClassName = { env . paused ? "text-amber-500" : undefined }
261+ valueClassName = { env . paused ? "text-warning" : undefined }
262+ compactThreshold = { 1000000 }
263+ />
264+ < BigNumber
265+ title = "Running"
266+ value = { environment . running }
267+ animate
268+ valueClassName = {
269+ environment . running === environment . concurrencyLimit ? "text-warning" : undefined
270+ }
271+ suffix = {
272+ environment . running === environment . concurrencyLimit
273+ ? "At concurrency limit"
274+ : undefined
275+ }
276+ compactThreshold = { 1000000 }
261277 />
262- < BigNumber title = "Running" value = { environment . running } animate />
263278 < BigNumber
264279 title = "Concurrency limit"
265280 value = { environment . concurrencyLimit }
266281 animate
282+ valueClassName = {
283+ environment . running === environment . concurrencyLimit ? "text-warning" : undefined
284+ }
267285 accessory = {
268286 plan ? (
269287 plan ?. v3Subscription ?. plan ?. limits . concurrentRuns . canExceed ? (
@@ -307,7 +325,37 @@ export default function Page() {
307325 < TableRow >
308326 < TableHeaderCell > Name</ TableHeaderCell >
309327 < TableHeaderCell alignment = "right" > Queued</ TableHeaderCell >
310- < TableHeaderCell alignment = "right" > Running</ TableHeaderCell >
328+ < TableHeaderCell alignment = "right" > Running/limit</ TableHeaderCell >
329+ < TableHeaderCell
330+ alignment = "right"
331+ tooltip = {
332+ < div className = "max-w-xs space-y-2 p-1 text-left" >
333+ < div className = "space-y-0.5" >
334+ < Header3 > Environment</ Header3 >
335+ < Paragraph
336+ variant = "small"
337+ className = "!text-wrap text-text-dimmed"
338+ spacing
339+ >
340+ This queue is limited by your environment's concurrency limit of{ " " }
341+ { environment . concurrencyLimit } .
342+ </ Paragraph >
343+ </ div >
344+ < div className = "space-y-0.5" >
345+ < Header3 > User</ Header3 >
346+ < Paragraph
347+ variant = "small"
348+ className = "!text-wrap text-text-dimmed"
349+ spacing
350+ >
351+ This queue is limited by a concurrency limit set in your code.
352+ </ Paragraph >
353+ </ div >
354+ </ div >
355+ }
356+ >
357+ Limited by
358+ </ TableHeaderCell >
311359 < TableHeaderCell
312360 alignment = "right"
313361 tooltip = {
@@ -334,88 +382,110 @@ export default function Page() {
334382 >
335383 Release on waitpoint
336384 </ TableHeaderCell >
337- < TableHeaderCell alignment = "right" > Concurrency limit</ TableHeaderCell >
338385 < TableHeaderCell className = "w-[1%] pl-24" >
339386 < span className = "sr-only" > Pause/resume</ span >
340387 </ TableHeaderCell >
341388 </ TableRow >
342389 </ TableHeader >
343390 < TableBody >
344391 { queues . length > 0 ? (
345- queues . map ( ( queue ) => (
346- < TableRow key = { queue . name } >
347- < TableCell >
348- < span className = "flex items-center gap-2" >
349- { queue . type === "task" ? (
350- < SimpleTooltip
351- button = {
352- < TaskIconSmall
353- className = { cn (
354- "size-[1.125rem] text-blue-500" ,
355- queue . paused && "opacity-50"
356- ) }
357- />
358- }
359- content = { `This queue was automatically created from your "${ queue . name } " task` }
360- />
361- ) : (
362- < SimpleTooltip
363- button = {
364- < RectangleStackIcon
365- className = { cn (
366- "size-[1.125rem] text-purple-500" ,
367- queue . paused && "opacity-50"
368- ) }
369- />
370- }
371- content = { `This is a custom queue you added in your code.` }
372- />
373- ) }
374- < span className = { queue . paused ? "opacity-50" : undefined } >
375- { queue . name }
392+ queues . map ( ( queue ) => {
393+ const limit = queue . concurrencyLimit ?? environment . concurrencyLimit ;
394+ const isAtLimit = queue . running === limit ;
395+ return (
396+ < TableRow key = { queue . name } >
397+ < TableCell >
398+ < span className = "flex items-center gap-2" >
399+ { queue . type === "task" ? (
400+ < SimpleTooltip
401+ button = {
402+ < TaskIconSmall
403+ className = { cn (
404+ "size-[1.125rem] text-blue-500" ,
405+ queue . paused && "opacity-50"
406+ ) }
407+ />
408+ }
409+ content = { `This queue was automatically created from your "${ queue . name } " task` }
410+ />
411+ ) : (
412+ < SimpleTooltip
413+ button = {
414+ < RectangleStackIcon
415+ className = { cn (
416+ "size-[1.125rem] text-purple-500" ,
417+ queue . paused && "opacity-50"
418+ ) }
419+ />
420+ }
421+ content = { `This is a custom queue you added in your code.` }
422+ />
423+ ) }
424+ < span className = { queue . paused ? "opacity-50" : undefined } >
425+ { queue . name }
426+ </ span >
427+ { queue . paused ? (
428+ < Badge variant = "extra-small" className = "text-warning" >
429+ Paused
430+ </ Badge >
431+ ) : null }
432+ { isAtLimit ? (
433+ < Badge variant = "extra-small" className = "text-warning" >
434+ At concurrency limit
435+ </ Badge >
436+ ) : null }
376437 </ span >
377- { queue . paused ? (
378- < Badge variant = "extra-small" className = "text-warning" >
379- Paused
380- </ Badge >
381- ) : null }
382- </ span >
383- </ TableCell >
384- < TableCell
385- alignment = "right"
386- className = { queue . paused ? "opacity-50" : undefined }
387- >
388- { queue . queued }
389- </ TableCell >
390- < TableCell
391- alignment = "right"
392- className = { queue . paused ? "opacity-50" : undefined }
393- >
394- { queue . running }
395- </ TableCell >
396- < TableCell
397- alignment = "right"
398- className = { queue . paused ? "opacity-50" : undefined }
399- >
400- { queue . releaseConcurrencyOnWaitpoint ? "Yes" : "No" }
401- </ TableCell >
402- < TableCell
403- alignment = "right"
404- className = { queue . paused ? "opacity-50" : undefined }
405- >
406- { queue . concurrencyLimit ?? (
407- < span className = "text-text-dimmed" >
408- Max ({ environment . concurrencyLimit } )
438+ </ TableCell >
439+ < TableCell
440+ alignment = "right"
441+ className = { queue . paused ? "opacity-50" : undefined }
442+ >
443+ { queue . queued }
444+ </ TableCell >
445+ < TableCell
446+ alignment = "right"
447+ className = { cn (
448+ queue . paused ? "tabular-nums opacity-50" : undefined ,
449+ isAtLimit && "text-warning"
450+ ) }
451+ >
452+ { queue . running } /
453+ < span
454+ className = { cn (
455+ "tabular-nums text-text-dimmed" ,
456+ isAtLimit && "text-warning"
457+ ) }
458+ >
459+ { limit }
409460 </ span >
410- ) }
411- </ TableCell >
412- < TableCellMenu
413- isSticky
414- visibleButtons = { queue . paused && < QueuePauseResumeButton queue = { queue } /> }
415- hiddenButtons = { ! queue . paused && < QueuePauseResumeButton queue = { queue } /> }
416- />
417- </ TableRow >
418- ) )
461+ </ TableCell >
462+ < TableCell
463+ alignment = "right"
464+ className = { cn (
465+ queue . paused ? "opacity-50" : undefined ,
466+ isAtLimit && "text-warning"
467+ ) }
468+ >
469+ { queue . concurrencyLimit ? "User" : "Environment" }
470+ </ TableCell >
471+ < TableCell
472+ alignment = "right"
473+ className = { queue . paused ? "opacity-50" : undefined }
474+ >
475+ { queue . releaseConcurrencyOnWaitpoint ? "Yes" : "No" }
476+ </ TableCell >
477+ < TableCellMenu
478+ isSticky
479+ visibleButtons = {
480+ queue . paused && < QueuePauseResumeButton queue = { queue } />
481+ }
482+ hiddenButtons = {
483+ ! queue . paused && < QueuePauseResumeButton queue = { queue } />
484+ }
485+ />
486+ </ TableRow >
487+ ) ;
488+ } )
419489 ) : (
420490 < TableRow >
421491 < TableCell colSpan = { 6 } >
@@ -503,7 +573,7 @@ function EnvironmentPauseResumeButton({
503573 type = "button"
504574 variant = "secondary/small"
505575 LeadingIcon = { env . paused ? PlayIcon : PauseIcon }
506- leadingIconClassName = { env . paused ? "text-success" : "text-amber-500 " }
576+ leadingIconClassName = { env . paused ? "text-success" : "text-warning " }
507577 >
508578 { env . paused ? "Resume..." : "Pause environment..." }
509579 </ Button >
@@ -512,8 +582,8 @@ function EnvironmentPauseResumeButton({
512582 </ TooltipTrigger >
513583 < TooltipContent className = { "text-xs" } >
514584 { env . paused
515- ? `Resume processing runs in ${ environmentFullTitle ( env ) } . `
516- : `Pause processing runs in ${ environmentFullTitle ( env ) } . ` }
585+ ? `Resume processing runs in ${ environmentFullTitle ( env ) } `
586+ : `Pause processing runs in ${ environmentFullTitle ( env ) } ` }
517587 </ TooltipContent >
518588 </ Tooltip >
519589 </ TooltipProvider >
@@ -582,7 +652,7 @@ function QueuePauseResumeButton({
582652 type = "button"
583653 variant = "tertiary/small"
584654 LeadingIcon = { queue . paused ? PlayIcon : PauseIcon }
585- leadingIconClassName = { queue . paused ? "text-success" : "text-amber-500 " }
655+ leadingIconClassName = { queue . paused ? "text-success" : "text-warning " }
586656 >
587657 { queue . paused ? "Resume..." : "Pause..." }
588658 </ Button >
@@ -703,7 +773,7 @@ export function QueueFilters() {
703773 const search = searchParams . get ( "query" ) ?? "" ;
704774
705775 return (
706- < div className = "flex w-full px-3 pb-3 " >
776+ < div className = "flex w-full border-t border-grid-dimmed px-1.5 py-1.5 " >
707777 < Input
708778 name = "search"
709779 placeholder = "Search queue name"
0 commit comments