ronantakizawa/codereview-bench huggingface dataset:
Repository: hashicorp/nomad
File: nomad/job_endpoint_test.go (Go)

Code before:

				return fmt.Errorf("expected 8 allocs, got %d:\n%#v", len(allocs), buf.String())
			}
			return nil
		}),
		wait.Timeout(3*time.Second),
		wait.Gap(time.Millisecond*10),
	))

	allocs, _ = srv.State().AllocsByJob(nil, job.Namespace, job.ID, true)
	for _, alloc := range allocs {
		if alloc.Job.Version == 1 && alloc.DeploymentStatus == nil {
			updateFromClient(alloc, true, false)
		}
	}

	t.Log("waiting for successful deployment")
	must.Wait(t, wait.InitialSuccess(
		wait.ErrorFunc(func() error {
			d, err := srv.State().DeploymentByID(nil, dID)
			if err != nil {
				return err
			}
			if d.Status != structs.DeploymentStatusSuccessful {
				return fmt.Errorf("deployment not successful: %+v", d)
			}
			return nil
		}),
		wait.Timeout(3*time.Second),
		wait.Gap(time.Millisecond*10),
	))
}


Review comment (bug):
_WIP_: this is flaky and we're occasionally getting stuck at 7. Haven't worked out exactly why yet but debugging shows that we're mutating the placed canaries when we do, and that's the underlying issue. (cc @pkazmierczak for your thoughts if you have a moment)

Code after:
	sort.Strings(gotCanaryIds)
	must.Eq(t, canaryIDs, gotCanaryIds)
	must.True(t, dstate.Promoted)

	srv.evalBroker.SetEnabled(true)
	t.Log("eval broker unpaused")

	t.Log("waiting for remaining allocs")
	must.Wait(t, wait.InitialSuccess(
		wait.ErrorFunc(func() error {
			allocs, _ = srv.State().AllocsByJob(nil, job.Namespace, job.ID, true)
			if len(allocs) != 8 {
				buf := new(bytes.Buffer)
				for _, alloc := range allocs {
					fmt.Fprintf(buf, "\talloc=%s v=%d status=%s canary=%v\n",
						alloc.ID[:8], alloc.Job.Version, alloc.ClientStatus,
						alloc.DeploymentStatus.Canary)
				}

				return fmt.Errorf("expected 8 allocs, got %d:\n%#v", len(allocs), buf.String())
			}
			return nil
		}),
		wait.Timeout(3*time.Second),
		wait.Gap(time.Millisecond*10),
	))

	allocs, _ = srv.State().AllocsByJob(nil, job.Namespace, job.ID, true)
	for _, alloc := range allocs {
		if alloc.Job.Version == 1 && alloc.DeploymentStatus == nil {
			updateFromClient(alloc, true, false)
		}
	}

	t.Log("waiting for successful deployment")
	must.Wait(t, wait.InitialSuccess(
		wait.ErrorFunc(func() error {
			d, err := srv.State().DeploymentByID(nil, dID)
			if err != nil {
				return err
			}
			if d.Status != structs.DeploymentStatusSuccessful {
				return fmt.Errorf("deployment not successful: %+v", d)
			}
			return nil
		}),
		wait.Timeout(3*time.Second),
		wait.Gap(time.Millisecond*10),
	))

	// ensure dstate hasn't been mutated incorrectly
Repository: hashicorp/nomad
File: nomad/state/state_store_test.go (Go)

Code before:

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000, evals)
		must.NoError(t, err)
		err = state.UpsertEvals(structs.MsgTypeTestSetup, 1001, []*structs.Evaluation{eval3})
		must.NoError(t, err)

		ws := memdb.NewWatchSet()
		out, err := state.EvalsByJob(ws, eval1.Namespace, eval1.JobID)
		must.NoError(t, err)

		sort.Sort(EvalIDSort(evals))
		sort.Sort(EvalIDSort(out))

		must.Eq(t, evals, out)
		must.False(t, watchFired(ws), must.Sprint("watch should not have fired"))
	})

	t.Run("excludes job with matching prefix", func(t *testing.T) {
		state := testStateStore(t)
		eval1 := mock.Eval()
		eval1.JobID = "hello"
		state.UpsertEvals(structs.MsgTypeTestSetup, 1, []*structs.Evaluation{eval1})

		eval2 := mock.Eval()
		eval2.JobID = "hellohello"
		state.UpsertEvals(structs.MsgTypeTestSetup, 2, []*structs.Evaluation{eval2})

		ws := memdb.NewWatchSet()
		evals, err := state.EvalsByJob(ws, structs.DefaultNamespace, "hello")
		must.NoError(t, err)
		must.Len(t, 1, evals)
		must.Eq(t, evals[0].JobID, eval1.JobID)
	})
}

