diff --git a/CHANGELOG.md b/CHANGELOG.md index 906dd20..743896c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - mariadb / mysql support (fixes https://github.com/ohmyform/ohmyform/issues/143) - user confirmation tokens - email verification +- idx for fields and logic to have stable order ### Changed diff --git a/Dockerfile b/Dockerfile index 49292c1..36589fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,8 @@ ENV PORT=3000 \ CREATE_ADMIN=FALSE \ ADMIN_EMAIL=admin@ohmyform.com \ ADMIN_USERNAME=root \ - ADMIN_PASSWORD=root + ADMIN_PASSWORD=root \ + NODE_ENV=production EXPOSE 3000 diff --git a/locales/en/mail/user/created.mjml b/locales/en/mail/user/created.mjml index 834ddff..ae057ab 100644 --- a/locales/en/mail/user/created.mjml +++ b/locales/en/mail/user/created.mjml @@ -13,6 +13,9 @@ Your Username is {{username}} + + Click here to verify your Account + diff --git a/src/dto/form/form.field.input.ts b/src/dto/form/form.field.input.ts index 1ded07c..fd35af7 100644 --- a/src/dto/form/form.field.input.ts +++ b/src/dto/form/form.field.input.ts @@ -17,6 +17,9 @@ export class FormFieldInput { @Field({ nullable: true }) readonly slug?: string + @Field({ nullable: true }) + readonly idx?: number + @Field() readonly description: string diff --git a/src/dto/form/form.field.logic.input.ts b/src/dto/form/form.field.logic.input.ts index b1553c2..cedf160 100644 --- a/src/dto/form/form.field.logic.input.ts +++ b/src/dto/form/form.field.logic.input.ts @@ -13,6 +13,9 @@ export class FormFieldLogicInput { @Field(() => String, { nullable: true }) readonly action: FormFieldLogicAction + @Field({ nullable: true }) + readonly idx?: number + @Field(() => ID, { nullable: true }) readonly jumpTo?: string diff --git a/src/dto/form/form.field.logic.model.ts b/src/dto/form/form.field.logic.model.ts index 94d17e1..7567b1c 100644 --- a/src/dto/form/form.field.logic.model.ts +++ b/src/dto/form/form.field.logic.model.ts @@ -12,6 +12,9 @@ export class FormFieldLogicModel { @Field() readonly action: string + @Field({ nullable: true }) + readonly idx?: number + @Field(() => ID, { nullable: true }) readonly jumpTo?: string @@ -34,6 +37,7 @@ export class FormFieldLogicModel { this.formula = document.formula this.jumpTo = document.jumpTo?.id.toString() + this.idx = document.idx this.action = document.action this.visible = document.visible this.disable = document.disable diff --git a/src/dto/form/form.field.model.ts b/src/dto/form/form.field.model.ts index 59c0fea..c8ae782 100644 --- a/src/dto/form/form.field.model.ts +++ b/src/dto/form/form.field.model.ts @@ -15,6 +15,9 @@ export class FormFieldModel { @Field({ nullable: true }) readonly slug?: string + @Field({ nullable: true }) + readonly idx: number + @Field() readonly type: string @@ -38,6 +41,7 @@ export class FormFieldModel { constructor(document: FormFieldEntity) { this.id = document.id.toString() + this.idx = document.idx this.title = document.title this.slug = document.slug this.type = document.type diff --git a/src/entity/form.field.entity.ts b/src/entity/form.field.entity.ts index f7560cc..fc61f0e 100644 --- a/src/entity/form.field.entity.ts +++ b/src/entity/form.field.entity.ts @@ -21,6 +21,9 @@ export class FormFieldEntity { @Column({ nullable: true }) public slug?: string + @Column({ nullable: true }) + public idx?: number + @OneToMany(() => FormFieldLogicEntity, logic => logic.field, { eager: true, orphanedRowAction: 'delete', cascade: true }) public logic: FormFieldLogicEntity[] diff --git a/src/entity/form.field.logic.entity.ts b/src/entity/form.field.logic.entity.ts index 9ddc22a..7cdb026 100644 --- a/src/entity/form.field.logic.entity.ts +++ b/src/entity/form.field.logic.entity.ts @@ -14,6 +14,9 @@ export class FormFieldLogicEntity { @Column() public formula: string + @Column({ nullable: true }) + public idx?: number + @Column({ type: 'varchar', length: 10 }) public action: FormFieldLogicAction diff --git a/src/migrations/mariadb/1641151802308-idx.ts b/src/migrations/mariadb/1641151802308-idx.ts new file mode 100644 index 0000000..42ff91e --- /dev/null +++ b/src/migrations/mariadb/1641151802308-idx.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class idx1641151802308 implements MigrationInterface { + name = 'idx1641151802308' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field_logic` ADD `idx` int NULL'); + await queryRunner.query('ALTER TABLE `form_field` ADD `idx` int NULL'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `form_field` DROP COLUMN `idx`'); + await queryRunner.query('ALTER TABLE `form_field_logic` DROP COLUMN `idx`'); + } +} diff --git a/src/migrations/postgres/1641151802308-idx.ts b/src/migrations/postgres/1641151802308-idx.ts new file mode 100644 index 0000000..8e7d61a --- /dev/null +++ b/src/migrations/postgres/1641151802308-idx.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class idx1641151802308 implements MigrationInterface { + name = 'idx1641151802308' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field_logic" ADD "idx" integer'); + await queryRunner.query('ALTER TABLE "form_field" ADD "idx" integer'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" DROP COLUMN "idx"'); + await queryRunner.query('ALTER TABLE "form_field_logic" DROP COLUMN "idx"'); + } +} diff --git a/src/migrations/sqlite/1641151802308-idx.ts b/src/migrations/sqlite/1641151802308-idx.ts new file mode 100644 index 0000000..0bc3550 --- /dev/null +++ b/src/migrations/sqlite/1641151802308-idx.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class idx1641151802308 implements MigrationInterface { + name = 'idx1641151802308' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('CREATE TABLE "temporary_form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, "idx" integer, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form_field_logic"("id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId") SELECT "id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId" FROM "form_field_logic"'); + await queryRunner.query('DROP TABLE "form_field_logic"'); + await queryRunner.query('ALTER TABLE "temporary_form_field_logic" RENAME TO "form_field_logic"'); + await queryRunner.query('CREATE TABLE "temporary_form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, "idx" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "temporary_form_field"("id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape" FROM "form_field"'); + await queryRunner.query('DROP TABLE "form_field"'); + await queryRunner.query('ALTER TABLE "temporary_form_field" RENAME TO "form_field"'); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "form_field" RENAME TO "temporary_form_field"'); + await queryRunner.query('CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form_field"("id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape") SELECT "id", "title", "description", "slug", "required", "disabled", "type", "value", "formId", "ratingSteps", "ratingShape" FROM "temporary_form_field"'); + await queryRunner.query('DROP TABLE "temporary_form_field"'); + await queryRunner.query('ALTER TABLE "form_field_logic" RENAME TO "temporary_form_field_logic"'); + await queryRunner.query('CREATE TABLE "form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)'); + await queryRunner.query('INSERT INTO "form_field_logic"("id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId") SELECT "id", "formula", "action", "visible", "require", "disable", "enabled", "fieldId", "jumpToId" FROM "temporary_form_field_logic"'); + await queryRunner.query('DROP TABLE "temporary_form_field_logic"'); + } +} diff --git a/src/service/form/form.update.service.ts b/src/service/form/form.update.service.ts index 194dc1e..4332f7e 100644 --- a/src/service/form/form.update.service.ts +++ b/src/service/form/form.update.service.ts @@ -61,6 +61,10 @@ export class FormUpdateService { field.description = nextField.description } + if (nextField.idx !== undefined) { + field.idx = nextField.idx + } + if (nextField.disabled !== undefined) { field.disabled = nextField.disabled } @@ -90,6 +94,9 @@ export class FormUpdateService { if (nextLogic.formula !== undefined) { logic.formula = nextLogic.formula } + if (nextLogic.idx !== undefined) { + logic.idx = nextLogic.idx + } if (nextLogic.action !== undefined) { logic.action = nextLogic.action }