Skip to content

Commit

Permalink
Add languageToolCore to form options, and permit creating and saving …
Browse files Browse the repository at this point in the history
…this rule type, exposing external id

With a friendly placeholder when the rule is first created, rather than a UUID
  • Loading branch information
jonathonherbert committed Nov 5, 2024
1 parent 3ffa8de commit 0997d3f
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 36 deletions.
45 changes: 31 additions & 14 deletions apps/rule-manager/app/db/DbRuleDraft.scala
Original file line number Diff line number Diff line change
Expand Up @@ -380,29 +380,44 @@ object DbRuleDraft extends SQLSyntaxSupport[DbRuleDraft] {
notes: Option[String] = None,
forceRedRule: Option[Boolean] = None,
advisoryRule: Option[Boolean] = None,
externalId: Option[String] = None,
user: String,
isArchived: Boolean = false,
tags: List[Int] = List.empty
)(implicit session: DBSession = autoSession): Try[DbRuleDraft] = {
val latestRuleOrder = getLatestRuleOrder()

val externalIdCol = externalId
.orElse {
ruleType match {
case RuleType.languageToolCore => Some("CHANGE_ME")
case _ => None
}
}
.map((column.externalId -> _))
.toList

val columnUpdates = List(
column.ruleType -> ruleType,
column.pattern -> pattern,
column.replacement -> replacement,
column.category -> category,
column.description -> description,
column.ignore -> ignore,
column.notes -> notes,
column.forceRedRule -> forceRedRule,
column.advisoryRule -> advisoryRule,
column.createdBy -> user,
column.updatedBy -> user,
column.isArchived -> isArchived,
column.ruleOrder -> (latestRuleOrder + 1)
) ++ externalIdCol

val id = withSQL {
insert
.into(DbRuleDraft)
.namedValues(
column.ruleType -> ruleType,
column.pattern -> pattern,
column.replacement -> replacement,
column.category -> category,
column.description -> description,
column.ignore -> ignore,
column.notes -> notes,
column.forceRedRule -> forceRedRule,
column.advisoryRule -> advisoryRule,
column.createdBy -> user,
column.updatedBy -> user,
column.isArchived -> isArchived,
column.ruleOrder -> (latestRuleOrder + 1)
columnUpdates: _*
)
}.updateAndReturnGeneratedKey().apply().toInt

Expand Down Expand Up @@ -432,6 +447,7 @@ object DbRuleDraft extends SQLSyntaxSupport[DbRuleDraft] {
description = formRule.description,
ignore = formRule.ignore,
notes = formRule.notes,
externalId = formRule.externalId,
forceRedRule = formRule.forceRedRule,
advisoryRule = formRule.advisoryRule,
user = user
Expand All @@ -454,7 +470,8 @@ object DbRuleDraft extends SQLSyntaxSupport[DbRuleDraft] {
category = formRule.category,
tags = formRule.tags,
description = formRule.description,
advisoryRule = formRule.advisoryRule
advisoryRule = formRule.advisoryRule,
externalId = formRule.externalId.orElse(existingRule.externalId)
)
)
updatedRule match {
Expand Down
6 changes: 4 additions & 2 deletions apps/rule-manager/app/model/CreateRuleForm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ object CreateRuleForm {
"ignore" -> boolean,
"notes" -> optional(text()),
"forceRedRule" -> optional(boolean),
"advisoryRule" -> optional(boolean)
"advisoryRule" -> optional(boolean),
"externalId" -> optional(text())
)(CreateRuleForm.apply)(CreateRuleForm.unapply)
)
}
Expand All @@ -52,5 +53,6 @@ case class CreateRuleForm(
ignore: Boolean,
notes: Option[String] = None,
forceRedRule: Option[Boolean] = None,
advisoryRule: Option[Boolean] = None
advisoryRule: Option[Boolean] = None,
externalId: Option[String] = None
)
6 changes: 4 additions & 2 deletions apps/rule-manager/app/model/UpdateRuleForm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ object UpdateRuleForm {
"category" -> optional(text()),
"tags" -> list(number()),
"description" -> optional(text()),
"advisoryRule" -> optional(boolean)
"advisoryRule" -> optional(boolean),
"externalId" -> optional(text())
)(UpdateRuleForm.apply)(UpdateRuleForm.unapply)
)
}
Expand All @@ -47,5 +48,6 @@ case class UpdateRuleForm(
category: Option[String] = None,
tags: List[Int],
description: Option[String] = None,
advisoryRule: Option[Boolean] = None
advisoryRule: Option[Boolean] = None,
externalId: Option[String] = None
)
69 changes: 51 additions & 18 deletions apps/rule-manager/client/src/ts/components/RuleContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ export const ruleTypeOptions: RuleTypeOption[] = [
},
];

const formDisplayRules = (ruleType: RuleType) => ({
displayDescription: ruleType !== 'dictionary',
displayDattern: ruleType !== 'dictionary' && ruleType !== 'languageToolCore',
displayDeplacement:
ruleType !== 'dictionary' && ruleType !== 'languageToolCore',
});