func TestStateStore_Evals(t *testing.T) {
	ci.Parallel(t)

	state := testStateStore(t)
	var evals []*structs.Evaluation

	for i := range 10 {
		eval := mock.Eval()
		evals = append(evals, eval)

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000+uint64(i), []*structs.Evaluation{eval})
		must.NoError(t, err)
	}

	ws := memdb.NewWatchSet()
	iter, err := state.Evals(ws, false)

Review comment (suggestion):
I feel we should check the error return here for completeness.

Code after:

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000, evals)
		must.NoError(t, err)
		err = state.UpsertEvals(structs.MsgTypeTestSetup, 1001, []*structs.Evaluation{eval3})
		must.NoError(t, err)

		ws := memdb.NewWatchSet()
		out, err := state.EvalsByJob(ws, eval1.Namespace, eval1.JobID)
		must.NoError(t, err)

		sort.Sort(EvalIDSort(evals))
		sort.Sort(EvalIDSort(out))

		must.Eq(t, evals, out)
		must.False(t, watchFired(ws), must.Sprint("watch should not have fired"))
	})

	t.Run("excludes job with matching prefix", func(t *testing.T) {
		state := testStateStore(t)
		eval1 := mock.Eval()
		eval1.JobID = "hello"
		must.NoError(t, state.UpsertEvals(structs.MsgTypeTestSetup, 1, []*structs.Evaluation{eval1}))

		eval2 := mock.Eval()
		eval2.JobID = "hellohello"
		must.NoError(t, state.UpsertEvals(structs.MsgTypeTestSetup, 2, []*structs.Evaluation{eval2}))

		ws := memdb.NewWatchSet()
		evals, err := state.EvalsByJob(ws, structs.DefaultNamespace, "hello")
		must.NoError(t, err)
		must.Len(t, 1, evals)
		must.Eq(t, evals[0].JobID, eval1.JobID)
	})
}

func TestStateStore_Evals(t *testing.T) {
	ci.Parallel(t)

	state := testStateStore(t)
	var evals []*structs.Evaluation

	for i := range 10 {
		eval := mock.Eval()
		evals = append(evals, eval)

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000+uint64(i), []*structs.Evaluation{eval})
		must.NoError(t, err)
	}

	ws := memdb.NewWatchSet()
	iter, err := state.Evals(ws, false)
Repository: hashicorp/nomad
File: nomad/state/state_store_test.go (Go)

Code before:
		eval2 := mock.Eval()
		eval2.JobID = eval1.JobID
		eval3 := mock.Eval()
		evals := []*structs.Evaluation{eval1, eval2}

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000, evals)
		must.NoError(t, err)
		err = state.UpsertEvals(structs.MsgTypeTestSetup, 1001, []*structs.Evaluation{eval3})
		must.NoError(t, err)

		ws := memdb.NewWatchSet()
		out, err := state.EvalsByJob(ws, eval1.Namespace, eval1.JobID)
		must.NoError(t, err)

		sort.Sort(EvalIDSort(evals))
		sort.Sort(EvalIDSort(out))

		must.Eq(t, evals, out)
		must.False(t, watchFired(ws), must.Sprint("watch should not have fired"))
	})

	t.Run("excludes job with matching prefix", func(t *testing.T) {
		state := testStateStore(t)
		eval1 := mock.Eval()
		eval1.JobID = "hello"
		state.UpsertEvals(structs.MsgTypeTestSetup, 1, []*structs.Evaluation{eval1})

		eval2 := mock.Eval()
		eval2.JobID = "hellohello"
		state.UpsertEvals(structs.MsgTypeTestSetup, 2, []*structs.Evaluation{eval2})

		ws := memdb.NewWatchSet()
		evals, err := state.EvalsByJob(ws, structs.DefaultNamespace, "hello")
		must.NoError(t, err)
		must.Len(t, 1, evals)
		must.Eq(t, evals[0].JobID, eval1.JobID)
	})
}

