Skip to content

Commit

Permalink
Merge pull request #470 from digitallyinduced/data-editor-tweaks
Browse files Browse the repository at this point in the history
Data editor tweaks
  • Loading branch information
mpscholten authored Oct 18, 2020
2 parents 14d15cc + af15673 commit 49816c2
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 41 deletions.
17 changes: 11 additions & 6 deletions IHP/IDE/Data/Controller.hs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ instance Controller DataController where
tableNames <- fetchTableNames connection
let tableName = param "tableName"
tableCols <- fetchTableCols connection tableName
let values :: [Text] = map (\col -> quoteIfLiteral (param @Bool (cs (get #columnName col) <> "_")) (param @Text (cs (get #columnName col)))) tableCols
let values :: [Text] = map (\col -> parseValues (param @Bool (cs (get #columnName col) <> "_")) (param @Bool (cs (get #columnName col) <> "-isBoolean")) (param @Text (cs (get #columnName col)))) tableCols
let query = "INSERT INTO " <> tableName <> " VALUES (" <> intercalate "," values <> ")"
PG.execute_ connection (PG.Query . cs $! query)
PG.close connection
Expand All @@ -100,7 +100,7 @@ instance Controller DataController where
tableCols <- fetchTableCols connection tableName
primaryKeyFields <- tablePrimaryKeyFields connection tableName

let values :: [Text] = map (\col -> quoteIfLiteral (param @Bool (cs (get #columnName col) <> "_")) (param @Text (cs (get #columnName col)))) tableCols
let values :: [Text] = map (\col -> parseValues (param @Bool (cs (get #columnName col) <> "_")) (param @Bool (cs (get #columnName col) <> "-isBoolean")) (param @Text (cs (get #columnName col)))) tableCols
let columns :: [Text] = map (\col -> cs (get #columnName col)) tableCols
let primaryKeyValues = map (\pkey -> "'" <> (param @Text (cs pkey <> "-pk")) <> "'") primaryKeyFields

Expand Down Expand Up @@ -139,7 +139,7 @@ instance Controller DataController where
connection <- connectToAppDb
let targetCol = param "targetName"
let targetValue = param "targetValue"
let query = "UPDATE " <> tableName <> " SET " <> targetCol <> " = '" <> targetValue <> "' WHERE id = " <> cs id
let query = "UPDATE " <> tableName <> " SET " <> targetCol <> " = '" <> targetValue <> "' WHERE id = '" <> cs id <> "'"
PG.execute_ connection (PG.Query . cs $! query)
PG.close connection
redirectTo ShowTableRowsAction { .. }
Expand Down Expand Up @@ -185,8 +185,13 @@ fetchRows connection tableName = do
PG.query_ connection (PG.Query . cs $! query)
quoteIfLiteral :: Bool -> Text -> Text
quoteIfLiteral False text = "'" <> text <> "'"
quoteIfLiteral True text = text
-- parseValues sqlMode isBoolField input
parseValues :: Bool -> Bool -> Text -> Text
parseValues _ True "on" = "true"
parseValues _ True "off" = "false"
parseValues False False text = "'" <> text <> "'"
parseValues True False text = text
parseValues False True text = text
parseValues True True text = text
updateValues list = map (\elem -> fst elem <> " = " <> snd elem) list
120 changes: 109 additions & 11 deletions IHP/IDE/Data/View/EditRow.hs
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,127 @@ instance View EditRowView ViewContext where
</span>

<div class="input-group">
{renderInputMethod (def, val)}
</div>
</div>|]

onClick tableName fieldName id = "window.location.assign(" <> tshow (pathTo (ToggleBooleanFieldAction tableName (cs fieldName) id)) <> ")"
renderInputMethod :: (ColumnDefinition, DynamicField) -> Html
renderInputMethod (def, val) | (get #columnType def) == "boolean" && isNothing (get #fieldValue val) = [hsx|
{isBooleanParam True def}
<input
id={get #columnName def <> "-alt"}
type="text"
name={get #columnName def}
class="form-control text-monospace text-secondary bg-light"
value="NULL"
/>
<div class="form-control" id={get #columnName def <> "-boxcontainer"}>
<input
id={get #columnName def <> "-input"}
type="checkbox"
class="d-none"
name={get #columnName def <> "-inactive"}
checked={(value val) == "t"}
/>
</div>
<input
id={get #columnName def <> "-hidden"}
type="hidden"
name={get #columnName def}
value={inputValue False}
/>
<div class="input-group-append">
<button class="btn dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></button>
<div class="dropdown-menu dropdown-menu-right custom-menu menu-for-column shadow backdrop-blur">
<a class="dropdown-item" data-value="DEFAULT" data-issql="True" onclick={fillField def "DEFAULT" "true"}>DEFAULT</a>
<a class="dropdown-item" data-value="NULL" data-issql="True" onclick={fillField def "NULL" "true"}>NULL</a>
<a class="dropdown-item">
<input
id={get #columnName def <> "-sqlbox"}
type="checkbox"
name={get #columnName def <> "_"}
checked={True}
class="mr-1"
onclick={"sqlModeCheckbox('" <> get #columnName def <> "', this, true)"}
/>
<label class="form-check-label" for={get #columnName def <> "-sqlbox"}> Parse as SQL</label>
</a>
<input
type="hidden"
name={get #columnName def <> "_"}
value={inputValue False}
/>
</div>
</div>
|]
renderInputMethod (def, val) | (get #columnType def) == "boolean" = [hsx|
{isBooleanParam True def}
<input
id={get #columnName def <> "-alt"}
type="text"
name={get #columnName def <> "-inactive"}
class="form-control text-monospace text-secondary bg-light d-none"
/>
<div class="form-control" id={get #columnName def <> "-boxcontainer"}>
<input
id={get #columnName def <> "-input"}
type="checkbox"
name={get #columnName def}
checked={(value val) == "t"}
/>
</div>
<input
id={get #columnName def <> "-hidden"}
type="hidden"
name={get #columnName def}
value={inputValue False}
/>
<div class="input-group-append">
<button class="btn dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></button>
<div class="dropdown-menu dropdown-menu-right custom-menu menu-for-column shadow backdrop-blur">
<a class="dropdown-item" data-value="DEFAULT" data-issql="True" onclick={fillField def "DEFAULT" "true"}>DEFAULT</a>
<a class="dropdown-item" data-value="NULL" data-issql="True" onclick={fillField def "NULL" "true"}>NULL</a>
<a class="dropdown-item">
<input
id={get #columnName def <> "-sqlbox"}
type="checkbox"
name={get #columnName def <> "_"}
checked={isSqlFunction (getColDefaultValue def)}
class="mr-1"
onclick={"sqlModeCheckbox('" <> get #columnName def <> "', this, true)"}
/>
<label class="form-check-label" for={get #columnName def <> "-sqlbox"}> Parse as SQL</label>
</a>
<input
type="hidden"
name={get #columnName def <> "_"}
value={inputValue False}
/>
</div>
</div>
|]
renderInputMethod (def, val) = [hsx|
{isBooleanParam False def}
<input
id={get #columnName def <> "-input"}
type="text"
name={get #columnName def}
class={classes ["form-control", ("text-monospace text-secondary bg-light", isSqlFunction_ value)]}
value={value}
class={classes ["form-control", ("text-monospace text-secondary bg-light", isSqlFunction_ (value val))]}
value={value val}
oninput={"stopSqlModeOnInput('" <> get #columnName def <> "')"}
/>
<div class="input-group-append">
<button class="btn dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></button>
<div class="dropdown-menu dropdown-menu-right custom-menu menu-for-column shadow backdrop-blur">
<a class="dropdown-item" data-value="DEFAULT" data-issql="True" onclick={fillField def "DEFAULT"}>DEFAULT</a>
<a class="dropdown-item" data-value="NULL" data-issql="True" onclick={fillField def "NULL"}>NULL</a>
<a class="dropdown-item" data-value="DEFAULT" data-issql="True" onclick={fillField def "DEFAULT" "false"}>DEFAULT</a>
<a class="dropdown-item" data-value="NULL" data-issql="True" onclick={fillField def "NULL" "false"}>NULL</a>
<a class="dropdown-item">
<input
id={get #columnName def <> "-sqlbox"}
type="checkbox"
name={get #columnName def <> "_"}
checked={isSqlFunction_ value}
checked={isSqlFunction_ (value val)}
class="mr-1"
onclick={"sqlModeCheckbox('" <> get #columnName def <> "', this)"}
/>
Expand All @@ -102,10 +204,6 @@ instance View EditRowView ViewContext where
value={inputValue False}
/>
</div>
</div>
</div>
</div>|]
where
value = fromMaybe BS.empty (get #fieldValue val)
</div>|]

onClick tableName fieldName id = "window.location.assign(" <> tshow (pathTo (ToggleBooleanFieldAction tableName (cs fieldName) id)) <> ")"
value val = fromMaybe BS.empty (get #fieldValue val)
11 changes: 5 additions & 6 deletions IHP/IDE/Data/View/EditValue.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ instance View EditValueView ViewContext where
where

tableBody = [hsx|<tbody>{forEach rows renderRow}</tbody>|]
renderRow fields = [hsx|<tr oncontextmenu={"showContextMenu('" <> contextMenuId <> "');"}>{forEach fields (renderField id fields)}
renderRow fields = [hsx|<tr oncontextmenu={"showContextMenu('" <> contextMenuId <> "');"}>{forEach fields (renderField id)}
</tr>
<div class="custom-menu menu-for-column shadow backdrop-blur" id={contextMenuId}>
<a href={EditRowAction tableName id}>Edit Row</a>
Expand All @@ -49,16 +49,15 @@ instance View EditValueView ViewContext where
contextMenuId = "context-menu-column-" <> tshow id
id = (cs (fromMaybe "" (get #fieldValue (fromJust (headMay fields)))))

renderField id fields DynamicField { .. } = if (tshow targetName) == (tshow fieldName) && targetId == id
then [hsx|<td>
renderField id DynamicField { .. } | (tshow targetName) == (tshow fieldName) && targetId == id = [hsx|<td>
<form id="fieldForm" method="POST" action={UpdateValueAction}>
<input id="editField" autofocus="autofocus" type="text" name="targetValue" value={fromMaybe "" fieldValue}/>
{forEach fields renderValue}
<input id="inputField" type="hidden" name="tableName" value={tableName}/>
<input type="hidden" name="id" value={id}/>
<input type="hidden" name="targetName" value={targetName}/>
</form></td>|]
else [hsx|<td><span data-fieldname={fieldName}><a class="no-link" href={EditRowValueAction tableName (cs fieldName) id}>{sqlValueToText fieldValue}</a></span></td>|]
renderValue DynamicField { .. } = [hsx|<input type="hidden" name={fieldName} value={renderRowValue fieldValue}/>|]
renderField id DynamicField { .. } | fieldName == "id" = [hsx|<td><span data-fieldname={fieldName}><a class="no-link border rounded p-1" href={EditRowValueAction tableName (cs fieldName) id}>{renderId (sqlValueToText fieldValue)}</a></span></td>|]
renderField id DynamicField { .. } = [hsx|<td><span data-fieldname={fieldName}><a class="no-link" href={EditRowValueAction tableName (cs fieldName) id}>{sqlValueToText fieldValue}</a></span></td>|]
script = preEscapedToHtml [plain|
<script>
onClickHandler = () => {
Expand Down
38 changes: 35 additions & 3 deletions IHP/IDE/Data/View/Layout.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
module IHP.IDE.Data.View.Layout (customQuery, tableHead, renderColumnHead, columnNames, renderRows, sqlValueToText, renderId, isBoolField, isSqlFunction, isSqlFunction_, fillField, getColDefaultValue, renderRowValue) where
module IHP.IDE.Data.View.Layout
( customQuery
, tableHead
, renderColumnHead
, columnNames
, renderRows
, sqlValueToText
, renderId
, isBoolField
, isSqlFunction
, isSqlFunction_
, fillField
, getColDefaultValue
, renderRowValue
, renderDefaultWithoutType
, isBooleanParam
) where

import IHP.ViewPrelude
import IHP.IDE.SchemaDesigner.Types hiding (columnNames)
import IHP.IDE.ToolServer.Types
import IHP.IDE.ToolServer.Layout
import qualified Data.Text as Text

customQuery :: Text -> Html
customQuery input = [hsx|<div class="p-2 rounded mt-2" style="background-color: #002B36;"><div id="queryInput" style="height:16px">{input}</div></div>|]
Expand Down Expand Up @@ -44,7 +61,7 @@ isSqlFunction_ text = text `elem`
, "NOW()"
, "NULL"]

fillField col value = "fillField('" <> get #columnName col <> "', '" <> value <> "');"
fillField col value isBoolField = "fillField('" <> get #columnName col <> "', '" <> value <> "'," <> isBoolField <> ");"

getColDefaultValue :: ColumnDefinition -> Text
getColDefaultValue ColumnDefinition { columnDefault, isNullable } = case columnDefault of
Expand All @@ -55,4 +72,19 @@ getColDefaultValue ColumnDefinition { columnDefault, isNullable } = case columnD

renderRowValue :: Maybe ByteString -> Text
renderRowValue (Just value) = "'" <> cs value <> "'"
renderRowValue Nothing = "NULL"
renderRowValue Nothing = "NULL"

renderDefaultWithoutType :: Text -> Text
renderDefaultWithoutType "" = ""
renderDefaultWithoutType input = case length (Text.splitOn "'" input) of
3 -> (Text.splitOn "'" input) !! 1
_ -> input

isBooleanParam :: Bool -> ColumnDefinition -> Html
isBooleanParam isBool def = [hsx|
<input
type="hidden"
name={get #columnName def <> "-isBoolean"}
value={inputValue isBool}
/>
|]
Loading

0 comments on commit 49816c2

Please sign in to comment.