Skip to content

Commit

Permalink
Added a Data Provider to manage images
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonio171003 committed Sep 4, 2024
1 parent 9e1864a commit 00dbce6
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 7 deletions.
10 changes: 10 additions & 0 deletions spra-play-server/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ dataExplorer {
}
referenceDisplayField = "email"
}

images {
tableName = "images"
primaryKeyField = "image_id"
nonEditableColumns = ["image_id", "created_at"]
canBeDeleted = false
createFilter {
requiredColumns = ["name", "data"]
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package net.wiringbits.spra.ui.web
import net.wiringbits.spra.api.models.AdminGetTables
import net.wiringbits.spra.ui.web.components.{CreateGuesser, EditGuesser, ListGuesser}
import net.wiringbits.spra.ui.web.facades.reactadmin.{Admin, Resource}
import net.wiringbits.spra.ui.web.facades.simpleRestProvider
import net.wiringbits.spra.ui.web.facades.createDataProvider
import net.wiringbits.spra.ui.web.models.DataExplorerSettings
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits.global
import slinky.core.facade.{Hooks, ReactElement}
import slinky.core.{FunctionalComponent, KeyAddingStage}
import slinky.web.html.{div, h1}

import scala.util.{Failure, Success}

object AdminView {
Expand Down Expand Up @@ -52,7 +51,7 @@ object AdminView {
}

div()(
Admin(simpleRestProvider(tablesUrl))(buildResources),
Admin(createDataProvider(tablesUrl))(buildResources),
error.map(h1(_))
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
package net.wiringbits.spra.ui.web.facades

import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport

@js.native
trait DataProvider extends js.Object

@js.native
@JSImport("ra-data-simple-rest", JSImport.Default)
// https://www.npmjs.com/package/ra-data-simple-rest
def simpleRestProvider(url: String): DataProvider = js.native

@js.native
@JSImport("react-admin", "withLifecycleCallbacks")
// https://marmelab.com/react-admin/withLifecycleCallbacks.html
object WithLifecycleCallbacks extends js.Object {
def apply(dataProvider: DataProvider, callbacks: js.Array[js.Object]): DataProvider = js.native
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
package net.wiringbits.spra.ui.web

import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport
import net.wiringbits.spra.ui.web.utils.Images.*
import org.scalajs.dom.File

package object facades {
@js.native
@JSImport("ra-data-simple-rest", JSImport.Default)
def simpleRestProvider(url: String): DataProvider = js.native
def createDataProvider(url: String): DataProvider = {
val baseDataProvider = simpleRestProvider(url)
WithLifecycleCallbacks(
baseDataProvider,
js.Array(
js.Dynamic.literal(
resource = "images",
afterRead = (record: js.Dynamic, dataProvider: js.Any) => {
val hexImage = record.data.asInstanceOf[String]
val urlImage = convertHexToImage(hexImage)
record.updateDynamic("data")(urlImage)
record
},
beforeSave = (data: js.Dynamic, dataProvider: js.Any) => {
val rawFile = data.data.rawFile.asInstanceOf[File]
convertImageToByteArray(rawFile).`then` { value =>
data.updateDynamic("data")(value.asInstanceOf[js.Any])
data
}
}
)
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package net.wiringbits.spra.ui.web.utils

import org.scalajs.dom
import org.scalajs.dom.{Blob, File}
import scala.util.{Failure, Success, Try}
import scala.scalajs.js.Promise
import scala.scalajs.js.typedarray.{ArrayBuffer, Int8Array, Uint8Array}
import scala.scalajs.js

object Images {
def convertImageToByteArray(image: dom.File): js.Promise[String] = {
new js.Promise[String]((resolve, reject) => {
val reader = new dom.FileReader()
reader.onload = { (e: dom.Event) =>
val arrayBuffer = reader.result.asInstanceOf[ArrayBuffer]
val byteArray = new Int8Array(arrayBuffer).toArray
resolve(byteArray.mkString("[", ", ", "]"))
}
reader.onerror = { (e: dom.Event) =>
reject(new js.Error("Failed to read file"))
}
reader.readAsArrayBuffer(image)
})
}

def convertHexToImage(imageHex: String): String = {
// Remove the "0x" prefix from the hex string, as it's not part of the actual image data
val hex = imageHex.tail.tail
val imageBinary: Array[Byte] =
if ((hex.length % 2) == 1)
Array.empty
else
Try(hex.grouped(2).map { hex => Integer.parseInt(hex, 16).toByte }.toArray) match {
case Success(value) => value
case Failure(_) => Array.empty
}
val byteArray = Uint8Array(js.Array(imageBinary.map(_.toShort): _*))
dom.URL.createObjectURL(dom.Blob(js.Array(byteArray.buffer)))
}
}

0 comments on commit 00dbce6

Please sign in to comment.