module IHP.IDE.SchemaDesigner.View.Columns.Edit where import IHP.ViewPrelude import IHP.IDE.SchemaDesigner.Types import qualified IHP.IDE.SchemaDesigner.Compiler as Compiler import IHP.IDE.ToolServer.Types import IHP.IDE.SchemaDesigner.View.Layout data EditColumnView = EditColumnView { EditColumnView -> [Statement] statements :: [Statement] , EditColumnView -> Text tableName :: Text , EditColumnView -> Int columnId :: Int , EditColumnView -> Column column :: Column , EditColumnView -> [Text] enumNames :: [Text] } instance View EditColumnView where html :: (?context::ControllerContext, ?view::EditColumnView) => EditColumnView -> Html html EditColumnView { $sel:column:EditColumnView :: EditColumnView -> Column column = column :: Column column@Column { Text name :: Text $sel:name:Column :: Column -> Text name }, Int [Text] [Statement] Text $sel:statements:EditColumnView :: EditColumnView -> [Statement] $sel:tableName:EditColumnView :: EditColumnView -> Text $sel:columnId:EditColumnView :: EditColumnView -> Int $sel:enumNames:EditColumnView :: EditColumnView -> [Text] statements :: [Statement] tableName :: Text columnId :: Int enumNames :: [Text] .. } = [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 :: Maybe Statement table = Text -> [Statement] -> Maybe Statement forall {t :: * -> *}. Foldable t => Text -> t Statement -> Maybe Statement findStatementByName Text tableName [Statement] statements columns :: [Column] columns = [Column] -> (Statement -> [Column]) -> Maybe Statement -> [Column] forall b a. b -> (a -> b) -> Maybe a -> b maybe [] ((.columns) (CreateTable -> [Column]) -> (Statement -> CreateTable) -> Statement -> [Column] forall b c a. (b -> c) -> (a -> b) -> a -> c forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k). Category cat => cat b c -> cat a b -> cat a c . Statement -> CreateTable unsafeGetCreateTable) Maybe Statement table primaryKeyColumns :: [Text] primaryKeyColumns = [Text] -> (Statement -> [Text]) -> Maybe Statement -> [Text] forall b a. b -> (a -> b) -> Maybe a -> b maybe [] (PrimaryKeyConstraint -> [Text] primaryKeyColumnNames (PrimaryKeyConstraint -> [Text]) -> (Statement -> PrimaryKeyConstraint) -> Statement -> [Text] forall b c a. (b -> c) -> (a -> b) -> a -> c forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k). Category cat => cat b c -> cat a b -> cat a c . (.primaryKeyConstraint) (CreateTable -> PrimaryKeyConstraint) -> (Statement -> CreateTable) -> Statement -> PrimaryKeyConstraint forall b c a. (b -> c) -> (a -> b) -> a -> c forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k). Category cat => cat b c -> cat a b -> cat a c . Statement -> CreateTable unsafeGetCreateTable) Maybe Statement table isArrayType :: PostgresType -> Bool isArrayType (PArray PostgresType _) = Bool True isArrayType PostgresType _ = Bool False isPrimaryKey :: Bool isPrimaryKey :: Bool isPrimaryKey = Text name Text -> [Text] -> Bool forall a. Eq a => a -> [a] -> Bool forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool `elem` [Text] primaryKeyColumns modalContent :: Html 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 :: Maybe Html modalFooter = Maybe Html forall a. Monoid a => a mempty modalCloseUrl :: Text modalCloseUrl = TablesController -> Text forall controller. HasPath controller => controller -> Text pathTo ShowTableAction { Text tableName :: Text $sel:tableName:TablesAction :: Text tableName } modalTitle :: Text modalTitle = Text "Edit Column" modal :: Modal modal = Modal { Html modalContent :: Html $sel:modalContent:Modal :: Html modalContent, Maybe Html modalFooter :: Maybe Html $sel:modalFooter:Modal :: Maybe Html modalFooter, Text modalCloseUrl :: Text $sel:modalCloseUrl:Modal :: Text modalCloseUrl, Text modalTitle :: Text $sel:modalTitle:Modal :: Text modalTitle } typeSelector :: Maybe PostgresType -> [Text] -> Html typeSelector :: Maybe PostgresType -> [Text] -> Html typeSelector Maybe PostgresType postgresType [Text] 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 :: Maybe Text isSelected = (PostgresType -> Text) -> Maybe PostgresType -> Maybe Text forall a b. (a -> b) -> Maybe a -> Maybe b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap PostgresType -> Text Compiler.compilePostgresType Maybe PostgresType postgresType renderEnumType :: Text -> Html renderEnumType Text enum = Maybe Text -> Text -> Text -> Html option Maybe Text isSelected Text enum Text enum option :: Maybe Text -> Text -> Text -> Html option :: Maybe Text -> Text -> Text -> Html option Maybe Text selected Text value Text text = case Maybe Text selected of Maybe Text Nothing -> [hsx|<option value={value}>{text}</option>|] Just Text selection -> if Text selection Text -> Text -> Bool forall a. Eq a => a -> a -> Bool == Text value Bool -> Bool -> Bool || Text selection Text -> Text -> Bool forall a. Eq a => a -> a -> Bool == Text value Text -> Text -> Text forall a. Semigroup a => a -> a -> a <> Text "[]" then [hsx|<option value={value} selected="selected">{text}</option>|] else [hsx|<option value={value}>{text}</option>|] customenums :: [Text] -> Html customenums [] = [hsx| |] customenums [Text] xs = [hsx| <optgroup label="Custom Enums"> {forEach xs renderEnumType} </optgroup> |] defaultSelector :: Maybe Expression -> Html defaultSelector :: Maybe Expression -> Html defaultSelector Maybe Expression defValue = [hsx| <div class="col-sm-10"> <select id="defaultSelector" name="defaultValue" class="form-control select2"> {forEach values renderValue} </select> </div> |] where suggestedValues :: [Maybe Expression] suggestedValues = [Maybe Expression forall a. Maybe a Nothing, Expression -> Maybe Expression forall a. a -> Maybe a Just (Text -> Expression TextExpression Text ""), Expression -> Maybe Expression forall a. a -> Maybe a Just (Text -> Expression VarExpression Text "NULL"), Expression -> Maybe Expression forall a. a -> Maybe a Just (Text -> [Expression] -> Expression CallExpression Text "NOW" [])] values :: [Maybe Expression] values = if Maybe Expression defValue Maybe Expression -> [Maybe Expression] -> Bool forall a. Eq a => a -> [a] -> Bool forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool `elem` [Maybe Expression] suggestedValues then [Maybe Expression] suggestedValues else Maybe Expression defValueMaybe Expression -> [Maybe Expression] -> [Maybe Expression] forall a. a -> [a] -> [a] :[Maybe Expression] suggestedValues renderValue :: Maybe Expression -> Html renderValue :: Maybe Expression -> Html renderValue e :: Maybe Expression e@(Just Expression expression) = [hsx|<option value={Compiler.compileExpression expression} selected={e == defValue}>{displayedValue}</option>|] where displayedValue :: Text displayedValue = case Expression expression of TextExpression Text "" -> Text "\"\"" Expression _ -> Expression -> Text Compiler.compileExpression Expression expression renderValue Maybe Expression Nothing = [hsx|<option value="" selected={Nothing == defValue}>No default</option>|]