Skip to content

Commit 423dd46

Browse files
committed
feat: added support for new /apps/list endpoint
1 parent acdba11 commit 423dd46

File tree

1 file changed

+169
-54
lines changed

1 file changed

+169
-54
lines changed

src/system/apps/Store.ts

Lines changed: 169 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { Process, RepoData } from '../../types'
22
import icon from '../../assets/icons/softwarecenter.svg'
3-
4-
import { sanitize } from '../../utils'
53
import nullIcon from '../../assets/icons/application-default-icon.svg'
64

75
const Store: Process = {
@@ -22,68 +20,175 @@ const Store: Process = {
2220
})
2321

2422
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')
2725

2826
fetch(`${process.kernel.config.SERVER as string}/apps/list/`)
2927
.then(async (res) => await res.json())
3028
.then(handle)
3129
.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-
})
3830

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')
4335

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))
5552

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+
}
6969

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+
}
74101

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))
87192
})
88193
}
89194

@@ -92,8 +197,18 @@ const Store: Process = {
92197
.then(async (data) => {
93198
await fs.writeFile(`/home/Applications/${url.split('/').at(-1)?.replace('.js', '.app') as string}`, `apps/${url.split('/').at(-1)?.split('.')[0] as string}`)
94199
await fs.writeFile(`/opt/apps/${url.split('/').at(-1) as string}`, data)
200+
await updateList()
95201
}).catch(e => console.error(e))
96202
}
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+
}
97212
}
98213
}
99214

0 commit comments

Comments
 (0)