Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
purescript-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
122
Issues
122
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
purescript-gargantext
Commits
1b4913c2
Commit
1b4913c2
authored
Jan 23, 2020
by
Przemyslaw Kaminski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[CodeEditor] first version with saving to corpus endpoint
parent
d3ca60a7
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
180 additions
and
55 deletions
+180
-55
CodeEditor.purs
src/Gargantext/Components/CodeEditor.purs
+6
-5
Corpus.purs
src/Gargantext/Components/Nodes/Corpus.purs
+121
-40
Types.purs
src/Gargantext/Components/Nodes/Corpus/Types.purs
+53
-10
No files found.
src/Gargantext/Components/CodeEditor.purs
View file @
1b4913c2
...
@@ -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
...
...
src/Gargantext/Components/Nodes/Corpus.purs
View file @
1b4913c2
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
Corpus
Hyperdata
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: onClick
Add
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
Corpus
Hyperdata)
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
...
...
src/Gargantext/Components/Nodes/Corpus/Types.purs
View file @
1b4913c2
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
Corpus
Hyperdata =
newtype Hyperdata =
Corpus
Hyperdata
Hyperdata
{
{
fields :: Array
(CorpusField CorpusFieldType)
fields :: Array
FTField
}
}
instance decode
CorpusHyperdata :: DecodeJson Corpus
Hyperdata where
instance decode
Hyperdata :: 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 = Corpus
Field {
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
Corpus
FieldType = 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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment