module IHP.IDE.SchemaDesigner.View.Migrations.Index where
import IHP.ViewPrelude
import IHP.IDE.ToolServer.Helper.View
import IHP.SchemaMigration
import IHP.IDE.ToolServer.Types
import IHP.IDE.ToolServer.Routes ()
import qualified Data.Time.Clock.POSIX as Clock
type Revision = Int
data IndexView = IndexView
{ IndexView -> [(Migration, Text)]
migrationsWithSql :: ![(Migration, Text)]
, IndexView -> [Int]
migratedRevisions :: ![Int]
, IndexView -> Maybe Text
lastError :: !(Maybe Text)
}
instance View IndexView where
html :: (?context::ControllerContext, ?view::IndexView) =>
IndexView -> Html
html IndexView { $sel:migrationsWithSql:IndexView :: IndexView -> [(Migration, Text)]
migrationsWithSql = [] } = Html
Html
emptyState
html IndexView { [Int]
[(Migration, Text)]
Maybe Text
$sel:migrationsWithSql:IndexView :: IndexView -> [(Migration, Text)]
$sel:migratedRevisions:IndexView :: IndexView -> [Int]
$sel:lastError:IndexView :: IndexView -> Maybe Text
migrationsWithSql :: [(Migration, Text)]
migratedRevisions :: [Int]
lastError :: Maybe Text
.. } = [hsx|
<div class="pt-3 flex-grow-1" oncontextmenu="showContextMenu('context-menu-migrations')">
<div class="d-flex align-items-center mb-3 pr-2">
<a
href={NewMigrationAction}
class="ml-auto btn btn-link btn-add"
data-toggle="tooltip"
data-placement="bottom"
title="Add Migration"
>
{addIcon}
</a>
</div>
<div class="mx-3">{renderFlashMessages}</div>
{forEachWithIndex migrationsWithSql renderMigration}
</div>
{migrationsContextMenu}
|]
where
renderMigration :: (Int, (Migration, Text)) -> Html
renderMigration :: (Int, (Migration, Text)) -> Html
renderMigration (Int
index, (Migration
migration, Text
sqlStatements)) = [hsx|
<div class={classes ["migration mx-3", ("is-completed", not pending), ("pending", pending)]} oncontextmenu={"showContextMenu('" <> contextMenuId <> "'); event.stopPropagation();"}>
<div class="migration-actions d-flex justify-content-end align-items-center">
{runOrStatus}
{when pending editAndDelete}
</div>
{code "sql" sqlStatements}
</div>
{migrationContextMenu migration contextMenuId pending}
|]
where
pending :: Bool
pending = (Migration
migration.revision) Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
migratedRevisions
currentError :: Maybe Text
currentError = Maybe Text
lastError
contextMenuId :: Text
contextMenuId :: Text
contextMenuId = Text
"context-menu-migration-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow (Migration
migration.revision)
editAndDelete :: Html
editAndDelete = [hsx|
<div class="d-flex">
<a
href={EditMigrationAction (migration.revision)}
class="btn btn-link btn-add"
data-toggle="tooltip"
data-placement="bottom"
title="Edit Migration"
>{editIcon}</a>
<a
href={DeleteMigrationAction (migration.revision)}
class="btn btn-link btn-add js-delete"
data-toggle="tooltip"
data-placement="bottom"
title="Delete Migration"
>{deleteIcon}</a>
</div>
|]
currentErrorHtml :: Html
currentErrorHtml = Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Maybe Text -> Bool
forall a. Maybe a -> Bool
isNothing Maybe Text
currentError) [hsx|
<div class="text-danger font-weight-bold mr-2">
{currentError}
</div>
|]
runOrStatus :: Html
runOrStatus :: Html
runOrStatus =
if Bool
pending
then [hsx|
<form method="POST" action={RunMigrationAction (migration.revision)} class="mr-2 d-flex align-items-center">
{currentErrorHtml}
<button
class="btn btn-secondary migration-run-button"
>{if isJust currentError then "Retry" else "Run" :: Text}</button>
</form>
|]
else [hsx|
<div class="d-flex justify-content-end mb-2">
<span class="text-muted mr-2 user-select-none" style="opacity: 0.5">{timeAgo revisionTime}</span>
<strong class="text-success">
{checkmark}
</strong>
</div>
|]
revisionTime :: UTCTime
revisionTime :: UTCTime
revisionTime = POSIXTime -> UTCTime
Clock.posixSecondsToUTCTime (POSIXTime -> UTCTime) -> POSIXTime -> UTCTime
forall a b. (a -> b) -> a -> b
$ (Integer -> POSIXTime
forall a. Num a => Integer -> a
fromInteger (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Migration
migration.revision)))
code :: Text -> Text -> Html
code :: Text -> Text -> Html
code Text
_ Text
src = [hsx|
<div class="source-code">
<pre><code class="language-sql">{src}</code></pre>
</div>
|]
checkmark :: Html
checkmark = String -> Html
forall a. ToMarkup a => a -> Html
preEscapedToHtml [plain|
<svg width="16px" height="12px" viewBox="0 0 16 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Migrations" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Mig-Redesign-with-messages" transform="translate(-1401.000000, -607.000000)" fill="#059053">
<g id="Task-10---24px" transform="translate(1401.000000, 607.000000)">
<path d="M15.6987017,0.284560762 C16.0938017,0.670430762 16.1013017,1.30355076 15.7155017,1.69867076 L5.94984168,11.6987008 C5.75306168,11.9002008 5.48044168,12.0093008 5.19897168,11.9994008 C4.91751168,11.9894008 4.65330168,11.8612008 4.47128168,11.6463008 L0.23691168,6.64630076 C-0.12001832,6.22480076 -0.0676983198,5.59380076 0.35376168,5.23690076 C0.77521168,4.88000076 1.40621168,4.93230076 1.76314168,5.35370076 L5.28704168,9.51480076 L14.2846017,0.301330762 C14.6704017,-0.0937992379 15.3036017,-0.101309238 15.6987017,0.284560762 Z" id="Path"></path>
</g>
</g>
</g>
</svg>
|]
emptyState :: Html
emptyState :: Html
emptyState = [hsx|
<div class="d-flex flex-column w-100 h-100 justify-content-center user-select-none" oncontextmenu="showContextMenu('context-menu-migrations')">
<div class="text-center">
<p class="text-muted">
No Migration yet.
</p>
<p>
<a href={NewMigrationAction} class="btn btn-secondary">+ New Migration</a>
</p>
</div>
</div>
{migrationsContextMenu}
|]
migrationsContextMenu :: Html
= [hsx|
<div class="custom-menu menu-for-table shadow backdrop-blur" id="context-menu-migrations">
<a href={NewMigrationAction}>Add Migration</a>
</div>
|]
r
migration value
contextMenuId Bool
pending = [hsx|
<div class="custom-menu menu-for-table shadow backdrop-blur" id={contextMenuId}>
{currentMigrationActions}
<a href={NewMigrationAction}>Add Migration</a>
</div>
|]
where
migrationId :: Int
migrationId :: Int
migrationId = r
migration.revision
currentMigrationActions :: Html
currentMigrationActions = Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
pending [hsx|
<a href={EditMigrationAction migrationId}>Edit Migration</a>
<a href={DeleteMigrationAction migrationId} class="js-delete">Delete Migration</a>
<div></div>
|]