func TestStateStore_Evals(t *testing.T) {
	ci.Parallel(t)

	state := testStateStore(t)
	var evals []*structs.Evaluation

	for i := range 10 {
		eval := mock.Eval()
		evals = append(evals, eval)

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000+uint64(i), []*structs.Evaluation{eval})
		must.NoError(t, err)

Review comment (suggestion):
I feel we should check the error return here for completeness.

Code after:
		eval2 := mock.Eval()
		eval2.JobID = eval1.JobID
		eval3 := mock.Eval()
		evals := []*structs.Evaluation{eval1, eval2}

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000, evals)
		must.NoError(t, err)
		err = state.UpsertEvals(structs.MsgTypeTestSetup, 1001, []*structs.Evaluation{eval3})
		must.NoError(t, err)

		ws := memdb.NewWatchSet()
		out, err := state.EvalsByJob(ws, eval1.Namespace, eval1.JobID)
		must.NoError(t, err)

		sort.Sort(EvalIDSort(evals))
		sort.Sort(EvalIDSort(out))

		must.Eq(t, evals, out)
		must.False(t, watchFired(ws), must.Sprint("watch should not have fired"))
	})

	t.Run("excludes job with matching prefix", func(t *testing.T) {
		state := testStateStore(t)
		eval1 := mock.Eval()
		eval1.JobID = "hello"
		must.NoError(t, state.UpsertEvals(structs.MsgTypeTestSetup, 1, []*structs.Evaluation{eval1}))

		eval2 := mock.Eval()
		eval2.JobID = "hellohello"
		must.NoError(t, state.UpsertEvals(structs.MsgTypeTestSetup, 2, []*structs.Evaluation{eval2}))

		ws := memdb.NewWatchSet()
		evals, err := state.EvalsByJob(ws, structs.DefaultNamespace, "hello")
		must.NoError(t, err)
		must.Len(t, 1, evals)
		must.Eq(t, evals[0].JobID, eval1.JobID)
	})
}

