Add metadata to zipArchives (display Github links in explorer)

This commit is contained in:
ochafik 2023-03-27 19:34:52 +01:00
commit 0ed2d658d0
5 changed files with 186 additions and 56 deletions

View file

@ -31,9 +31,11 @@ Licenses: see [LICENSES](./LICENSE).
- Proper PWA w/ File opening / association to *.scad files - Proper PWA w/ File opening / association to *.scad files
- Animation rendering (And other formats than STL) - Animation rendering (And other formats than STL)
- Compress URL fragment - Compress URL fragment
- Customizer support. Probably by adding --export-json or --export-format=customizer-json to OpenSCAD. - Customizer support. Probably by adding --export-json or --export-format=customizer-json to OpenSCAD. And use React Hook Forms maybe? https://react-hook-form.com/
- Mobile (iOS) editing support: switch to https://www.npmjs.com/package/react-codemirror ? - Mobile (iOS) editing support: switch to https://www.npmjs.com/package/react-codemirror ?
- Proper Preview rendering: have OpenSCAD export the preview scene to a rich format (e.g. glTF, with some parts being translucent when prefixed w/ % modifier) and display it using https://modelviewer.dev/ maybe) - Proper Preview rendering: have OpenSCAD export the preview scene to a rich format (e.g. glTF, with some parts being translucent when prefixed w/ % modifier) and display it using https://modelviewer.dev/ maybe)
- Detect which bundled libraries are included / used in the sources and only download these rather than wait for all of the zips. Means the file explorer would need to be more lazy or have some prebuilt hierarchy.
- Preparse builtin libraries definitions at compile time, ship the JSON.
## Building ## Building

View file

