Skip to content

Commit dcbb14c

Browse files
committed
live-web-edit: Switched WorkspaceView to Action based flow.
live-web-edit: Added APIRequest. live-web-edit: Switched WorkspaceRoutes to ValueOrError objects and added separate logging.
1 parent 8bf8099 commit dcbb14c

File tree

12 files changed

+430
-484
lines changed

12 files changed

+430
-484
lines changed

packages/live-web-edit/lib/server/Workspace.lv

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import path from 'path'
22
import fs from 'fs'
3-
43
import .lib.middle
54

5+
import PublicError from 'live-elements-web-server/shared/errors/public-error.mjs'
6+
67
component Workspace{
78

89
static string dataFile = 'workspace.json'
@@ -120,7 +121,7 @@ component Workspace{
120121
static fn load(location:string, name:string){
121122
const wspath = path.join(location, name)
122123
if ( !fs.existsSync(wspath) ){
123-
throw new Error(`Workspace '${name}' doesn't exist.`)
124+
throw new PublicError(`Workspace '${name}' doesn't exist.`)
124125
}
125126
const info = Workspace.loadInfo(wspath)
126127

@@ -192,7 +193,7 @@ component Workspace{
192193

193194
fn writeFile(filePath:string, content:string){
194195
if ( !this.canWrite() ){
195-
throw new Error(`Workspace ${this.name} is read-only.`)
196+
throw new PublicError(`Workspace ${this.name} is read-only.`)
196197
}
197198
const fullpath = path.join(this._path, filePath)
198199
const fileDir = path.dirname(fullpath)
@@ -212,7 +213,7 @@ component Workspace{
212213

213214
async fn compile(workspaceOperations:WorkspaceOperations, baseUrl:string){
214215
if ( !this.canWrite() ){
215-
throw new Error(`Workspace ${this.name} is read only. Can't compile.`)
216+
throw new PublicError(`Workspace ${this.name} is read only. Can't compile.`)
216217
}
217218
this._compilation = await workspaceOperations.compile(this, baseUrl)
218219
return this._compilation

packages/live-web-edit/lib/server/WorkspaceRoute.lv

Lines changed: 112 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ import live-elements-web-server.router
22
import live-elements-web-server.page.index
33
import .lib.middle
44

5+
import VE from 'live-elements-web-server/shared/core/value-or-error.mjs'
56
import PackagePath from 'live-elements-web-server/lib/package-path.cjs'
67
import CSSError from 'live-elements-web-server/shared/errors/css-error.mjs'
78
import StandardError from 'live-elements-web-server/shared/errors/standard-error.mjs'
9+
import PublicError from 'live-elements-web-server/shared/errors/public-error.mjs'
10+
import RequestError from 'live-elements-web-server/shared/errors/request-error.mjs'
811
import path from 'path'
912
import fs from 'fs'
1013

14+
1115
component WorkspaceRoute < Route{
1216
id: workspaceRoute
1317

@@ -85,7 +89,8 @@ component WorkspaceRoute < Route{
8589
}
8690
}
8791

88-
ViewRoute{ url: '/w/:wsname'
92+
ViewRoute{
93+
url: '/w/:wsname'
8994
c: workspaceRoute.view
9095
data: (req, res) => {
9196
try{
@@ -103,21 +108,29 @@ component WorkspaceRoute < Route{
103108
}
104109
}
105110

106-
GetRoute{ url: '/w-load/:wsname' f: async (req, res) => {
107-
const wsname = req.params.wsname
108-
let ws = null
109-
if ( wsname === '-' ){
110-
if ( fs.existsSync(path.join(workspaceRoute.workspaces.path, workspaceRoute.defaultProject))){
111-
ws = await workspaceRoute.workspaces.loadWorkspace(workspaceRoute.defaultProject)
111+
GetRoute{
112+
url: '/w-load/:wsname'
113+
f: async (req, res) => {
114+
try{
115+
const wsname = req.params.wsname
116+
let ws = null
117+
if ( wsname === '-' ){
118+
if ( fs.existsSync(path.join(workspaceRoute.workspaces.path, workspaceRoute.defaultProject))){
119+
ws = await workspaceRoute.workspaces.loadWorkspace(workspaceRoute.defaultProject)
120+
} else {
121+
ws = await workspaceRoute.workspaces.createWorkspaceFrom('default')
122+
ws.save()
123+
}
112124
} else {
113-
ws = await workspaceRoute.workspaces.createWorkspaceFrom('default')
114-
ws.save()
125+
ws = await workspaceRoute.workspaces.loadWorkspace(wsname)
115126
}
116-
} else {
117-
ws = await workspaceRoute.workspaces.loadWorkspace(wsname)
127+
128+
res.json(VE.vob(workspaceRoute.workspaceData(ws)))
129+
res.end()
130+
} catch (e) {
131+
console.error(RequestError.wrap(req, e).toString())
132+
res.status(500).json(VE.eob(PublicError.mask(e, 'Workspace loading error.')))
118133
}
119-
res.json(workspaceRoute.workspaceData(ws))
120-
res.end()
121134
}
122135
}
123136

@@ -127,85 +140,108 @@ component WorkspaceRoute < Route{
127140
}
128141
}
129142

130-
PostRoute{ url: '/w-fork/:wsname' f: async (req, res) => {
131-
const name = req.params.wsname
132-
let wsFrom = name
133-
if ( wsFrom === 'default' ){
134-
const ws = await workspaceRoute.workspaces.createWorkspaceFrom('default')
135-
ws.save()
136-
res.json(workspaceRoute.workspaceData(ws))
137-
res.end()
138-
return
139-
}
143+
PostRoute{ url: '/w-fork/:wsname'
144+
f: async (req, res) => {
145+
try{
146+
const name = req.params.wsname
147+
let wsFrom = name
148+
if ( wsFrom === 'default' ){
149+
const ws = await workspaceRoute.workspaces.createWorkspaceFrom('default')
150+
ws.save()
151+
res.json(VE.vob(workspaceRoute.workspaceData(ws))).end()
152+
return
153+
}
140154

141-
for ( let i = 0; i < workspaceRoute.templates.length; ++i ){
142-
if ( workspaceRoute.templates[i].name === name ){
143-
wsFrom = workspaceRoute.templates[i].path
144-
const ws = await workspaceRoute.workspaces.createWorkspaceFrom(wsFrom)
145-
res.json(workspaceRoute.workspaceData(ws))
146-
res.end()
147-
return
155+
for ( let i = 0; i < workspaceRoute.templates.length; ++i ){
156+
if ( workspaceRoute.templates[i].name === name ){
157+
wsFrom = workspaceRoute.templates[i].path
158+
const ws = await workspaceRoute.workspaces.createWorkspaceFrom(wsFrom)
159+
res.json(VE.vob(workspaceRoute.workspaceData(ws))).end()
160+
return
161+
}
162+
}
163+
164+
const ws = workspaceRoute.workspaces.loadWorkspace(wsFrom)
165+
const wsfork = await workspaceRoute.workspaces.createWorkspaceFrom(req.params.wsname)
166+
res.json(VE.vob(workspaceRoute.workspaceData(wsfork))).end()
167+
} catch (e) {
168+
console.error(RequestError.wrap(req, e).toString())
169+
res.status(500).json(VE.eob(PublicError.mask(e, 'Workspace fork error.')))
148170
}
171+
149172
}
173+
}
150174

151-
const ws = workspaceRoute.workspaces.loadWorkspace(wsFrom)
152-
const wsfork = await workspaceRoute.workspaces.createWorkspaceFrom(req.params.wsname)
153-
res.json(workspaceRoute.workspaceData(wsfork))
154-
}}
155-
156-
PostRoute{ url: '/w-document/save/:wsname' f: async (req, res) => {
157-
const ws = workspaceRoute.workspaces.loadWorkspace(req.params.wsname)
158-
const doc = req.body.document
175+
PostRoute{ url: '/w-document/save/:wsname'
176+
f: async (req, res) => {
177+
try{
178+
const ws = workspaceRoute.workspaces.loadWorkspace(req.params.wsname)
179+
const doc = req.body.document
159180

160-
if ( ws.writeBehavior === Workspace.WriteBehavior.Write ){
161-
const wsdoc = ws.isDocumentOpened(doc.path)
162-
if ( wsdoc ){
163-
const contentRestore = wsdoc.content
164-
try{
165-
wsdoc.content = doc.content
166-
} catch ( e ){
167-
wsdoc.content = contentRestore
181+
if ( ws.writeBehavior === Workspace.WriteBehavior.Write ){
182+
const wsdoc = ws.isDocumentOpened(doc.path)
183+
if ( wsdoc ){
184+
const contentRestore = wsdoc.content
185+
try{
186+
wsdoc.content = doc.content
187+
} catch ( e ){
188+
wsdoc.content = contentRestore
189+
}
190+
ws.writeFile(doc.path, doc.content)
168191
}
169-
ws.writeFile(doc.path, doc.content)
170-
}
171-
res.json({ success: true }).end()
172-
} else if ( ws.writeBehavior === Workspace.WriteBehavior.Fork ){
173-
const wsfork = await workspaceRoute.workspaces.createWorkspaceFrom(req.params.wsname)
174-
const wsdoc = wsfork.isDocumentOpened(doc.path)
175-
if ( wsdoc ){
176-
const contentRestore = wsdoc.content
177-
try{
178-
wsdoc.content = doc.content
179-
} catch ( e ){
180-
wsdoc.content = contentRestore
192+
res.json(VE.vob({ success: true })).end()
193+
} else if ( ws.writeBehavior === Workspace.WriteBehavior.Fork ){
194+
const wsfork = await workspaceRoute.workspaces.createWorkspaceFrom(req.params.wsname)
195+
const wsdoc = wsfork.isDocumentOpened(doc.path)
196+
if ( wsdoc ){
197+
const contentRestore = wsdoc.content
198+
try{
199+
wsdoc.content = doc.content
200+
} catch ( e ){
201+
wsdoc.content = contentRestore
202+
}
203+
wsfork.writeFile(doc.path, doc.content)
181204
}
182-
wsfork.writeFile(doc.path, doc.content)
205+
res.json(VE.vob(workspaceRoute.workspaceData(wsfork))).end()
206+
} else {
207+
res.json(VE.eob(new PublicError('Workspace is read-only.')))
183208
}
184-
res.json({ data: workspaceRoute.workspaceData(wsfork) })
185-
} else {
186-
res.json({ error: 'Workspace is read-only.'} )
209+
} catch (e) {
210+
console.error(RequestError.wrap(req, e).toString())
211+
res.status(500).json(VE.eob(PublicError.mask(e, 'Document save error.')))
187212
}
188213
}
189214
}
190215

191-
PostRoute{ url: '/w-compile/:wsname' f: async (req, res) => {
192-
const ws = workspaceRoute.workspaces.loadWorkspace(req.params.wsname)
193-
const result = await ws.compile(workspaceRoute.workspaces.operations, workspaceRoute.url)
194-
if ( result.hasErrors() ){
195-
ws.save()
196-
res.json({error: { messages: result.errors.map(e => e.message)} }).end()
197-
} else {
198-
res.json({success: true, compilation: result.identifier }).end()
216+
PostRoute{ url: '/w-compile/:wsname'
217+
f: async (req, res) => {
218+
try{
219+
const ws = workspaceRoute.workspaces.loadWorkspace(req.params.wsname)
220+
const result = await ws.compile(workspaceRoute.workspaces.operations, workspaceRoute.url)
221+
if ( result.hasErrors() ){
222+
throw new PublicError(result.errors.map(e => e.message))
223+
} else {
224+
res.json(VE.vob({compilation: result.identifier})).end()
225+
}
226+
} catch (e) {
227+
console.error(RequestError.wrap(req, e).toString())
228+
res.status(500).json(VE.eob(PublicError.mask(e, 'Workspace compilation error.')))
229+
}
199230
}
200-
}}
231+
}
201232

202233
PostRoute{ url: '/w-lockwrite/:wsname' f: async (req, res) => {
203-
const ws = workspaceRoute.workspaces.loadWorkspace(req.params.wsname)
204-
if ( ws.writeBehavior !== Workspace.WriteBehavior.ReadOnly ){
205-
ws.writeBehavior = Workspace.WriteBehavior.ReadOnly
206-
ws.save()
234+
try{
235+
const ws = workspaceRoute.workspaces.loadWorkspace(req.params.wsname)
236+
if ( ws.writeBehavior !== Workspace.WriteBehavior.ReadOnly ){
237+
ws.writeBehavior = Workspace.WriteBehavior.ReadOnly
238+
ws.save()
239+
}
240+
res.json(VE.vob({success: true})).end()
241+
} catch (e) {
242+
console.error(RequestError.wrap(req, e).toString())
243+
res.status(500).json(VE.eob(PublicError.mask(e, 'Workspace lock write error.')))
207244
}
208-
res.json({success: true}).end()
209245
}
210246
}
211247

packages/live-web-edit/view/codeeditor/CodeEditorView.lv

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,6 @@ component CodeEditorView < Div{
174174
const newUseFragment = LvFragmentEditor.findUse(useText, useText.length - 1)
175175
const newUseSegments = newUseFragment.source.split(',').map(i => i.trim()).filter(i => i.length > 0)
176176

177-
console.log("COMPARIGIN:", newUseSegments, existingUseSegments)
178-
179177
const uniqueUseSegments = newUseSegments.filter(newImp =>
180178
!existingUseSegments.some(existing => existing === newImp)
181179
);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import ky from 'ky'
2+
import ValueOrError from 'live-elements-web-server/shared/core/value-or-error.mjs'
3+
4+
export default class ApiRequest{
5+
6+
static get(url){
7+
return ky.get(url).json()
8+
.then(response => { return ValueOrError.fromJSON(response) })
9+
.catch( e => {
10+
if ( e.response ){
11+
return e.response.json().then(data => {
12+
return ValueOrError.fromJSON(data)
13+
})
14+
} else {
15+
return ValueOrError.fromError(new Error(`Internal server error.`))
16+
}
17+
})
18+
}
19+
20+
static post(url, data, timeout = 10000){
21+
return ky.post(url, { json: data, timeout } ).json()
22+
.then(response => {
23+
return ValueOrError.fromJSON(response)
24+
})
25+
.catch( e => {
26+
if ( e.response ){
27+
return e.response.json().then(errData => {
28+
return ValueOrError.fromJSON(errData)
29+
})
30+
} else {
31+
return ValueOrError.fromError(new Error(`Internal server error.`))
32+
}
33+
})
34+
}
35+
}

packages/live-web-edit/view/workspace/WorkspaceOpenSelector.lv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ component WorkspaceOpenSelector < Div{
99
ScopedStyle{ src: './style/workspaceopenselector.css' process: 'live-web-view/style/CSSProcessor.lv' }
1010
]
1111

12-
static fn groupBySection(data:Array<Object>){
12+
static fn groupBySection(data:Object[]){
1313
const groupedData = {}
1414
data.forEach(item => {
1515
if (!groupedData[item.section]) {

0 commit comments

Comments
 (0)