1
1
import { Process , RepoData } from '../../types'
2
2
import icon from '../../assets/icons/softwarecenter.svg'
3
-
4
- import { sanitize } from '../../utils'
5
3
import nullIcon from '../../assets/icons/application-default-icon.svg'
6
4
7
5
const Store : Process = {
@@ -22,68 +20,175 @@ const Store: Process = {
22
20
} )
23
21
24
22
const fs = await process . loadLibrary ( 'lib/VirtualFS' )
25
-
26
- win . content . style . background = 'var(--base)'
23
+ const HTML = await process . loadLibrary ( 'lib/HTML' )
24
+ const { Button , Icon } = await process . loadLibrary ( 'lib/Components' )
27
25
28
26
fetch ( `${ process . kernel . config . SERVER as string } /apps/list/` )
29
27
. then ( async ( res ) => await res . json ( ) )
30
28
. then ( handle )
31
29
. catch ( e => console . error ( e ) )
32
- document . addEventListener ( 'fs_update' , ( ) => {
33
- fetch ( `${ process . kernel . config . SERVER as string } /apps/list/` )
34
- . then ( async ( res ) => await res . json ( ) )
35
- . then ( handle )
36
- . catch ( e => console . error ( e ) )
37
- } )
38
30
39
- function handle ( repos : RepoData [ ] ) : void {
40
- win . content . innerHTML = `
41
- <div class=" repos" style="display: flex;flex-direction: column;gap: 10px;"></div>
42
- `
31
+ async function updateList ( ) : Promise < void > {
32
+ const res = fetch ( ` ${ process . kernel . config . SERVER as string } /apps/list/` )
33
+ const repos = await ( await res ) . json ( )
34
+ const div = new HTML ( win . content ) . qs ( 'div' )
43
35
44
- repos . forEach ( ( repo ) => {
45
- ( win . content . querySelector ( '.repos' ) as HTMLElement ) . innerHTML += `
46
- <div data-repo-id="${ sanitize ( repo . id ) } " style="display: flex;flex-direction: column;gap: 10px;background: var(--surface-0);padding: 20px;margin: 10px;border-radius: 10px;">
47
- <div style="flex: 1;">
48
- <h2 style="margin: 0;margin-bottom: 10px;">${ sanitize ( repo . name ) } </h2>
49
- <code style="font-family: monospace;">${ sanitize ( repo . id ) } </code>
50
- </div>
51
- <br/>
52
- <div class="apps"></div>
53
- </div>
54
- `
36
+ repos . forEach ( async ( repo : string , index : number ) => {
37
+ const repoDiv = div . qsa ( 'div' ) [ index ]
38
+ repoDiv ?. html ( '' )
39
+ fetch ( `${ process . kernel . config . SERVER as string } /cors/?url=${ repo } ` )
40
+ . then ( async res => await res . json ( ) )
41
+ . then ( ( repo : RepoData ) => {
42
+ repo . apps . forEach ( ( app ) => {
43
+ fs . exists ( `/home/Applications/${ app . url . split ( '/' ) . at ( - 1 ) ?. replace ( '.js' , '.app' ) as string } ` )
44
+ . then ( ( exists : boolean ) => {
45
+ const button = Button . new ( ) . style ( {
46
+ display : 'flex' ,
47
+ gap : '5px' ,
48
+ 'align-items' : 'center'
49
+ } ) . text ( 'Uninstall' )
50
+ . prepend ( Icon . new ( 'delete' ) )
51
+ . on ( 'click' , ( ) => uninstall ( app . url ) )
55
52
56
- repo . apps . forEach ( ( app ) => {
57
- ( win . content . querySelector ( `div[data-repo-id="${ sanitize ( repo . id ) } "] > .apps` ) as HTMLElement ) . innerHTML += `
58
- <div data-pkg="${ sanitize ( app . name ) } " style="display: flex;gap: 20px;">
59
- <img src="${ sanitize ( app . icon ?? nullIcon ) } " height="59.5px" style="border-radius: var(--app-radius);">
60
- <div>
61
- <h3 style="margin: 0;margin-bottom: 10px;">${ sanitize ( app . name ) } </h3>
62
- <div style="display: flex;gap:5px;align-items: center;">
63
- <code style="font-family: monospace;">${ sanitize ( app . targetVer ) } </code>
64
- <span class="material-symbols-rounded">download</span>
65
- </div>
66
- </div>
67
- </div>
68
- `
53
+ if ( exists ) {
54
+ fetch ( `${ process . kernel . config . SERVER as string } /cors?url=${ app . url } ` )
55
+ . then ( async ( res ) => await res . text ( ) )
56
+ . then ( async ( data ) => {
57
+ const local = Buffer . from ( await fs . readFile ( `/opt/apps/${ app . url . split ( '/' ) . at ( - 1 ) as string } ` ) ) . toString ( )
58
+ if ( local !== data ) {
59
+ button . text ( 'Update' )
60
+ . prepend ( Icon . new ( 'update' ) )
61
+ . on ( 'click' , ( ) => install ( app . url ) )
62
+ }
63
+ } ) . catch ( e => console . error ( e ) )
64
+ } else {
65
+ button . text ( 'Install' )
66
+ . prepend ( Icon . new ( 'download' ) )
67
+ . on ( 'click' , ( ) => install ( app . url ) )
68
+ }
69
69
70
- fs . exists ( `/opt/apps/${ app . url . split ( '/' ) . at ( - 1 ) as string } ` ) . then ( ( exists : boolean ) => {
71
- fs . exists ( `/home/Applications/${ app . url . split ( '/' ) . at ( - 1 ) ?. replace ( '.js' , '.app' ) as string } ` ) . then ( ( exists2 : boolean ) => {
72
- if ( exists ) {
73
- ( win . content . querySelector ( `div[data-pkg="${ sanitize ( app . name ) } "] div > .material-symbols-rounded` ) as HTMLElement ) . innerHTML = 'delete' ;
70
+ new HTML ( 'div' )
71
+ . style ( {
72
+ display : 'flex' ,
73
+ 'flex-direction' : 'row' ,
74
+ gap : '10px' ,
75
+ padding : '10px' ,
76
+ background : 'var(--base)' ,
77
+ 'border-radius' : '10px'
78
+ } )
79
+ . appendMany (
80
+ new HTML ( 'img' ) . attr ( {
81
+ src : app . icon ?? nullIcon
82
+ } ) . style ( {
83
+ 'aspect-ratio' : '1 / 1' ,
84
+ width : '60px' ,
85
+ height : '60px'
86
+ } ) ,
87
+ new HTML ( 'div' ) . appendMany (
88
+ new HTML ( 'h3' ) . style ( {
89
+ margin : '0'
90
+ } ) . text ( app . name ) ,
91
+ button
92
+ )
93
+ )
94
+ . appendTo ( repoDiv )
95
+ } )
96
+ } )
97
+ } )
98
+ . catch ( e => console . error ( e ) )
99
+ } )
100
+ }
74
101
75
- ( win . content . querySelector ( `div[data-pkg="${ sanitize ( app . name ) } "] div > .material-symbols-rounded` ) as HTMLElement ) . onclick = async ( ) => {
76
- await fs . unlink ( `/home/Applications/${ app . url . split ( '/' ) . at ( - 1 ) ?. replace ( '.js' , '.app' ) as string } ` )
77
- await fs . unlink ( `/opt/apps/${ app . url . split ( '/' ) . at ( - 1 ) as string } ` )
78
- }
79
- } else {
80
- ( win . content . querySelector ( `div[data-pkg="${ sanitize ( app . name ) } "] div > .material-symbols-rounded` ) as HTMLElement ) . onclick = ( ) => {
81
- install ( app . url )
82
- }
83
- }
84
- } ) . catch ( ( e : any ) => console . error ( e ) )
85
- } ) . catch ( ( e : any ) => console . error ( e ) )
86
- } )
102
+ function handle ( repos : string [ ] ) : void {
103
+ win . content . innerHTML = ''
104
+ const div = new HTML ( 'div' ) . appendTo ( win . content )
105
+ repos . forEach ( ( repo ) => {
106
+ fetch ( `${ process . kernel . config . SERVER as string } /cors/?url=${ repo } ` )
107
+ . then ( async res => await res . json ( ) )
108
+ . then ( ( repo : RepoData ) => {
109
+ const icon = Icon . new ( 'arrow_drop_up' )
110
+ new HTML ( 'h2' ) . text ( repo . name ) . style ( {
111
+ margin : '0' ,
112
+ padding : '10px' ,
113
+ display : 'flex' ,
114
+ gap : '5px' ,
115
+ 'align-items' : 'center'
116
+ } )
117
+ . prepend ( icon )
118
+ . appendTo ( div )
119
+ . on ( 'click' , ( ) => {
120
+ repoDiv . style ( {
121
+ height : repoDiv . elm . style . height === '0px' ? 'max-content' : '0'
122
+ } )
123
+ icon . text ( `arrow_drop_${ repoDiv . elm . style . height === '0px' ? 'up' : 'down' } ` )
124
+ } )
125
+ const repoDiv = new HTML ( 'div' ) . appendTo ( div ) . style ( {
126
+ height : '0' ,
127
+ display : 'flex' ,
128
+ 'flex-direction' : 'column' ,
129
+ gap : '10px' ,
130
+ overflow : 'hidden' ,
131
+ padding : '0 10px'
132
+ } )
133
+ repo . apps . forEach ( ( app ) => {
134
+ fs . exists ( `/home/Applications/${ app . url . split ( '/' ) . at ( - 1 ) ?. replace ( '.js' , '.app' ) as string } ` )
135
+ . then ( ( exists : boolean ) => {
136
+ const button = Button . new ( ) . style ( {
137
+ display : 'flex' ,
138
+ gap : '5px' ,
139
+ 'align-items' : 'center'
140
+ } ) . text ( 'Uninstall' )
141
+ . prepend ( Icon . new ( 'delete' ) )
142
+ . on ( 'click' , ( ) => uninstall ( app . url ) )
143
+
144
+ if ( exists ) {
145
+ fetch ( `${ process . kernel . config . SERVER as string } /cors?url=${ app . url } ` )
146
+ . then ( async ( res ) => await res . text ( ) )
147
+ . then ( async ( data ) => {
148
+ const local = Buffer . from ( await fs . readFile ( `/opt/apps/${ app . url . split ( '/' ) . at ( - 1 ) as string } ` ) ) . toString ( )
149
+ if ( local !== data ) {
150
+ button . text ( 'Update' )
151
+ . prepend ( Icon . new ( 'update' ) )
152
+ . un ( 'click' , ( ) => uninstall ( app . url ) )
153
+ . on ( 'click' , ( ) => install ( app . url ) )
154
+ }
155
+ } ) . catch ( e => console . error ( e ) )
156
+ } else {
157
+ button . text ( 'Install' )
158
+ . prepend ( Icon . new ( 'download' ) )
159
+ . un ( 'click' , ( ) => uninstall ( app . url ) )
160
+ . on ( 'click' , ( ) => install ( app . url ) )
161
+ }
162
+
163
+ new HTML ( 'div' )
164
+ . style ( {
165
+ display : 'flex' ,
166
+ 'flex-direction' : 'row' ,
167
+ gap : '10px' ,
168
+ padding : '10px' ,
169
+ background : 'var(--base)' ,
170
+ 'border-radius' : '10px'
171
+ } )
172
+ . appendMany (
173
+ new HTML ( 'img' ) . attr ( {
174
+ src : app . icon ?? nullIcon
175
+ } ) . style ( {
176
+ 'aspect-ratio' : '1 / 1' ,
177
+ width : '60px' ,
178
+ height : '60px'
179
+ } ) ,
180
+ new HTML ( 'div' ) . appendMany (
181
+ new HTML ( 'h3' ) . style ( {
182
+ margin : '0'
183
+ } ) . text ( app . name ) ,
184
+ button
185
+ )
186
+ )
187
+ . appendTo ( repoDiv )
188
+ } )
189
+ } )
190
+ } )
191
+ . catch ( e => console . error ( e ) )
87
192
} )
88
193
}
89
194
@@ -92,8 +197,18 @@ const Store: Process = {
92
197
. then ( async ( data ) => {
93
198
await fs . writeFile ( `/home/Applications/${ url . split ( '/' ) . at ( - 1 ) ?. replace ( '.js' , '.app' ) as string } ` , `apps/${ url . split ( '/' ) . at ( - 1 ) ?. split ( '.' ) [ 0 ] as string } ` )
94
199
await fs . writeFile ( `/opt/apps/${ url . split ( '/' ) . at ( - 1 ) as string } ` , data )
200
+ await updateList ( )
95
201
} ) . catch ( e => console . error ( e ) )
96
202
}
203
+
204
+ function uninstall ( url : string ) : void {
205
+ fs . unlink ( `/home/Applications/${ url . split ( '/' ) . at ( - 1 ) ?. replace ( '.js' , '.app' ) as string } ` )
206
+ . then ( async ( ) => {
207
+ await fs . unlink ( `/opt/apps/${ url . split ( '/' ) . at ( - 1 ) as string } ` )
208
+ await updateList ( )
209
+ } )
210
+ . catch ( e => console . error ( e ) )
211
+ }
97
212
}
98
213
}
99
214
0 commit comments