ihp-ide-1.4.0: IHP/IDE/SchemaDesigner/View/Columns/Edit.hs
module IHP.IDE.SchemaDesigner.View.Columns.Edit where
import IHP.ViewPrelude hiding (primaryKeyColumnNames)
import IHP.IDE.SchemaDesigner.Types
import qualified IHP.IDE.SchemaDesigner.Compiler as Compiler
import IHP.IDE.ToolServer.Types
import IHP.IDE.SchemaDesigner.View.Layout
import Text.Countable (singularize)
data EditColumnView = EditColumnView
{ statements :: [Statement]
, tableName :: Text
, columnId :: Int
, column :: Column
, enumNames :: [Text]
}
instance View EditColumnView where
html EditColumnView { column = column@Column { name }, .. } = [hsx|
<div class="row no-gutters bg-white" id="schema-designer-viewer">
{renderObjectSelector (zip [0..] statements) (Just tableName)}
{renderColumnSelector tableName (zip [0..] columns) statements}
</div>
{migrationStatus}
{renderModal modal}
|]
where
table = findStatementByName tableName statements
columns = maybe [] ((.columns) . unsafeGetCreateTable) table
primaryKeyColumns = maybe [] (primaryKeyColumnNames . (.primaryKeyConstraint) . unsafeGetCreateTable) table
isArrayType (PArray _) = True
isArrayType _ = False
isPrimaryKey :: Bool
isPrimaryKey = name `elem` primaryKeyColumns
modalContent = [hsx|
<form method="POST" action={UpdateColumnAction}>
<input type="hidden" name="tableName" value={tableName}/>
<input type="hidden" name="columnId" value={tshow columnId}/>
<div class="form-group">
<input
id="nameInput"
name="name"
type="text"
class="form-control"
autofocus="autofocus"
value={column.name}
data-table-name-singular={singularize tableName}
/>
</div>
<div class="form-group">
{typeSelector (Just (column.columnType)) enumNames}
<div class="d-flex text-muted mt-1" id="column-options">
<div class="custom-control custom-checkbox mr-2">
<input id="allowNull" type="checkbox" name="allowNull" class="custom-control-input" checked={not (column.notNull)}/>
<label class="mr-1 custom-control-label" for="allowNull">
Nullable
</label>
</div>
<div class="custom-control custom-checkbox mr-2">
<input type="checkbox" id="isUnique" name="isUnique" class="custom-control-input" checked={column.isUnique}/>
<label class="custom-control-label" for="isUnique">
Unique
</label>
</div>
<div class="custom-control custom-checkbox mr-2">
<input type="checkbox" id="primaryKey" name="primaryKey" class="custom-control-input" checked={isPrimaryKey}/>
<label class="custom-control-label" for="primaryKey">
Primary Key
</label>
</div>
<div class="custom-control custom-checkbox mr-2">
<input id="isArray" type="checkbox" name="isArray" class="custom-control-input" checked={isArrayType (column.columnType)}/>
<label class="custom-control-label">
Array Type
</label>
</div>
</div>
</div>
<div class="form-group row">
{defaultSelector (column.defaultValue)}
</div>
<div class="text-right">
<button type="submit" class="btn btn-primary">Edit Column</button>
</div>
<input type="hidden" name="primaryKey" value={inputValue False}/>
<input type="hidden" name="allowNull" value={inputValue False}/>
<input type="hidden" name="isUnique" value={inputValue False}/>
<input type="hidden" name="isArray" value={inputValue False}/>
</form>
|]
modalFooter = mempty
modalCloseUrl = pathTo ShowTableAction { tableName }
modalTitle = "Edit Column"
modal = Modal { modalContent, modalFooter, modalCloseUrl, modalTitle }
typeSelector :: Maybe PostgresType -> [Text] -> Html
typeSelector postgresType enumNames = [hsx|
<select id="typeSelector" name="columnType" class="form-control select2-simple">
<optgroup label="Common Types">
{option isSelected "TEXT" "Text"}
{option isSelected "INT" "Int"}
{option isSelected "UUID" "UUID"}
{option isSelected "BOOLEAN" "Bool"}
{option isSelected "DATE" "Date / Day"}
{option isSelected "TIMESTAMP WITH TIME ZONE" "Timestamp (UTCTime)"}
{option isSelected "SERIAL" "Serial"}
</optgroup>
{customenums enumNames}
<optgroup label="Other Types">
{option isSelected "TIMESTAMP WITHOUT TIME ZONE" "Timestamp (LocalTime)"}
{option isSelected "REAL" "Float"}
{option isSelected "DOUBLE PRECISION" "Double"}
{option isSelected "POINT" "Point"}
{option isSelected "BYTEA" "Binary"}
{option isSelected "Time" "Time"}
{option isSelected "INTERVAL" "Interval"}
{option isSelected "BIGSERIAL" "Bigserial"}
{option isSelected "SMALLINT" "Int (16bit)"}
{option isSelected "BIGINT" "Int (64bit)"}
{option isSelected "JSONB" "JSON"}
{option isSelected "INET" "IP Address"}
{option isSelected "TSVECTOR" "TSVector"}
</optgroup>
</select>
|]
where
isSelected :: Maybe Text
isSelected = fmap Compiler.compilePostgresType postgresType
renderEnumType enum = option isSelected enum enum
option :: Maybe Text -> Text -> Text -> Html
option selected value text = case selected of
Nothing -> [hsx|<option value={value}>{text}</option>|]
Just selection ->
if selection == value || selection == value <> "[]"
then [hsx|<option value={value} selected="selected">{text}</option>|]
else [hsx|<option value={value}>{text}</option>|]
customenums [] = [hsx| |]
customenums xs = [hsx| <optgroup label="Custom Enums">
{forEach xs renderEnumType}
</optgroup>
|]
defaultSelector :: Maybe Expression -> Html
defaultSelector defValue = [hsx|
<div class="col-sm-10">
<select id="defaultSelector" name="defaultValue" class="form-control select2">
{forEach values renderValue}
</select>
</div>
|]
where
suggestedValues = [Nothing, Just (TextExpression ""), Just (VarExpression "NULL"), Just (CallExpression "NOW" [])]
values = if defValue `elem` suggestedValues then suggestedValues else defValue:suggestedValues
renderValue :: Maybe Expression -> Html
renderValue e@(Just expression) = [hsx|<option value={Compiler.compileExpression expression} selected={e == defValue}>{displayedValue}</option>|]
where
displayedValue = case expression of
TextExpression "" -> "\"\""
_ -> Compiler.compileExpression expression
renderValue Nothing = [hsx|<option value="" selected={Nothing == defValue}>No default</option>|]