packages feed

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>|]