import Head from 'next/head' import { useState, useEffect, useRef } from 'react' import { saveAs } from 'file-saver'; import CreatableSelect from 'react-select/creatable'; import Select from 'react-select'; import { useRouter } from 'next/router' import allworkspaces from '../../../public/list.json' export async function getStaticPaths() { let paths = allworkspaces.workspaces.map(workspace => ({ params: { workspace: [btoa(workspace.name)] } })) paths.push({ params: { workspace: null } }) return { paths, fallback: false, // can also be true or 'blocking' } } // `getStaticPaths` requires using `getStaticProps` export async function getStaticProps({ params }) { const workspace = params.workspace return { // Passed to the page component as props props: { workspace: workspace ?? null }, } } export default function New({ workspace }) { const name = useRef(null); const friendly_name = useRef(null); const description = useRef(null); const [categories, setCategories] = useState(null) const [architecture, setArchitecture] = useState(null) const [icon, setIcon] = useState(null) const [ext, setExt] = useState('png') const [inlineImage, setInlineImage] = useState(null) const defaultState = { friendly_name: null, image_src: null, description: null, name: null, cores: 2, memory: 2768, gpu_count: 0, cpu_allocation_method: "Inherit", docker_registry: "https://index.docker.io/v1/", categories: [], require_gpu: false, enabled: true, image_type: 'Container', } const [combined, setCombined] = useState(defaultState) const router = useRouter() // const { workspace } = router.query useEffect(() => { if(workspace === null) { description.current.value = '' name.current.value = '' friendly_name.current.value = '' setCategories(null) setArchitecture(null) setIcon(null) setCombined(defaultState) } else if (workspace && workspace[0]) { const workspaceDetails = allworkspaces.workspaces.find(el => el.name === atob(workspace[0])) delete workspaceDetails['sha'] description.current.value = workspaceDetails.description name.current.value = workspaceDetails.name friendly_name.current.value = workspaceDetails.friendly_name if (workspaceDetails.categories) { let catMap = [] workspaceDetails.categories.map((e) => catMap.push({ label: e, value: e, })) setCategories(catMap) } if (workspaceDetails.architecture) { let archMap = [] workspaceDetails.architecture.map((e) => archMap.push({ label: e, value: e, })) setArchitecture(archMap) } setInlineImage('../../icons/' + workspaceDetails.image_src) setCombined({ ...combined, ...workspaceDetails }) } }, [workspace]) const displayWorkspace = () => { return { ...combined, // categories: JSON.stringify(combined.categories) } } const customStyles = { control: (base, state) => ({ ...base, background: "#f1f5f9", borderRadius: '0.5rem', borderColor: "#94a3b8" }), multiValue: (styles, { data }) => { return { ...styles, backgroundColor: '#dde6f1', }; } } useEffect(() => { if (combined && combined.friendly_name) { const updateWorkspace = { ...combined } updateWorkspace.image_src = friendlyUrl(updateWorkspace.friendly_name) + '.' + ext setCombined(updateWorkspace) } }, [ext]) const updateCategories = (items) => { const updateWorkspace = { ...combined } updateWorkspace.categories = items.map(cat => cat.value) setCombined(updateWorkspace) let catMap = [] updateWorkspace.categories.map((e) => catMap.push({ label: e, value: e, })) setCategories(catMap) } const updateArchitecture = (items) => { const updateWorkspace = { ...combined } updateWorkspace.architecture = items.map(arch => arch.value) setCombined(updateWorkspace) let archMap = [] updateWorkspace.architecture.map((e) => archMap.push({ label: e, value: e, })) setArchitecture(archMap) } function friendlyUrl(url) { // make the url lowercase var encodedUrl = url.toString().toLowerCase(); // replace & with and encodedUrl = encodedUrl.split(/\&+/).join("-and-") // remove invalid characters encodedUrl = encodedUrl.split(/[^a-z0-9]/).join("-"); // remove duplicates encodedUrl = encodedUrl.split(/-+/).join("-"); // trim leading & trailing characters encodedUrl = encodedUrl.trim('-'); return encodedUrl; } const downloadZip = () => { var JSZip = require("jszip"); const zip = new JSZip() const folder = zip.folder(combined.friendly_name) folder.file('workspace.json', JSON.stringify(combined, null, 2)) if (icon) { folder.file(combined.image_src, icon.file) } else if (inlineImage) { const promise = fetch(inlineImage).then(response => response.blob()) folder.file(combined.image_src, promise) } zip.generateAsync({ type: "blob" }) .then(function (content) { // Force down of the Zip file saveAs(content, friendlyUrl(combined.friendly_name) + '.zip'); }); } const handleChange = (event) => { const updateWorkspace = { ...combined } updateWorkspace[event.target.name] = event.target.value if (event.target.name === 'icon') { delete updateWorkspace.icon setIcon({ value: event.target.value, file: event.target.files[0] }) setExt(event.target.value.substr(event.target.value.lastIndexOf('.') + 1)) setInlineImage(null) // return } if (updateWorkspace.friendly_name) { updateWorkspace.image_src = friendlyUrl(updateWorkspace.friendly_name) + '.' + ext } setCombined(updateWorkspace) } const options = [ { value: 'Browser', label: 'Browser' }, { value: 'Communication', label: 'Communication' }, { value: 'Desktop', label: 'Desktop' }, { value: 'Development', label: 'Development' }, { value: 'Games', label: 'Games' }, { value: 'Multimedia', label: 'Multimedia' }, { value: 'Office', label: 'Office' }, { value: 'Privacy', label: 'Privacy' }, { value: 'Productivity', label: 'Productivity' }, { value: 'Remote Access', label: 'Remote Access' } ] return (
Kasm Workspaces

Add Workspace

This page is designed to allow admins to generate the JSON they need to upload to the "workspaces" directory. It also allows end users to see what settings are needed if they want to manually copy them into a new workspace.

Select the image to use, image will be renamed when it's downloaded.

This is the name that will show for users

You can select from the available option or create new ones.

A short description about the workspace

The docker image to use, i.e. kasmweb/filezilla:develop