export const RuleContent = ({
ruleData,
ruleFormData,
Expand All @@ -72,7 +79,14 @@ export const RuleContent = ({
};

const patternErrors = getErrorPropsForField('pattern', validationErrors);
const isDictionaryRule = ruleFormData.ruleType === 'dictionary';
const idErrors = getErrorPropsForField('externalId', validationErrors);
const { ruleType } = ruleFormData;
const displayDescription = ruleType !== 'dictionary';
const displayPattern =
ruleType !== 'dictionary' && ruleType !== 'languageToolCore';
const displayReplacement =
ruleType !== 'dictionary' && ruleType !== 'languageToolCore';
const displayExternalId = ruleType === 'languageToolCore';

return (
<RuleFormSection
Expand All @@ -89,7 +103,7 @@ export const RuleContent = ({
>
<LineBreak />
<EuiFlexItem>
{!isDictionaryRule && (
{displayDescription && (
<EuiFormRow
label={
<div>
Expand All @@ -115,7 +129,6 @@ export const RuleContent = ({
}
helpText="What will the users see in Composer?"
fullWidth={true}
isDisabled={isDictionaryRule}
>
{!showMarkdownPreview ? (
<EuiTextArea
Expand Down Expand Up @@ -153,30 +166,50 @@ export const RuleContent = ({
display: flex;
gap: 1rem;
align-items: flex-end;
white-space: nowrap;
`}
/>
<EuiSpacer size="s" />
<EuiFormRow
label={<Label text="Pattern" required={true} />}
fullWidth={true}
{...patternErrors}
>
<TextField
value={ruleFormData.pattern || ''}
onChange={(_) =>
partiallyUpdateRuleData({ pattern: _.target.value })
}
required={true}
{displayExternalId && (
<EuiFormRow
label={<Label text="LanguageTool ID" required={true} />}
helpText="The ID of the built-in LanguageTool rule"
fullWidth={true}
{...idErrors}
>
<TextField
value={ruleFormData.externalId || ''}
onChange={(_) =>
partiallyUpdateRuleData({ externalId: _.target.value })
}
required={true}
fullWidth={true}
{...patternErrors}
/>
</EuiFormRow>
)}
{displayPattern && (
<EuiFormRow
label={<Label text="Pattern" required={true} />}
fullWidth={true}
{...patternErrors}
/>
</EuiFormRow>
{!isDictionaryRule && (
>
<TextField
value={ruleFormData.pattern || ''}
onChange={(_) =>
partiallyUpdateRuleData({ pattern: _.target.value })
}
required={true}
fullWidth={true}
{...patternErrors}
/>
</EuiFormRow>
)}
{displayReplacement && (
<EuiFormRow
label="Replacement"
helpText="What is the ideal term as per the house style?"
fullWidth={true}
isDisabled={isDictionaryRule}
>
<EuiFieldText
value={ruleFormData.replacement || ''}
Expand Down
64 changes: 64 additions & 0 deletions apps/rule-manager/test/db/DbRuleDraftSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,44 @@ class DbRuleDraftSpec extends RuleFixture with Matchers with DBTest {
dbRule should not be (null)
}

it should s"store external IDs when creating rules of type ${RuleType.languageToolCore}" in {
implicit session =>
val formRule = CreateRuleForm(
ruleType = "languageToolCore",
pattern = None,
replacement = None,
category = None,
tags = None,
description = None,
ignore = false,
notes = None,
forceRedRule = None,
advisoryRule = None,
externalId = Some("EXTERNAL_ID")
)
val dbRule = DbRuleDraft.createFromFormRule(formRule, user = "test.user")
dbRule.toOption.get.externalId shouldBe Some("EXTERNAL_ID")
}

it should s"generate a friendly placeholder for external ID when creating rules of type ${RuleType.languageToolCore}" in {
implicit session =>
val formRule = CreateRuleForm(
ruleType = "languageToolCore",
pattern = None,
replacement = None,
category = None,
tags = None,
description = None,
ignore = false,
notes = None,
forceRedRule = None,
advisoryRule = None,
externalId = None
)
val dbRule = DbRuleDraft.createFromFormRule(formRule, user = "test.user")
dbRule.toOption.get.externalId shouldBe Some("CHANGE_ME")
}

it should "edit an existing record using a form rule, updating the user and updated datetime" in {
implicit session =>
val existingRule = DbRuleDraft
Expand All @@ -344,6 +382,32 @@ class DbRuleDraftSpec extends RuleFixture with Matchers with DBTest {
dbRule.updatedAt.toInstant.toEpochMilli should be >= existingRule.updatedAt.toInstant.toEpochMilli
}

it should s"update external IDs for rules of type ${RuleType.languageToolCore}" in {
implicit session =>
val existingRule = DbRuleDraft
.create(
ruleType = "languageToolCore",
externalId = Some("EXTERNAL_ID"),
user = "test.user",
ignore = false
)
.get
val existingId = existingRule.id.get
val formRule = UpdateRuleForm(
ruleType = Some("languageToolCore"),
externalId = Some("EXTERNAL_ID_UPDATE"),
tags = List.empty
)

val dbRule =
DbRuleDraft.updateFromFormRule(formRule, existingId, "another.user").getOrElse(null)

dbRule.id should be(Some(existingId))
dbRule.externalId should be(Some("EXTERNAL_ID_UPDATE"))
dbRule.updatedBy should be("another.user")
dbRule.updatedAt.toInstant.toEpochMilli should be >= existingRule.updatedAt.toInstant.toEpochMilli
}

it should "save a record, updating the modified fields and incrementing the revisionId" in {
implicit session =>
val entity = DbRuleDraft.findAll().head
Expand Down

0 comments on commit 0997d3f

Please sign in to comment.