1111 class =" details"
1212 :title =" progressDetails"
1313 >{{ progressDetails }}</label >
14- <Progress
14+ <CustomProgress
1515 class =" progress-bar"
1616 :indeterminate =" progressIndeterminate"
1717 :value =" progress.current"
2626
2727<script lang="ts">
2828import Vue from ' vue' ;
29- import Component from ' vue-class-component' ;
3029
31- import Progress from ' @pkg/components/Progress.vue' ;
30+ import CustomProgress from ' @pkg/components/Progress.vue' ;
3231import { ipcRenderer } from ' @pkg/utils/ipcRenderer' ;
3332
34- @Component ({ components: { Progress } })
35- class BackendProgress extends Vue {
36- /** Current Kubernetes backend action progress. */
37- progress: {
38- /** The current progress, from 0 to max. */
39- readonly current: number ;
40- /** Maximum possible progress; if less than zero, the progress is indeterminate. */
41- readonly max: number ;
42- /** Description of current action. */
43- readonly description? : string ;
44- /** Time since the description became valid. */
45- readonly transitionTime? : Date ;
46- } = { current: 1 , max: 1 };
47-
48- progressInterval: ReturnType <typeof setInterval > | undefined ;
49-
50- get progressDetails(): string {
51- return this .progress .description || ' ' ;
52- }
53-
54- progressDuration = ' ' ;
55-
56- get progressIndeterminate(): boolean {
57- return this .progress .max <= 0 ;
58- }
59-
60- get progressBusy(): boolean {
61- return this .progressIndeterminate || this .progress .current < this .progress .max ;
62- }
63-
64- /** Return a string describing the elapsed time or progress. */
65- describeElapsed(since : number ): string {
66- if (this .progress .max > 0 ) {
67- // If we have numbers, give a description about that.
68- const units = [' ' , ' K' , ' M' , ' G' , ' T' ];
69- let remaining = this .progress .max - this .progress .current ;
70-
71- while (remaining > 512 && units .length > 0 ) {
72- remaining /= 1024 ;
73- units .shift ();
74- }
75- if (remaining > 0 ) {
76- remaining = Math .round (remaining );
77- } else {
78- remaining = Math .round (remaining * 10 ) / 10 ;
79- }
80-
81- return ` ${ remaining }${ units [0 ] } left ` ;
82- }
83- if (! since ) {
84- return ' ' ;
85- }
86- let remaining = Math .floor ((Date .now () - since ) / 1000 );
87- const parts: [number , string ][] = [];
88-
89- parts .unshift ([remaining % 60 , ' s' ]);
90- remaining = Math .floor (remaining / 60 );
91- parts .unshift ([remaining % 60 , ' m' ]);
92- remaining = Math .floor (remaining / 60 );
93- parts .unshift ([remaining % 24 , ' h' ]);
94- parts .unshift ([Math .floor (remaining / 24 ), ' d' ]);
95-
96- return parts .filter (([n , s ]) => n > 0 ).map (([n , s ]) => ` ${ n }${ s } ` ).join (' ' );
97- }
33+ export default Vue .extend ({
34+ components: { CustomProgress },
35+ data() {
36+ return {
37+ /** Current Kubernetes backend action progress. */
38+ progress: { current: 1 , max: 1 } as {
39+ /** The current progress, from 0 to max. */
40+ readonly current: number ;
41+ /** Maximum possible progress; if less than zero, the progress is indeterminate. */
42+ readonly max: number ;
43+ /** Description of current action. */
44+ readonly description? : string ;
45+ /** Time since the description became valid. */
46+ readonly transitionTime? : Date ;
47+ },
48+ progressInterval: undefined as ReturnType <typeof setInterval > | undefined ,
49+ progressDuration: ' ' ,
50+ };
51+ },
52+
53+ computed: {
54+ progressDetails(): string {
55+ return this .progress .description || ' ' ;
56+ },
57+ progressIndeterminate(): boolean {
58+ return this .progress .max <= 0 ;
59+ },
60+ progressBusy(): boolean {
61+ return this .progressIndeterminate || this .progress .current < this .progress .max ;
62+ },
63+ },
9864
9965 mounted() {
10066 ipcRenderer .on (' k8s-progress' , (event , progress ) => {
@@ -117,9 +83,45 @@ class BackendProgress extends Vue {
11783 ipcRenderer .invoke (' k8s-progress' ).then ((progress ) => {
11884 this .progress = progress ;
11985 });
120- }
121- }
122- export default BackendProgress ;
86+ },
87+
88+ methods: {
89+ /** Return a string describing the elapsed time or progress. */
90+ describeElapsed(since : number ): string {
91+ if (this .progress .max > 0 ) {
92+ // If we have numbers, give a description about that.
93+ const units = [' ' , ' K' , ' M' , ' G' , ' T' ];
94+ const scales = [2 ** 0 , 2 ** 10 , 2 ** 20 , 2 ** 30 , 2 ** 40 ];
95+ const remaining = this .progress .max - this .progress .current ;
96+
97+ const unitIndex = scales .findLastIndex ((scale ) => remaining * 2 >= scale );
98+ const fraction = remaining / scales [unitIndex ];
99+ // If the fraction is 0.5...0.9999 display it as single significant figure.
100+ const display = fraction > 1 ? Math .round (fraction ) : Math .round (fraction * 10 ) / 10 ;
101+ return ` ${ display }${ units [unitIndex ] } left ` ;
102+ }
103+ if (! since ) {
104+ return ' ' ;
105+ }
106+ // We have a starting time; describe how much time has elapsed since.
107+ // Start from the smallest unit, and modify `remaining` to be the next
108+ // unit up at every iteration.
109+ let remaining = Math .floor ((Date .now () - since ) / 1000 ); // Elapsed time, in seconds.
110+ const scales: [number , string ][] = [[60 , ' s' ], [60 , ' m' ], [24 , ' h' ], [Number .POSITIVE_INFINITY, ' d' ]];
111+ let label = ' ' ;
112+
113+ for (const [scale, unit] of scales ) {
114+ if (remaining % scale > 0 ) {
115+ // Add the part, but only if it's non-zero.
116+ label = ` ${ remaining % scale }${ unit }${ label } ` ;
117+ }
118+ remaining = Math .floor (remaining / scale );
119+ }
120+
121+ return label ;
122+ },
123+ },
124+ });
123125 </script >
124126
125127<style lang="scss" scoped>
0 commit comments