@ -7,6 +7,7 @@ import { ModelContext, FSContext } from './contexts';
// import { isFileWritable } from '../state/model'; // import { isFileWritable } from '../state/model';
import { join } from '../fs/filesystem'; import { join } from '../fs/filesystem';
import { defaultSourcePath } from '../state/initial-state'; import { defaultSourcePath } from '../state/initial-state';
import { zipArchives } from '../fs/zip-archives';
function listFilesAsNodes(fs: FS, path: string, accept?: (path: string) => boolean): TreeNode[] { function listFilesAsNodes(fs: FS, path: string, accept?: (path: string) => boolean): TreeNode[] {
const files: [string, string][] = [] const files: [string, string][] = []
@ -15,7 +16,7 @@ function listFilesAsNodes(fs: FS, path: string, accept?: (path: string) => boole
if (name.startsWith('.')) { if (name.startsWith('.')) {
continue; continue;
} }
const childPath = join(path, name);//`${path}/${name}`; const childPath = join(path, name);
if (accept && !accept(childPath)) { if (accept && !accept(childPath)) {
continue; continue;
} }
@ -31,19 +32,47 @@ function listFilesAsNodes(fs: FS, path: string, accept?: (path: string) => boole
const nodes: TreeNode[] = [] const nodes: TreeNode[] = []
for (const [arr, isDirectory] of [[files, false], [dirs, true]] as [[string, string][], boolean][]) { for (const [arr, isDirectory] of [[files, false], [dirs, true]] as [[string, string][], boolean][]) {
for (const [name, path] of arr) { for (const [name, path] of arr) {
const children = isDirectory ? listFilesAsNodes(fs, path) : undefined; let children: TreeNode[] = [];
if (isDirectory && children!.length == 0) { let label = name;
continue; if (path.lastIndexOf('/') === 0) {
const config = zipArchives[name];
if (config && config.gitOrigin) {
const repoUrl = config.gitOrigin.repoUrl;
if (!children) children = [];
children.push({
icon: 'pi pi-github',
label: repoUrl,
key: repoUrl,
selectable: true,
});
for (const [label, link] of Object.entries(config.docs ?? [])) {
children.push({
icon: 'pi pi-book',
label,
key: link,
selectable: true,
});
}
}
} }
if (isDirectory) {
children = [...children, ...listFilesAsNodes(fs, path, accept)];
if (children.length == 0) {
continue;
}
}
nodes.push({ nodes.push({
// icon: path == '/home' ? 'pi-home' : ...
// icon: isDirectory ? 'pi pi-folder' : isFileWritable(path) ? 'pi pi-file' : 'pi pi-lock', // icon: isDirectory ? 'pi pi-folder' : isFileWritable(path) ? 'pi pi-file' : 'pi pi-lock',
icon: isDirectory ? 'pi pi-folder' : path === defaultSourcePath ? 'pi pi-home' : 'pi pi-file', icon: isDirectory ? 'pi pi-folder' : path === defaultSourcePath ? 'pi pi-home' : 'pi pi-file',
label: name, label,
data: path, data: path,
key: path, key: path,
children, children,
selectable: !isDirectory // && (name == 'LICENSE' || name.endsWith('.scad') || name.endsWith('.scad') selectable: !isDirectory
}); });
} }
} }
@ -58,34 +87,26 @@ export default function FilePicker({className, style}: {className?: string, styl
const fs = useContext(FSContext); const fs = useContext(FSContext);
const fsItems = fs && listFilesAsNodes(fs, '/') const fsItems = fs && listFilesAsNodes(fs, '/')
// [
// {
// icon: 'pi pi-home',
// label: 'User files',
// key: '/',
// children: listFilesAsNodes(fs, '/'),//
// // children: listFilesAsNodes(fs, '/', f => f != librariesFolder && !f.startsWith(`${librariesFolder}/`)),
// selectable: false
// },
// {
// icon: 'pi pi-database',
// label: 'Builtin libraries',
// key: '/libraries',
// children: listFilesAsNodes(fs, '/libraries'),
// selectable: false
// },
// ] || [];
return ( return (
<TreeSelect <TreeSelect
className={className} className={className}
title='OpenSCAD Playground Files' title='OpenSCAD Playground Files'
value={state.params.sourcePath} value={state.params.sourcePath}
onChange={(e) => model.openFile(String(e.value))} resetFilterOnHide={true}
// dropdownIcon="pi pi-folder-open" filterBy="key"
onChange={e => {
const key = e.value;
if (typeof key === 'string') {
if (key.startsWith('https://')) {
window.open(key, '_blank')
} else {
model.openFile(key);
}
}
}}
filter filter
style={style} style={style}
// style={{style}}
options={fsItems} /> options={fsItems} />
) )
} }

View file

@ -1,6 +1,6 @@
// Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING. // Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING.
import { zipArchives } from "./zip-archives"; import { deployedArchiveNames, zipArchives } from "./zip-archives";
declare var BrowserFS: BrowserFSInterface declare var BrowserFS: BrowserFSInterface
@ -56,7 +56,7 @@ export async function symlinkLibraries(archiveNames: string[], fs: FS, prefix='/
}; };
await Promise.all(archiveNames.map(n => (async () => { await Promise.all(archiveNames.map(n => (async () => {
if (!(n in zipArchives)) throw new Error(`Archive named ${n} invalid (valid ones: ${Object.keys(zipArchives).join(', ')})`); if (!(n in zipArchives)) throw new Error(`Archive named ${n} invalid (valid ones: ${deployedArchiveNames.join(', ')})`);
const {symlinks} = (zipArchives)[n]; const {symlinks} = (zipArchives)[n];
if (symlinks) { if (symlinks) {
for (const from in symlinks) { for (const from in symlinks) {
@ -87,7 +87,7 @@ function configureAndInstallFS(windowOrSelf: Window, options: any) {
} }
export async function createEditorFS(prefix: string): Promise<FS> { export async function createEditorFS(prefix: string): Promise<FS> {
const archiveNames = Object.keys(zipArchives); const archiveNames = deployedArchiveNames;
const librariesMounts = await getBrowserFSLibrariesMounts(archiveNames); const librariesMounts = await getBrowserFSLibrariesMounts(archiveNames);
const allMounts: FSMounts = {}; const allMounts: FSMounts = {};
for (const n in librariesMounts) { for (const n in librariesMounts) {

View file

@ -4,47 +4,152 @@ import { Symlinks } from "./filesystem";
export type ZipArchives = { export type ZipArchives = {
[name: string]: { [name: string]: {
symlinks?: Symlinks deployed?: boolean,
description?: string,
gitOrigin?: {
repoUrl: string,
branch: string,
include: {
glob: string | string[],
ignore?: string | string[],
replacePrefix?: {[path: string]: string},
}[]
}
symlinks?: Symlinks,
docs?: {[name: string]: string}
} }
}; };
export const zipArchives: ZipArchives = { export const zipArchives: ZipArchives = {
'fonts': {}, 'fonts': {},
// @openscad 'MCAD': {
'MCAD': {}, description: 'OpenSCAD Parametric CAD Library',
// @revarbat gitOrigin: {
'BOSL': {}, branch: 'master',
'BOSL2': { repoUrl: 'https://github.com/openscad/MCAD',
// "includes": { include: [{glob: ['*.scad', 'bitmap/*.scad', 'LICENSE']}],
// "BOSL2/std.scad": "The Belfry OpenScad Library, v2.0. An OpenSCAD library of shapes, masks, and manipulators to make working with OpenSCAD easier. BETA" },
// } },
'BOSL': {
description: 'The Belfry OpenScad Library',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/revarbat/BOSL',
include: [{glob: ['**/*.scad', 'LICENSE']}],
},
},
'BOSL2': {
description: 'The Belfry OpenScad Library, v2.0',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/revarbat/BOSL2',
include: [{glob: ['**/*.scad', 'LICENSE']}],
},
docs: {
'CheatSheet': 'https://github.com/revarbat/BOSL2/wiki/CheatSheet',
'Wiki': 'https://github.com/revarbat/BOSL2/wiki',
},
},
'NopSCADlib': {
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/nophead/NopSCADlib',
include: [{
glob: '**/*.scad',
ignore: 'test/**',
}],
},
},
'FunctionalOpenSCAD': {
description: 'Implementing OpenSCAD in OpenSCAD',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/thehans/FunctionalOpenSCAD',
include: [{glob: ['**/*.scad', 'LICENSE']}],
},
},
'funcutils': {
description: 'OpenSCAD collection of functional programming utilities, making use of function-literals.',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/thehans/funcutils',
include: [{glob: '**/*.scad'}],
},
}, },
// @nophead
'NopSCADlib': {},
// @thehans
'FunctionalOpenSCAD': {},
'funcutils': {},
// @colyer
'smooth-prim': { 'smooth-prim': {
description: 'OpenSCAD smooth primitives library',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/rcolyer/smooth-prim',
include: [{glob: ['**/*.scad', 'LICENSE.txt']}],
},
symlinks: {'smooth_prim.scad': 'smooth_prim.scad'}, symlinks: {'smooth_prim.scad': 'smooth_prim.scad'},
}, },
'closepoints': { 'closepoints': {
description: 'OpenSCAD ClosePoints Library',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/rcolyer/closepoints',
include: [{glob: ['**/*.scad', 'LICENSE.txt']}],
},
symlinks: {'closepoints.scad': 'closepoints.scad'}, symlinks: {'closepoints.scad': 'closepoints.scad'},
}, },
'plot-function': { 'plot-function': {
description: 'OpenSCAD Function Plotting Library',
gitOrigin: {
branch: 'master',
repoUrl: 'https://github.com/colyer/plot-function',
include: [{glob: ['**/*.scad', 'LICENSE.txt']}],
},
symlinks: {'plot_function.scad': 'plot_function.scad'}, symlinks: {'plot_function.scad': 'plot_function.scad'},
}, },
// 'threads': {}, // 'threads': {
// @sofian // deployed: false,
// gitOrigin: {
// branch: 'master',
// repoUrl: 'https://github.com/colyer/threads',
// include: [{glob: ['**/*.scad', 'LICENSE.txt']}],
// },
// },
'openscad-tray': { 'openscad-tray': {
description: 'OpenSCAD library to create rounded rectangular trays with optional subdividers.',
gitOrigin: {
branch: 'main',
repoUrl: 'https://github.com/sofian/openscad-tray',
include: [{glob: ['**/*.scad', 'LICENSE']}],
},
symlinks: {'tray.scad': 'tray.scad'}, symlinks: {'tray.scad': 'tray.scad'},
}, },
// @mrWheel 'YAPP_Box': {
'YAPP_Box': {}, description: 'Yet Another Parametric Projectbox Box',
// @Cantareus gitOrigin: {
'Stemfie_OpenSCAD': {}, branch: 'main',
// @UBaer21 repoUrl: 'https://github.com/mrWheel/YAPP_Box',
include: [{glob: ['**/*.scad', 'LICENSE']}],
},
},
'Stemfie_OpenSCAD': {
description: 'OpenSCAD Stemfie Library',
gitOrigin: {
branch: 'main',
repoUrl: 'https://github.com/Cantareus/Stemfie_OpenSCAD',
include: [{glob: ['**/*.scad', 'LICENSE']}],
},
},
'UB.scad': { 'UB.scad': {
symlinks: {"ub.scad": "libraries/ub.scad"}, gitOrigin: {
branch: 'main',
repoUrl: 'https://github.com/UBaer21/UB.scad',
include: [{glob: ['libraries/*.scad', 'LICENSE', 'examples/UBexamples/*.scad'], replacePrefix: {
'libraries/': '',
'examples/UBexamples/': 'examples/',
}}],
},
symlinks: {"ub.scad": "libraries/ub.scad"}, // TODO change this after the replaces work
}, },
}; };
export const deployedArchiveNames =
Object.entries(zipArchives)
.filter(([_, {deployed}]) => deployed == null || deployed)
.map(([n]) => n);

View file

@ -76,11 +76,13 @@ export async function buildOpenSCADCompletionItemProvider(fs: FS, workingDir: st
const toAbsolutePath = (path: string) => path.startsWith('/') ? path : `${workingDir}/${path}`; const toAbsolutePath = (path: string) => path.startsWith('/') ? path : `${workingDir}/${path}`;
const allSymlinks: Symlinks = {}; const allSymlinks: Symlinks = {};
for (const n of Object.keys(zipArchives)) { for (const [n, {deployed, symlinks}] of Object.entries(zipArchives)) {
if (n == 'fonts') { if (n == 'fonts') {
continue; continue;
} }
const { symlinks } = zipArchives[n]; if (deployed === false) {
continue;
}
for (const s in symlinks) { for (const s in symlinks) {
allSymlinks[s] = `${n}/${symlinks[s]}`; allSymlinks[s] = `${n}/${symlinks[s]}`;
} }