Commit 1b4913c2 authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[CodeEditor] first version with saving to corpus endpoint

parent d3ca60a7
...@@ -43,9 +43,9 @@ instance showViewType :: Show ViewType where ...@@ -43,9 +43,9 @@ instance showViewType :: Show ViewType where
show = genericShow show = genericShow
type Props = type Props =
( code :: String ( code :: Code
, defaultCodeType :: CodeType , defaultCodeType :: CodeType
, onChange :: String -> Effect Unit , onChange :: Code -> Effect Unit
) )
-- Fixes newlines in code -- Fixes newlines in code
...@@ -114,7 +114,7 @@ codeEditorCpt = R.hooksComponent "G.C.CE.CodeEditor" cpt ...@@ -114,7 +114,7 @@ codeEditorCpt = R.hooksComponent "G.C.CE.CodeEditor" cpt
H.div { className: "code-area " <> (codeHidden $ fst controls.viewType) } [ H.div { className: "code-area " <> (codeHidden $ fst controls.viewType) } [
H.div { className: "code-container" } [ H.div { className: "code-container" } [
H.textarea { defaultValue: code H.textarea { defaultValue: code
, on: { change: onEditChange controls } , on: { change: onEditChange controls onChange }
, placeholder: "Type some code..." , placeholder: "Type some code..."
, ref: controls.codeElRef } [ ] , ref: controls.codeElRef } [ ]
, H.pre { className: (langClass $ fst controls.codeType) , H.pre { className: (langClass $ fst controls.codeType)
...@@ -150,12 +150,13 @@ codeEditorCpt = R.hooksComponent "G.C.CE.CodeEditor" cpt ...@@ -150,12 +150,13 @@ codeEditorCpt = R.hooksComponent "G.C.CE.CodeEditor" cpt
previewHidden Both = "" previewHidden Both = ""
previewHidden _ = " hidden" previewHidden _ = " hidden"
onEditChange :: forall e. Record Controls -> e -> Effect Unit onEditChange :: forall e. Record Controls -> (Code -> Effect Unit) -> e -> Effect Unit
onEditChange controls@{codeElRef, codeOverlayElRef, editorCodeRef} e = do onEditChange controls@{codeElRef, codeOverlayElRef, editorCodeRef} onChange e = do
let code = R2.unsafeEventValue e let code = R2.unsafeEventValue e
R.setRef editorCodeRef code R.setRef editorCodeRef code
setCodeOverlay controls code setCodeOverlay controls code
renderHtml (R.readRef controls.editorCodeRef) controls renderHtml (R.readRef controls.editorCodeRef) controls
onChange code
setCodeOverlay :: Record Controls -> Code -> Effect Unit setCodeOverlay :: Record Controls -> Code -> Effect Unit
setCodeOverlay {codeOverlayElRef, codeType: (codeType /\ _)} code = do setCodeOverlay {codeOverlayElRef, codeType: (codeType /\ _)} code = do
......
module Gargantext.Components.Nodes.Corpus where module Gargantext.Components.Nodes.Corpus where
import Data.Argonaut (class DecodeJson, encodeJson) import Data.Argonaut (class DecodeJson, decodeJson, encodeJson)
import Data.Argonaut.Parser (jsonParser)
import Data.Array as A import Data.Array as A
import Data.Either (Either(..))
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Tuple (fst) import Data.Tuple (Tuple(..), fst)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2) import DOM.Simple.Console (log2)
import Effect.Aff (Aff, throwError) import Effect.Aff (Aff, launchAff_, throwError)
import Effect (Effect)
import Effect.Exception (error) import Effect.Exception (error)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
...@@ -18,7 +21,7 @@ import Gargantext.Components.Node (NodePoly(..), HyperdataList) ...@@ -18,7 +21,7 @@ import Gargantext.Components.Node (NodePoly(..), HyperdataList)
import Gargantext.Components.Nodes.Corpus.Types import Gargantext.Components.Nodes.Corpus.Types
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes (SessionRoute(NodeAPI, Children)) import Gargantext.Routes (SessionRoute(NodeAPI, Children))
import Gargantext.Sessions (Session, get) import Gargantext.Sessions (Session, get, put)
import Gargantext.Types (NodeType(..), AffTableResult) import Gargantext.Types (NodeType(..), AffTableResult)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
...@@ -38,70 +41,148 @@ corpusLayoutCpt = R.hooksComponent "G.C.N.C.corpusLayout" cpt ...@@ -38,70 +41,148 @@ corpusLayoutCpt = R.hooksComponent "G.C.N.C.corpusLayout" cpt
\corpus -> corpusLayoutView {corpus, nodeId, session} \corpus -> corpusLayoutView {corpus, nodeId, session}
type ViewProps = ( type ViewProps = (
corpus :: NodePoly CorpusHyperdata corpus :: NodePoly Hyperdata
| Props | Props
) )
type Index = Int
type FTFieldWithIndex = Tuple Index FTField
corpusLayoutView :: Record ViewProps -> R.Element corpusLayoutView :: Record ViewProps -> R.Element
corpusLayoutView props = R.createElement corpusLayoutViewCpt props [] corpusLayoutView props = R.createElement corpusLayoutViewCpt props []
corpusLayoutViewCpt :: R.Component ViewProps corpusLayoutViewCpt :: R.Component ViewProps
corpusLayoutViewCpt = R.hooksComponent "G.C.N.C.corpusLayoutView" cpt corpusLayoutViewCpt = R.hooksComponent "G.C.N.C.corpusLayoutView" cpt
where where
cpt {corpus: (NodePoly {hyperdata: CorpusHyperdata {fields}}), nodeId, session} _ = do cpt {corpus: (NodePoly {hyperdata: Hyperdata {fields}}), nodeId, session} _ = do
fieldsS <- R.useState' fields let fieldsWithIndex = A.mapWithIndex (\idx -> \t -> Tuple idx t) fields
fieldsS <- R.useState' fieldsWithIndex
pure $ H.div {} [ pure $ H.div {} [
H.div {} (corpusFieldCodeEditor {nodeId, session} <$> (fst fieldsS)) H.div { className: "row" } [
H.div { className: "btn btn-default " <> (saveEnabled fieldsWithIndex fieldsS)
, on: { click: onClickSave {fields: fieldsS, nodeId, session} }
} [
H.span { className: "glyphicon glyphicon-save" } [ ]
]
]
, H.div {} [ fieldsCodeEditor {nodeId, session, fields: fieldsS} ]
, H.div { className: "row" } [ , H.div { className: "row" } [
H.div { className: "btn btn-default" H.div { className: "btn btn-default"
, on: { click: onClick fieldsS } , on: { click: onClickAdd fieldsS }
} [ } [
H.span { className: "glyphicon glyphicon-plus" } [ ] H.span { className: "glyphicon glyphicon-plus" } [ ]
] ]
] ]
] ]
--H.iframe { src: gargMd , width: "100%", height: "100%", style: {"border-style": "none"}} []
--gargMd = "https://hackmd.iscpif.fr/g9Aah4iwQtCayIzsKQjA0Q#" saveEnabled :: Array FTFieldWithIndex -> R.State (Array FTFieldWithIndex) -> String
onClick (_ /\ setFieldsS) _ = do saveEnabled fs (fsS /\ _) = if fs == fsS then "disabled" else "enabled"
setFieldsS $ \fieldsS -> A.snoc fieldsS $ CorpusField {
name: "New file" onClickSave :: forall e. { fields :: R.State (Array FTFieldWithIndex)
, typ: Markdown { , nodeId :: Int
tag: "MarkdownField" , session :: Session } -> e -> Effect Unit
, text: "# New file" onClickSave {fields: (fieldsS /\ _), nodeId, session} _ = do
} log2 "[corpusLayoutViewCpt] onClickSave fieldsS" fieldsS
} launchAff_ do
saveCorpus $ { hyperdata: Hyperdata {fields: (\(Tuple _ f) -> f) <$> fieldsS}
corpusFieldCodeEditor :: Record LoadProps -> CorpusField CorpusFieldType -> R.Element , nodeId
corpusFieldCodeEditor p (CorpusField {name, typ}) = , session }
H.div { className: "row panel panel-default" } [
H.div { className: "panel-heading" } [ H.text name ] onClickAdd :: forall e. R.State (Array FTFieldWithIndex) -> e -> Effect Unit
, H.div { className: "panel-body" } [ onClickAdd (_ /\ setFieldsS) _ = do
corpusFieldCodeEditor' typ setFieldsS $ \fieldsS -> A.snoc fieldsS $ Tuple (A.length fieldsS) defaultField
]
] type FieldsCodeEditorProps =
(
corpusFieldCodeEditor' :: CorpusFieldType -> R.Element fields :: R.State (Array FTFieldWithIndex)
corpusFieldCodeEditor' (Markdown {text}) = | LoadProps
CE.codeEditor {code: text, defaultCodeType: CE.Markdown, onChange} )
fieldsCodeEditor :: Record FieldsCodeEditorProps -> R.Element
fieldsCodeEditor props = R.createElement fieldsCodeEditorCpt props []
fieldsCodeEditorCpt :: R.Component FieldsCodeEditorProps
fieldsCodeEditorCpt = R.hooksComponent "G.C.N.C.fieldsCodeEditorCpt" cpt
where
cpt {nodeId, fields: fS@(fields /\ setFields), session} _ = do
pure $ H.div {} $
(\(Tuple idx field) ->
fieldCodeEditorWrapper { field
, onChange: onChange fS idx
}) <$> fields
onChange :: R.State (Array FTFieldWithIndex) -> Index -> FieldType -> Effect Unit
onChange (_ /\ setFields) idx typ = do
log2 "[fieldsCodeEditorCpt] onChange" typ
setFields $ \fields ->
case A.modifyAt idx (\(Tuple _ (Field f)) -> Tuple idx (Field $ f { typ = typ })) fields of
Nothing -> fields
Just newFields -> newFields
type FieldCodeEditorProps =
(
field :: FTField
, onChange :: FieldType -> Effect Unit
)
fieldCodeEditorWrapper :: Record FieldCodeEditorProps -> R.Element
fieldCodeEditorWrapper props = R.createElement fieldCodeEditorWrapperCpt props []
fieldCodeEditorWrapperCpt :: R.Component FieldCodeEditorProps
fieldCodeEditorWrapperCpt = R.hooksComponent "G.C.N.C.fieldCodeEditorWrapperCpt" cpt
where where
onChange c = do cpt props@{field: Field {name, typ}} _ = do
log2 "[corpusFieldCodeEditor'] Markdown c" c pure $ H.div { className: "row panel panel-default" } [
corpusFieldCodeEditor' (JSON j) = do H.div { className: "panel-heading" } [ H.text name ]
CE.codeEditor {code, defaultCodeType: CE.JSON, onChange} , H.div { className: "panel-body" } [
fieldCodeEditor props
]
]
fieldCodeEditor :: Record FieldCodeEditorProps -> R.Element
fieldCodeEditor props = R.createElement fieldCodeEditorCpt props []
fieldCodeEditorCpt :: R.Component FieldCodeEditorProps
fieldCodeEditorCpt = R.hooksComponent "G.C.N.C.fieldCodeEditorCpt" cpt
where where
code = R2.stringify (encodeJson j) 2 cpt {field: Field {typ: Markdown md@{text}}, onChange} _ = do
onChange c = do pure $ CE.codeEditor {code: text, defaultCodeType: CE.Markdown, onChange: onChange'}
log2 "[corpusFieldCodeEditor'] JSON c" c where
onChange' :: CE.Code -> Effect Unit
onChange' c = do
log2 "[fieldCodeEditor'] Markdown c" c
onChange $ Markdown $ md { text = c }
cpt {field: Field {typ: JSON j}, onChange} _ = do
pure $ CE.codeEditor {code, defaultCodeType: CE.JSON, onChange: onChange'}
where
code = R2.stringify (encodeJson j) 2
onChange' :: CE.Code -> Effect Unit
onChange' c = do
log2 "[fieldCodeEditor'] JSON c" c
case jsonParser c of
Left err -> log2 "[fieldCodeEditor'] cannot parse json" c
Right j' -> case decodeJson j' of
Left err -> log2 "[fieldCodeEditor'] cannot decode json" j'
Right j'' -> onChange $ JSON j''
type LoadProps = ( type LoadProps = (
nodeId :: Int nodeId :: Int
, session :: Session , session :: Session
) )
loadCorpus' :: Record LoadProps -> Aff (NodePoly CorpusHyperdata) loadCorpus' :: Record LoadProps -> Aff (NodePoly Hyperdata)
loadCorpus' {nodeId, session} = get session $ NodeAPI Corpus (Just nodeId) "" loadCorpus' {nodeId, session} = get session $ NodeAPI Corpus (Just nodeId) ""
type SaveProps = (
hyperdata :: Hyperdata
| LoadProps
)
saveCorpus :: Record SaveProps -> Aff Unit
saveCorpus {hyperdata, nodeId, session} = put session (NodeAPI Corpus (Just nodeId) "") hyperdata
loadCorpus :: Record LoadProps -> Aff CorpusData loadCorpus :: Record LoadProps -> Aff CorpusData
loadCorpus {nodeId, session} = do loadCorpus {nodeId, session} = do
-- fetch corpus via lists parentId -- fetch corpus via lists parentId
......
module Gargantext.Components.Nodes.Corpus.Types where module Gargantext.Components.Nodes.Corpus.Types where
import Data.Argonaut (class DecodeJson, decodeJson, (.:), (.:?)) import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, (.:), (.:?), (:=), (~>), jsonEmptyObject)
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq)
import Data.Maybe (Maybe) import Data.Maybe (Maybe)
import Gargantext.Prelude import Gargantext.Prelude
...@@ -15,23 +17,31 @@ type Tag = String ...@@ -15,23 +17,31 @@ type Tag = String
type Title = String type Title = String
type MarkdownText = String type MarkdownText = String
newtype CorpusHyperdata = newtype Hyperdata =
CorpusHyperdata Hyperdata
{ {
fields :: Array (CorpusField CorpusFieldType) fields :: Array FTField
} }
instance decodeCorpusHyperdata :: DecodeJson CorpusHyperdata where instance decodeHyperdata :: DecodeJson Hyperdata where
decodeJson json = do decodeJson json = do
obj <- decodeJson json obj <- decodeJson json
fields <- obj .: "fields" fields <- obj .: "fields"
pure $ CorpusHyperdata {fields} pure $ Hyperdata {fields}
instance encodeHyperdata :: EncodeJson Hyperdata where
encodeJson (Hyperdata {fields}) = do
"fields" := fields
~> jsonEmptyObject
newtype CorpusField a = CorpusField { newtype Field a = Field {
name :: String name :: String
, typ :: a , typ :: a
} }
type FTField = Field FieldType
derive instance genericFTField :: Generic (Field FieldType) _
instance eqFTField :: Eq (Field FieldType) where
eq = genericEq
data CorpusFieldType = JSON { data FieldType = JSON {
authors :: Author authors :: Author
, desc :: Description , desc :: Description
, query :: Query , query :: Query
...@@ -42,7 +52,10 @@ data CorpusFieldType = JSON { ...@@ -42,7 +52,10 @@ data CorpusFieldType = JSON {
tag :: Tag tag :: Tag
, text :: MarkdownText , text :: MarkdownText
} }
instance decodeCorpusField :: DecodeJson (CorpusField CorpusFieldType) where derive instance genericFieldType :: Generic FieldType _
instance eqFieldType :: Eq FieldType where
eq = genericEq
instance decodeFTField :: DecodeJson (Field FieldType) where
decodeJson json = do decodeJson json = do
obj <- decodeJson json obj <- decodeJson json
name <- obj .: "name" name <- obj .: "name"
...@@ -61,7 +74,37 @@ instance decodeCorpusField :: DecodeJson (CorpusField CorpusFieldType) where ...@@ -61,7 +74,37 @@ instance decodeCorpusField :: DecodeJson (CorpusField CorpusFieldType) where
text <- data_ .: "text" text <- data_ .: "text"
pure $ Markdown {tag, text} pure $ Markdown {tag, text}
_ -> Left $ "Unsupported 'type' " <> type_ _ -> Left $ "Unsupported 'type' " <> type_
pure $ CorpusField {name, typ} pure $ Field {name, typ}
instance encodeFTField :: EncodeJson (Field FieldType) where
encodeJson (Field {name, typ}) =
"data" := typ
~> "name" := name
~> "type" := typ' typ
~> jsonEmptyObject
where
typ' (JSON _) = "JSON"
typ' (Markdown _) = "Markdown"
instance encodeFieldType :: EncodeJson FieldType where
encodeJson (JSON {authors, desc, query, tag, title}) =
"authors" := authors
~> "desc" := desc
~> "query" := query
~> "tag" := "JsonField"
~> "title" := title
~> jsonEmptyObject
encodeJson (Markdown {text}) =
"tag" := "MarkdownField"
~> "text" := text
~> jsonEmptyObject
defaultField :: FTField
defaultField = Field {
name: "New file"
, typ: Markdown {
tag: "MarkdownField"
, text: "# New file"
}
}
newtype CorpusInfo = newtype CorpusInfo =
CorpusInfo CorpusInfo
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment