open and dynamic load app
This commit is contained in:
parent
671bfd65bc
commit
91cd53c147
1
go.mod
1
go.mod
@ -12,6 +12,7 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
||||||
github.com/goccy/go-json v0.10.0 // indirect
|
github.com/goccy/go-json v0.10.0 // indirect
|
||||||
|
github.com/google/uuid v1.3.0
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -21,6 +21,8 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
|
|||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="WindowsLayer"></div>
|
<div id="WindowsLayer"></div>
|
||||||
|
<div id="Applications"></div>
|
||||||
<!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" >
|
<!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" >
|
||||||
<div id="TestWindowHeader" class="WindowDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;">
|
<div id="TestWindowHeader" class="WindowDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;">
|
||||||
</div> -->
|
</div> -->
|
||||||
|
@ -1,27 +1,22 @@
|
|||||||
class Finder{
|
class Finder{
|
||||||
appId = "finder"
|
appId = "finder"
|
||||||
/**
|
constructor(){
|
||||||
* @param {HTMLElement} appElem
|
// this.appElem = appElem
|
||||||
*/
|
|
||||||
constructor(appElem){
|
|
||||||
this.appElem = appElem
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
*/
|
*/
|
||||||
NewWindow(path){
|
NewWindow(path){
|
||||||
console.log("Init")
|
// console.log("Init")
|
||||||
fetch(`${window.location.origin}/application/${this.appId}/render`) //TODO Move to wde func. Or Not?
|
fetch(`${window.location.origin}/application/${this.appId}/render`) //TODO Move to wde func. Or Not?
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, "Personal Properties", 500, 400 )
|
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 500, 350 )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
newWindow.innerHTML = html
|
newWindow.innerHTML = html
|
||||||
console.log(newWindow.children[1].children[0])
|
// console.log(newWindow.children[1].children[0])
|
||||||
let fileView = new FileView("/kek", newWindow.children[1].children[0])
|
let fileView = new FileView("/kek", newWindow.children[1].children[0], this.click)
|
||||||
let scrollBar = new WdeScrollBar(newWindow.children[1].children[1], newWindow.children[1].children[0])
|
let scrollBar = new WdeScrollBar(newWindow.children[1].children[1], newWindow.children[1].children[0])
|
||||||
|
|
||||||
let closeButton = newWindow.children[0].children[0]
|
let closeButton = newWindow.children[0].children[0]
|
||||||
@ -32,8 +27,21 @@ class Finder{
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
WebDesktopEnvironment.Alert(error);
|
WebDesktopEnvironment.Alert(error);
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {MouseEvent} event
|
||||||
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
click(event, path){
|
||||||
|
let fileName = event.target.getAttribute("fileName")
|
||||||
|
let fileExtension = fileName.split(".")[fileName.split(".").length - 1]
|
||||||
|
switch (fileExtension) {
|
||||||
|
case "lol":
|
||||||
|
WebDesktopEnvironment.Open("finder", ["pizda"])
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("Unsupported file type")
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
// const simpleScrollbar = require("../wde/simple-scrollbar");
|
|
||||||
|
|
||||||
|
|
||||||
class PersonalProperties{
|
class PersonalProperties{
|
||||||
appId = "personal-properties"
|
appId = "personal-properties"
|
||||||
/**
|
/**
|
||||||
@ -10,14 +7,16 @@ class PersonalProperties{
|
|||||||
this.appElem = appElem
|
this.appElem = appElem
|
||||||
}
|
}
|
||||||
|
|
||||||
Init(){
|
/**
|
||||||
console.log("Init")
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
NewWindow(path){
|
||||||
fetch(`${window.location.origin}/application/personal-properties/render`) //TODO Move to wde func. Or Not?
|
fetch(`${window.location.origin}/application/personal-properties/render`) //TODO Move to wde func. Or Not?
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
// console.log(document.body)
|
// console.log(document.body)
|
||||||
// let heigth = Math.max(document.body.clientHeight*0.8, scrollDiv.children[0].scrollHeight) //TODO
|
// let heigth = Math.max(document.body.clientHeight*0.8, scrollDiv.children[0].scrollHeight) //TODO
|
||||||
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, "Personal Properties", 360, document.body.clientHeight*0.8 )
|
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 360, document.body.clientHeight*0.8 )
|
||||||
|
|
||||||
newWindow.innerHTML = html
|
newWindow.innerHTML = html
|
||||||
|
|
||||||
@ -33,4 +32,33 @@ class PersonalProperties{
|
|||||||
WebDesktopEnvironment.Alert(error);
|
WebDesktopEnvironment.Alert(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Init(){
|
||||||
|
// console.log("Init")
|
||||||
|
// fetch(`${window.location.origin}/application/personal-properties/render`) //TODO Move to wde func. Or Not?
|
||||||
|
// .then((response) => response.text())
|
||||||
|
// .then((html) => {
|
||||||
|
// // console.log(document.body)
|
||||||
|
// // let heigth = Math.max(document.body.clientHeight*0.8, scrollDiv.children[0].scrollHeight) //TODO
|
||||||
|
// let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, "Personal Properties", 360, document.body.clientHeight*0.8 )
|
||||||
|
|
||||||
|
// newWindow.innerHTML = html
|
||||||
|
|
||||||
|
// let closeButton = newWindow.children[0].children[0]
|
||||||
|
// let scrollDiv = newWindow.children[1]
|
||||||
|
// let scrollBar = new WdeScrollBar(scrollDiv.children[1].children[0], scrollDiv.children[0])
|
||||||
|
|
||||||
|
// closeButton.addEventListener('click', function (params) {
|
||||||
|
// WebDesktopEnvironment.CloseWindow(newWindow)
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// .catch((error) => {
|
||||||
|
// WebDesktopEnvironment.Alert(error);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class test{
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -3,8 +3,10 @@ class FileView{
|
|||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @param {HTMLElement} fileViewElem
|
* @param {HTMLElement} fileViewElem
|
||||||
|
* @param {Function} clickCallback
|
||||||
*/
|
*/
|
||||||
constructor(path, fileViewElem){
|
constructor(path, fileViewElem, clickCallback){
|
||||||
|
//TODO check all params
|
||||||
this.path = path
|
this.path = path
|
||||||
|
|
||||||
this.openFolder(path, fileViewElem)
|
this.openFolder(path, fileViewElem)
|
||||||
@ -14,23 +16,16 @@ class FileView{
|
|||||||
// let scrollBar = new WdeScrollBar(fileViewElem.children[1].children[0], fileViewElem.children[0])
|
// let scrollBar = new WdeScrollBar(fileViewElem.children[1].children[0], fileViewElem.children[0])
|
||||||
|
|
||||||
fileViewElem.addEventListener('click', (event) => {
|
fileViewElem.addEventListener('click', (event) => {
|
||||||
this.click(event)
|
clickCallback(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {event} event
|
|
||||||
*/
|
|
||||||
click(){
|
|
||||||
console.log(event.target)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get html of folder by path
|
/** Get html of folder by path
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @param {HTMLElement} parentElem
|
* @param {HTMLElement} parentElem
|
||||||
*/
|
*/
|
||||||
openFolder(path, parentElem){
|
openFolder(path, parentElem){
|
||||||
console.log(`${window.location.origin}/system/wde/widgets/file-tile-view?path=${path}`)
|
// console.log(`${window.location.origin}/system/wde/widgets/file-tile-view?path=${path}`)
|
||||||
fetch(`${window.location.origin}/system/wde/widgets/file-tile-view?path=${path}`) //TODO Move to wde func. Or Not?
|
fetch(`${window.location.origin}/system/wde/widgets/file-tile-view?path=${path}`) //TODO Move to wde func. Or Not?
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
|
@ -5,7 +5,7 @@ class WdeScrollBar{
|
|||||||
*/
|
*/
|
||||||
constructor(scrollBarContainer, content){
|
constructor(scrollBarContainer, content){
|
||||||
let nonNativeScroll = false
|
let nonNativeScroll = false
|
||||||
console.log(scrollBarContainer)
|
// console.log(scrollBarContainer)
|
||||||
let handler = scrollBarContainer.children[0]
|
let handler = scrollBarContainer.children[0]
|
||||||
|
|
||||||
handler.style.height = (content.clientHeight /content.scrollHeight)* handler.parentElement.clientHeight + 'px'
|
handler.style.height = (content.clientHeight /content.scrollHeight)* handler.parentElement.clientHeight + 'px'
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
wde = new WebDesktopEnvironment
|
wde = new WebDesktopEnvironment
|
||||||
|
WebDesktopEnvironment.Open("finder")
|
||||||
|
// WebDesktopEnvironment.Open("personal-properties")
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
class WebDesktopEnvironment{
|
class WebDesktopEnvironment{
|
||||||
|
static Applications = {};
|
||||||
constructor(){
|
constructor(){
|
||||||
// console.log(window)
|
|
||||||
this.wc = new WindowsCompositor
|
this.wc = new WindowsCompositor
|
||||||
|
|
||||||
//Get basic window ready frame
|
//Get basic window ready frame
|
||||||
fetch(`${window.location.origin}/system/wde/getbasicwindow`) //TODO Move to wde func
|
fetch(`${window.location.origin}/system/wde/getbasicwindow`) //TODO Move to wde func
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
WebDesktopEnvironment.SetBasicWindow(html)
|
WebDesktopEnvironment.SetBasicWindow(html)
|
||||||
// let app = this.loadApp("personal-properties")
|
|
||||||
let finder = this.loadApp("finder")
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
WebDesktopEnvironment.Alert(error);
|
WebDesktopEnvironment.Alert(error);
|
||||||
@ -22,42 +21,67 @@ class WebDesktopEnvironment{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} appId
|
* @param {string} appId
|
||||||
|
* @param {function} func callback after script loading
|
||||||
* @returns {Application | undefined}
|
* @returns {Application | undefined}
|
||||||
*/
|
*/
|
||||||
loadApp(appId){
|
static LoadApp(appId, func){
|
||||||
let newApp = document.createElement("application")
|
console.log(`Load application ${appId}`)
|
||||||
newApp.setAttribute("id", `application-${appId}`)
|
|
||||||
|
|
||||||
let appElem = document.getElementById("WindowsLayer").appendChild(newApp)
|
|
||||||
|
|
||||||
|
let appDiv = document.createElement("application")
|
||||||
|
appDiv.setAttribute("id", `application-${appId}`)
|
||||||
|
document.getElementById("WindowsLayer").appendChild(appDiv)
|
||||||
|
|
||||||
let script = document.createElement("script")
|
let script = document.createElement("script")
|
||||||
|
script.setAttribute("id", `application-script-${appId}`)
|
||||||
script.setAttribute("src", `${window.location.origin}/system/applications/${appId}/app.js`)
|
script.setAttribute("src", `${window.location.origin}/system/applications/${appId}/app.js`)
|
||||||
script.setAttribute("async", "false")
|
script.setAttribute("async", "false")
|
||||||
appElem.appendChild(script)
|
let appElem = document.getElementById("Applications").appendChild(script)
|
||||||
script.addEventListener("load", function () {
|
|
||||||
newApp
|
script.addEventListener('load', (event) =>{
|
||||||
switch (appId) {
|
switch (appId) {
|
||||||
case "finder":
|
case "finder":
|
||||||
let newApp = new Finder(appElem)
|
let newFinderApp = new Finder()
|
||||||
newApp.NewWindow()
|
this.Applications[appId] = newFinderApp
|
||||||
break;
|
func()
|
||||||
|
return newFinderApp
|
||||||
|
case "personal-properties":
|
||||||
|
let newPersonalPropertiesApp = new PersonalProperties()
|
||||||
|
this.Applications[appId] = newPersonalPropertiesApp
|
||||||
|
func()
|
||||||
|
return newPersonalPropertiesApp
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}, false)
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} appId
|
||||||
|
* @param {string[]} args
|
||||||
|
*/
|
||||||
|
static Open(appId, args){
|
||||||
|
if (this.Applications[appId] == undefined){
|
||||||
|
console.log(`Application ${appId} is not loaded yet`)
|
||||||
|
WebDesktopEnvironment.LoadApp(appId, () =>{
|
||||||
|
this.Applications[appId].NewWindow(args)
|
||||||
|
// console.log(this.Applications)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.Applications[appId].NewWindow(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} appId
|
* @param {string} appId
|
||||||
* @param {string} windowName
|
|
||||||
* @param {number} width
|
* @param {number} width
|
||||||
* @param {number} height
|
* @param {number} height
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
static CreateNewWindow(appId, windowName, width, height) {
|
static CreateNewWindow(appId, width, height) {
|
||||||
let appElem = document.getElementById(`application-${appId}`)
|
let appElem = document.getElementById(`application-${appId}`)
|
||||||
let newWindow = document.createElement("div")
|
let newWindow = document.createElement("div")
|
||||||
newWindow.setAttribute("class", "StandartApplicationWindow")
|
newWindow.setAttribute("class", "StandartApplicationWindow")
|
||||||
@ -74,19 +98,19 @@ class WebDesktopEnvironment{
|
|||||||
let app = window.parentElement
|
let app = window.parentElement
|
||||||
window.remove()
|
window.remove()
|
||||||
// console.log(app.childElementCount)
|
// console.log(app.childElementCount)
|
||||||
if (app.childElementCount < 2){
|
// if (app.childElementCount < 2){
|
||||||
console.log(app)
|
// console.log(app)
|
||||||
app.remove()
|
// app.remove()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
static basicWindow
|
|
||||||
/**
|
/**
|
||||||
* @param {string} html
|
* @param {string} html
|
||||||
*/
|
*/
|
||||||
static SetBasicWindow(html){
|
static SetBasicWindow(html){
|
||||||
this.basicWindow = html
|
this.basicWindow = html
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
@ -96,13 +120,11 @@ class WebDesktopEnvironment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @param {string} alertText
|
* @param {string} alertText
|
||||||
*/
|
*/
|
||||||
static Alert(alertText){
|
static Alert(alertText){
|
||||||
console.log(alertText)
|
console.log(alertText)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var getJSON = function(url, callback) {
|
var getJSON = function(url, callback) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="WindowsLayer"></div>
|
<div id="WindowsLayer"></div>
|
||||||
|
<div id="Applications"></div>
|
||||||
<!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" >
|
<!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" >
|
||||||
<div id="TestWindowHeader" class="WindowDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;">
|
<div id="TestWindowHeader" class="WindowDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;">
|
||||||
</div> -->
|
</div> -->
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{ define "wde-widgets/file-tile-view.tmpl" }}
|
{{ define "wde-widgets/file-tile-view.tmpl" }}
|
||||||
{{ range $fileTile := .Files }}
|
{{ range $fileTile := .Files }}
|
||||||
<div class="FileTile">
|
<div id="{{ $fileTile.Id }}" class="FileTile" fileName="{{$fileTile.FileName}}">
|
||||||
<div class="FileTileIcon NoClick"></div>
|
<div class="FileTileIcon NoClick"></div>
|
||||||
<div class="FileTileTitle NoClick">{{ $fileTile.FileName }}</div>
|
<div class="FileTileTitle NoClick">{{ $fileTile.FileName }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package webfilesystem
|
package webfilesystem
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
type WebFileSystem struct {
|
type WebFileSystem struct {
|
||||||
folders []*Folder
|
folders []*Folder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *WebFileSystem) List() []*File {
|
func (fs *WebFileSystem) List() []*File {
|
||||||
return []*File{{"Kek.kek"}, {"lel.lol"}, {"pretty.blog"}, {"ofiget.html"}, {"Kek.kek"}, {"lel.lol"}, {"pretty.blog"}, {"ofiget.html"}, {"Kek.kek"}, {"lel.lol"}, {"pretty.blog"}, {"ofiget.html"}, {"Kek.kek"}, {"lel.lol"}, {"pretty.blog"}, {"ofiget.html"}}
|
return []*File{{uuid.NewString(), "Kek.kek"}, {uuid.NewString(), "lel.lol"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Folder struct {
|
type Folder struct {
|
||||||
@ -13,5 +15,6 @@ type Folder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
|
Id string
|
||||||
FileName string
|
FileName string
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user