func TestStateStore_Evals(t *testing.T) {
	ci.Parallel(t)

	state := testStateStore(t)
	var evals []*structs.Evaluation

	for i := range 10 {
		eval := mock.Eval()
		evals = append(evals, eval)

		err := state.UpsertEvals(structs.MsgTypeTestSetup, 1000+uint64(i), []*structs.Evaluation{eval})
		must.NoError(t, err)
Repository: hashicorp/nomad
File: nomad/state/state_store_test.go (Go)

Code before:
				a2 := mock.Alloc()
				a2.Job = j
				a2.JobID = j.ID
				a2.ClientStatus = structs.AllocClientStatusFailed
				a2.NextAllocation = a.ID

				err = txn.Insert("allocs", a2)
				must.NoError(t, err)

				e := mock.Eval()
				e.JobID = j.ID
				e.Status = structs.EvalStatusComplete
				err = txn.Insert("evals", e)
				must.NoError(t, err)
				return j
			},
			exp: structs.JobStatusDead,
		},
		{
			name: "filters evals with matching job ID prefix",
			setup: func(t *testing.T, txn *txn) *structs.Job {

				j := mock.Job()
				if j.TaskGroups[0].ReschedulePolicy == nil {
					t.Fatal("test job has no reschedule policy")
				}

				e1 := mock.Eval()
				e1.JobID = j.ID
				e1.Status = structs.EvalStatusComplete
				err := txn.Insert("evals", e1)
				must.NoError(t, err)

				e2 := mock.Eval()
				e2.JobID = fmt.Sprintf("%s%s", j.ID, j.ID)
				e2.Status = structs.EvalStatusPending
				err = txn.Insert("evals", e2)
				must.NoError(t, err)
				return j
			},
			exp: structs.JobStatusDead,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			ci.Parallel(t)

			state := testStateStore(t)

			txn := state.db.WriteTxn(0)

Review comment (suggestion):
I think we could use `must.NotNil` if we wanted to save a few lines.

Code after:
				a2.Job = j
				a2.JobID = j.ID
				a2.ClientStatus = structs.AllocClientStatusFailed
				a2.NextAllocation = a.ID

				err = txn.Insert("allocs", a2)
				must.NoError(t, err)

				e := mock.Eval()
				e.JobID = j.ID
				e.Status = structs.EvalStatusComplete
				err = txn.Insert("evals", e)
				must.NoError(t, err)
				return j
			},
			exp: structs.JobStatusDead,
		},
		{
			name: "filters evals with matching job ID prefix",
			setup: func(t *testing.T, txn *txn) *structs.Job {

				j := mock.Job()
				must.NotNil(t, j.TaskGroups[0].ReschedulePolicy)

				e1 := mock.Eval()
				e1.JobID = j.ID
				e1.Status = structs.EvalStatusComplete
				err := txn.Insert("evals", e1)
				must.NoError(t, err)

				e2 := mock.Eval()
				e2.JobID = fmt.Sprintf("%s%s", j.ID, j.ID)
				e2.Status = structs.EvalStatusPending
				err = txn.Insert("evals", e2)
				must.NoError(t, err)
				return j
			},
			exp: structs.JobStatusDead,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			ci.Parallel(t)

			state := testStateStore(t)

			txn := state.db.WriteTxn(0)

			job := tc.setup(t, txn)
Repository: hashicorp/vault
File: ui/mirage/factories/mfa-duo-method.js (JavaScript)

Code before:
/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import { Factory } from 'miragejs';

export default Factory.extend({
  api_hostname: 'api-foobar.duosecurity.com',
  mount_accessor: '',
  name: '', // returned but cannot be set at this time
  // namespace_path: 'root', commented out for testing behavior when this is not present
  pushinfo: '',
  type: 'duo',
  use_passcode: false,
  username_template: '',

  afterCreate(record) {
    if (record.name) {
      console.warn('Endpoint ignored these unrecognized parameters: [name]'); // eslint-disable-line
      record.name = '';
    }
  },
});


Review comment (suggestion):
Thanks for adding this comment! After thinking about this more, I think we should actually mimic the real life behavior here and make this an empty string. Here's the response on root 
```
{
    "algorithm": "SHA1",
    "digits": 6,
    "id": "5d250b5d-3bd5-ba91-908d-daf268d3e294",
    "issuer": "vault",
    "key_size": 20,
    "max_validation_attempts": 5,
    "name": "",
    "namespace_id": "root",
    "namespace_path": "",
    "period": 30,
    "qr_size": 200,
    "skew": 1,
    "type": "totp"
}
```
```suggestion
namespace_path: '', // the root namespace returns an empty string for the path

Code after:
/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import { Factory } from 'miragejs';

export default Factory.extend({
  api_hostname: 'api-foobar.duosecurity.com',
  mount_accessor: '',
  name: '', // returned but cannot be set at this time
  namespace_path: '', // the root namespace returns an empty string for the path
  pushinfo: '',
  type: 'duo',
  use_passcode: false,
  username_template: '',

  afterCreate(record) {
    if (record.name) {
      console.warn('Endpoint ignored these unrecognized parameters: [name]'); // eslint-disable-line
      record.name = '';
    }
  },
});
Repository: hashicorp/vault
File: ui/mirage/factories/mfa-okta-method.js (JavaScript)

Code before:
/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import { Factory } from 'miragejs';

export default Factory.extend({
  base_url: 'okta.com',
  mount_accessor: '',
  name: '', // returned but cannot be set at this time
  namespace_path: 'root',
  org_name: 'dev-foobar',
  type: 'okta',
  username_template: '', // returned but cannot be set at this time

  afterCreate(record) {
    if (record.name) {
      console.warn('Endpoint ignored these unrecognized parameters: [name]'); // eslint-disable-line
      record.name = '';
    }
  },
});


Review comment (suggestion):
```suggestion
  namespace_path: 'admin/',
```


Expanding on my comment above, root technically doesn't return a `namespace_path` and actually does return on `namespace_id` (I think this is why there was confusion during the original implementation, see sample response above) can we update this to be `admin/` (or whatever namespace you'd like 😄 )

Code after:
/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import { Factory } from 'miragejs';

export default Factory.extend({
  base_url: 'okta.com',
  mount_accessor: '',
  name: '', // returned but cannot be set at this time
  namespace_path: 'admin/',
  org_name: 'dev-foobar',
  type: 'okta',
  username_template: '', // returned but cannot be set at this time

  afterCreate(record) {
    if (record.name) {
      console.warn('Endpoint ignored these unrecognized parameters: [name]'); // eslint-disable-line
      record.name = '';
    }
  },
});
Repository: hashicorp/vault
File: ui/app/components/tools/wrap.js (JavaScript)

Code before:

/**
 * @module ToolsWrap
 * ToolsWrap components are components that sys/wrapping/wrap functionality.
 *
 * @example
 * <Tools::Wrap />
 */

export default class ToolsWrap extends Component {
  @service store;
  @service flashMessages;

  @tracked buttonDisabled = false;
  @tracked token = '';
  @tracked wrapTTL = null;
  @tracked wrapData = null;
  @tracked errorMessage = '';
  @tracked showJson = true;

  get startingValue() {
    // must pass the third param called "space" in JSON.stringify to structure object with whitespace
    // otherwise the following codemirror modifier check will pass `this._editor.getValue() !== namedArgs.content` and _setValue will be called.
    // the method _setValue moves the cursor to the beginning of the text field.
    // the effect is that the cursor jumps after the first key input.
    return JSON.stringify({ '': '' }, null, 2);
  }

  get stringifiedWrapData() {
    return this?.wrapData ? stringify([this.wrapData], {}) : this.startingValue;
  }

  @action handleToggle() {
    this.showJson = !this.showJson;
    this.buttonDisabled = false;
  }

  @action
  reset(clearData = true) {
    this.token = '';
    this.errorMessage = '';
    this.wrapTTL = null;
    if (clearData) this.wrapData = null;
  }

  @action
  updateTtl(evt) {
    if (!evt) return;
    this.wrapTTL = evt.enabled ? `${evt.seconds}s` : '30m';
  }


Review comment (suggestion):
I think the white space is a nice UX improvement! Even if users are likely just copying and pasting their data - it's nice to match other instances of this component.

Code after:

/**
 * @module ToolsWrap
 * ToolsWrap components are components that sys/wrapping/wrap functionality.
 *
 * @example
 * <Tools::Wrap />
 */

export default class ToolsWrap extends Component {
  @service store;
  @service flashMessages;

  @tracked hasLintingErrors = false;
  @tracked token = '';
  @tracked wrapTTL = null;
  @tracked wrapData = null;
  @tracked errorMessage = '';
  @tracked showJson = true;

  get startingValue() {
    // must pass the third param called "space" in JSON.stringify to structure object with whitespace
    // otherwise the following codemirror modifier check will pass `this._editor.getValue() !== namedArgs.content` and _setValue will be called.
    // the method _setValue moves the cursor to the beginning of the text field.
    // the effect is that the cursor jumps after the first key input.
    return JSON.stringify({ '': '' }, null, 2);
  }

  get stringifiedWrapData() {
    return this?.wrapData ? stringify([this.wrapData], {}) : this.startingValue;
  }

  @action
  handleToggle() {
    this.showJson = !this.showJson;
    this.hasLintingErrors = false;
  }

  @action
  reset(clearData = true) {
    this.token = '';
    this.errorMessage = '';
    this.wrapTTL = null;
    this.hasLintingErrors = false;
    if (clearData) this.wrapData = null;
  }

  @action
  updateTtl(evt) {
    if (!evt) return;
    this.wrapTTL = evt.enabled ? `${evt.seconds}s` : '30m';
Repository: hashicorp/vault
File: ui/app/components/tools/wrap.js (JavaScript)

Code before:
  @action
  reset(clearData = true) {
    this.token = '';
    this.errorMessage = '';
    this.wrapTTL = null;
    if (clearData) this.wrapData = null;
  }

  @action
  updateTtl(evt) {
    if (!evt) return;
    this.wrapTTL = evt.enabled ? `${evt.seconds}s` : '30m';
  }

  @action
  codemirrorUpdated(val, codemirror) {
    codemirror.performLint();
    this.hasLintingErrors = codemirror?.state.lint.marked?.length > 0;
    if (!this.hasLintingErrors) this.wrapData = JSON.parse(val);
  }

  @action
  async handleSubmit(evt) {
    evt.preventDefault();

    if (this.hasLintingErrors) return;

    const data = this.wrapData;
    const wrapTTL = this.wrapTTL || null;

    try {
      const response = await this.store.adapterFor('tools').toolAction('wrap', data, { wrapTTL });
      this.token = response.wrap_info.token;
      this.flashMessages.success('Wrap was successful.');
    } catch (error) {
      this.errorMessage = errorMessage(error);
    }
  }
}


Review comment (suggestion):
My previous comment may have been confusing, but we don't actually want to prevent submission in this case since the form technically isn't "invalid", what's submitted just may not align with the user expectation so we warn them, but let them submit anyway.

Code after:
  @action
  reset(clearData = true) {
    this.token = '';
    this.errorMessage = '';
    this.wrapTTL = null;
    this.hasLintingErrors = false;
    if (clearData) this.wrapData = null;
  }

  @action
  updateTtl(evt) {
    if (!evt) return;
    this.wrapTTL = evt.enabled ? `${evt.seconds}s` : '30m';
  }

  @action
  codemirrorUpdated(val, codemirror) {
    codemirror.performLint();
    this.hasLintingErrors = codemirror?.state.lint.marked?.length > 0;
    if (!this.hasLintingErrors) this.wrapData = JSON.parse(val);
  }

  @action
  async handleSubmit(evt) {
    evt.preventDefault();

    const data = this.wrapData;
    const wrapTTL = this.wrapTTL || null;

    try {
      const response = await this.store.adapterFor('tools').toolAction('wrap', data, { wrapTTL });
      this.token = response.wrap_info.token;
      this.flashMessages.success('Wrap was successful.');
    } catch (error) {
      this.errorMessage = errorMessage(error);
    }
  }
}
Repository: hashicorp/vault
File: ui/app/models/database/role.js (JavaScript)

Code before:
/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import Model, { attr } from '@ember-data/model';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { getRoleFields } from 'vault/utils/model-helpers/database-helpers';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import { withModelValidations } from 'vault/decorators/model-validations';

const validations = {
  database: [
    {
      validator(model) {
        const { database } = model;
        if (database) return true;
      },
      message: 'Database is required',
    },
  ],
  type: [
    {
      validator(model) {
        const { type } = model;
        if (type) return true;
      },
      message: 'role type is required',
    },
  ],
  username: [
    {
      validator(model) {
        const { type, username } = model;
        if (!type || type === 'dynamic') return true;
        if (username) return true;
      },
      message: 'username is required',
    },
  ],
};
@withModelValidations(validations)
export default class RoleModel extends Model {
  idPrefix = 'role/';


Review comment (refactor):
There is a [built in validator for presence](https://github.com/hashicorp/vault/blob/main/ui/app/utils/model-helpers/validators.js#L15).
```suggestion
    { type: 'presence', message: 'Database is required' },
```

Code after:
/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */
import Model, { attr } from '@ember-data/model';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { getRoleFields } from 'vault/utils/model-helpers/database-helpers';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import { withModelValidations } from 'vault/decorators/model-validations';
const validations = {
  database: [{ type: 'presence', message: 'Database is required.' }],
  type: [{ type: 'presence', message: 'Type is required.' }],
  username: [
    {
      validator(model) {
        const { type, username } = model;
        if (!type || type === 'dynamic') return true;
        if (username) return true;
      },
      message: 'Username is required.',
    },
  ],
};
@withModelValidations(validations)
export default class RoleModel extends Model {
  idPrefix = 'role/';
  @attr('string', { readOnly: true }) backend;
  @attr('string', { label: 'Role name' }) name;
  @attr('array', {
    label: 'Connection name',
    editType: 'searchSelect',
    fallbackComponent: 'string-list',
    models: ['database/connection'],
    selectLimit: 1,
    onlyAllowExisting: true,
    subText: 'The database connection for which credentials will be generated.',
  })
  database;
  @attr('string', {
    label: 'Type of role',
    noDefault: true,
    possibleValues: ['static', 'dynamic'],
  })
  type;
  @attr({