mirror of
https://github.com/VinylDNS/vinyldns
synced 2025-08-31 06:15:49 +00:00
Update
This commit is contained in:
@@ -161,6 +161,17 @@ vinyldns {
|
||||
port=${?API_SERVICE_PORT}
|
||||
}
|
||||
|
||||
api {
|
||||
limits {
|
||||
batchchange-routing-max-items-limit = 100
|
||||
membership-routing-default-max-items = 100
|
||||
membership-routing-max-items-limit = 1000
|
||||
membership-routing-max-groups-list-limit = 3000
|
||||
recordset-routing-default-max-items= 100
|
||||
zone-routing-default-max-items = 100
|
||||
zone-routing-max-items-limit = 100
|
||||
}
|
||||
}
|
||||
|
||||
approved-name-servers = [
|
||||
"172.17.42.1.",
|
||||
|
@@ -76,6 +76,18 @@ crypto {
|
||||
secret = ${?CRYPTO_SECRET}
|
||||
}
|
||||
|
||||
api {
|
||||
limits {
|
||||
batchchange-routing-max-items-limit = 100
|
||||
membership-routing-default-max-items = 100
|
||||
membership-routing-max-items-limit = 1000
|
||||
membership-routing-max-groups-list-limit = 3000
|
||||
recordset-routing-default-max-items= 100
|
||||
zone-routing-default-max-items = 100
|
||||
zone-routing-max-items-limit = 100
|
||||
}
|
||||
}
|
||||
|
||||
http.port = 9001
|
||||
http.port = ${?PORTAL_PORT}
|
||||
|
||||
|
@@ -164,6 +164,17 @@ vinyldns {
|
||||
port=${?API_SERVICE_PORT}
|
||||
}
|
||||
|
||||
api {
|
||||
limits {
|
||||
batchchange-routing-max-items-limit = 100
|
||||
membership-routing-default-max-items = 100
|
||||
membership-routing-max-items-limit = 1000
|
||||
membership-routing-max-groups-list-limit = 3000
|
||||
recordset-routing-default-max-items= 100
|
||||
zone-routing-default-max-items = 100
|
||||
zone-routing-max-items-limit = 100
|
||||
}
|
||||
}
|
||||
|
||||
approved-name-servers = [
|
||||
"172.17.42.1.",
|
||||
|
@@ -611,12 +611,13 @@ class RecordSetService(
|
||||
|
||||
def listFailedRecordSetChanges(
|
||||
authPrincipal: AuthPrincipal,
|
||||
zoneId: Option[String] = None,
|
||||
startFrom: Int= 0,
|
||||
maxItems: Int = 100,
|
||||
maxItems: Int = 100
|
||||
): Result[ListFailedRecordSetChangesResponse] =
|
||||
for {
|
||||
recordSetChangesFailedResults <- recordChangeRepository
|
||||
.listFailedRecordSetChanges(maxItems, startFrom)
|
||||
.listFailedRecordSetChanges(zoneId, maxItems, startFrom)
|
||||
.toResult[ListFailedRecordSetChangesResults]
|
||||
_ <- zoneAccess(recordSetChangesFailedResults.items, authPrincipal).toResult
|
||||
} yield
|
||||
|
@@ -120,6 +120,7 @@ trait RecordSetServiceAlgebra {
|
||||
|
||||
def listFailedRecordSetChanges(
|
||||
authPrincipal: AuthPrincipal,
|
||||
zoneId: Option[String],
|
||||
startFrom: Int,
|
||||
maxItems: Int
|
||||
): Result[ListFailedRecordSetChangesResponse]
|
||||
|
@@ -269,7 +269,7 @@ class RecordSetRoute(
|
||||
}
|
||||
}
|
||||
} ~
|
||||
path("metrics" / "health" / "recordsetchangesfailure") {
|
||||
path("metrics" / "health" / "zones" / Segment / "recordsetchangesfailure") {zoneId =>
|
||||
(get & monitor("Endpoint.listFailedRecordSetChanges")) {
|
||||
parameters("startFrom".as[Int].?(0), "maxItems".as[Int].?(DEFAULT_MAX_ITEMS)) {
|
||||
(startFrom: Int, maxItems: Int) =>
|
||||
@@ -279,7 +279,7 @@ class RecordSetRoute(
|
||||
errorMsg = s"maxItems was $maxItems, maxItems must be between 0 exclusive " +
|
||||
s"and $DEFAULT_MAX_ITEMS inclusive"
|
||||
){
|
||||
authenticateAndExecute(recordSetService.listFailedRecordSetChanges(_, startFrom, maxItems)) {
|
||||
authenticateAndExecute(recordSetService.listFailedRecordSetChanges(_, Some(zoneId), startFrom, maxItems)) {
|
||||
changes =>
|
||||
complete(StatusCodes.OK, changes)
|
||||
}
|
||||
|
@@ -2017,11 +2017,11 @@ class RecordSetServiceSpec
|
||||
|
||||
doReturn(IO.pure(ListFailedRecordSetChangesResults(completeRecordSetChanges)))
|
||||
.when(mockRecordChangeRepo)
|
||||
.listFailedRecordSetChanges(100,0)
|
||||
.listFailedRecordSetChanges(Some(okZone.id),100,0)
|
||||
|
||||
|
||||
val result: ListFailedRecordSetChangesResponse =
|
||||
underTest.listFailedRecordSetChanges(authPrincipal = okAuth).value.unsafeRunSync().toOption.get
|
||||
underTest.listFailedRecordSetChanges(authPrincipal = okAuth,Some(okZone.id)).value.unsafeRunSync().toOption.get
|
||||
|
||||
val changesWithName =
|
||||
ListFailedRecordSetChangesResponse(
|
||||
@@ -2042,11 +2042,11 @@ class RecordSetServiceSpec
|
||||
|
||||
doReturn(IO.pure(ListFailedRecordSetChangesResults(completeRecordSetChanges)))
|
||||
.when(mockRecordChangeRepo)
|
||||
.listFailedRecordSetChanges(3,2)
|
||||
.listFailedRecordSetChanges(Some(okZone.id),3,2)
|
||||
|
||||
|
||||
val result: ListFailedRecordSetChangesResponse =
|
||||
underTest.listFailedRecordSetChanges(authPrincipal = okAuth,2,3).value.unsafeRunSync().toOption.get
|
||||
underTest.listFailedRecordSetChanges(authPrincipal = okAuth,Some(okZone.id),2,3).value.unsafeRunSync().toOption.get
|
||||
|
||||
val changesWithName =
|
||||
ListFailedRecordSetChangesResponse(
|
||||
|
@@ -421,9 +421,6 @@ class RecordSetRoutingSpec
|
||||
|
||||
private val failedChangesWithUserName =
|
||||
List(rsChange1.copy(status = RecordSetChangeStatus.Failed) , rsChange2.copy(status = RecordSetChangeStatus.Failed))
|
||||
private val listFailedRecordSetChangeResponse = ListFailedRecordSetChangesResponse(
|
||||
failedChangesWithUserName,0,0,100
|
||||
)
|
||||
|
||||
class TestService extends RecordSetServiceAlgebra {
|
||||
|
||||
@@ -585,14 +582,17 @@ class RecordSetRoutingSpec
|
||||
|
||||
def listFailedRecordSetChanges(
|
||||
authPrincipal: AuthPrincipal,
|
||||
zoneId:Option[String],
|
||||
startFrom: Int,
|
||||
maxItems: Int
|
||||
): Result[ListFailedRecordSetChangesResponse] = {
|
||||
val outcome = authPrincipal match {
|
||||
case _ => Right(listFailedRecordSetChangeResponse)
|
||||
}
|
||||
outcome.toResult
|
||||
}
|
||||
zoneId match {
|
||||
case Some(zoneNotFound.id) => Left(ZoneNotFoundError(s"$zoneId"))
|
||||
case Some(notAuthorizedZone.id) => Left(NotAuthorizedError("no way"))
|
||||
case _ => authPrincipal match {
|
||||
case _ => Right(ListFailedRecordSetChangesResponse(failedChangesWithUserName,0,startFrom,maxItems))
|
||||
}
|
||||
}}.toResult
|
||||
|
||||
def searchRecordSets(
|
||||
startFrom: Option[String],
|
||||
@@ -942,7 +942,7 @@ class RecordSetRoutingSpec
|
||||
val rsChangeFailed1 = rsChange1.copy(status = RecordSetChangeStatus.Failed)
|
||||
val rsChangeFailed2 = rsChange2.copy(status = RecordSetChangeStatus.Failed)
|
||||
|
||||
Get(s"/metrics/health/recordsetchangesfailure") ~> recordSetRoute ~> check {
|
||||
Get(s"/metrics/health/zones/${okZone.id}/recordsetchangesfailure") ~> recordSetRoute ~> check {
|
||||
val changes = responseAs[ListFailedRecordSetChangesResponse]
|
||||
changes.failedRecordSetChanges.map(_.id) shouldBe List(rsChangeFailed1.id, rsChangeFailed2.id)
|
||||
|
||||
|
@@ -161,6 +161,18 @@ vinyldns {
|
||||
port=${?API_SERVICE_PORT}
|
||||
}
|
||||
|
||||
api {
|
||||
limits {
|
||||
batchchange-routing-max-items-limit = 100
|
||||
membership-routing-default-max-items = 100
|
||||
membership-routing-max-items-limit = 1000
|
||||
membership-routing-max-groups-list-limit = 3000
|
||||
recordset-routing-default-max-items= 100
|
||||
zone-routing-default-max-items = 100
|
||||
zone-routing-max-items-limit = 100
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
approved-name-servers = [
|
||||
"172.17.42.1.",
|
||||
|
@@ -35,7 +35,8 @@ trait RecordChangeRepository extends Repository {
|
||||
|
||||
def getRecordSetChange(zoneId: String, changeId: String): IO[Option[RecordSetChange]]
|
||||
|
||||
def listFailedRecordSetChanges(maxItems: Int = 100,
|
||||
def listFailedRecordSetChanges(zoneId: Option[String],
|
||||
maxItems: Int = 100,
|
||||
startFrom: Int = 0
|
||||
): IO[ListFailedRecordSetChangesResults]
|
||||
|
||||
|
@@ -183,19 +183,19 @@ class MySqlRecordChangeRepositoryIntegrationSpec
|
||||
repo.save(db, ChangeSet(inserts))
|
||||
}
|
||||
saveRecChange.attempt.unsafeRunSync() shouldBe right
|
||||
val result = repo.listFailedRecordSetChanges(10, 0).unsafeRunSync()
|
||||
val result = repo.listFailedRecordSetChanges(Some(okZone.id),10, 0).unsafeRunSync()
|
||||
(result.items should have).length(10)
|
||||
result.maxItems shouldBe 10
|
||||
result.items should contain theSameElementsAs(inserts)
|
||||
|
||||
}
|
||||
|
||||
"return empty for success record changes" in {
|
||||
val inserts = generateInserts(okZone, 10)
|
||||
val saveRecChange = executeWithinTransaction { db: DB =>
|
||||
repo.save(db, ChangeSet(inserts))
|
||||
}
|
||||
saveRecChange.attempt.unsafeRunSync() shouldBe right
|
||||
val result = repo.listFailedRecordSetChanges(5, 0).unsafeRunSync()
|
||||
val result = repo.listFailedRecordSetChanges(Some(okZone.id),5, 0).unsafeRunSync()
|
||||
(result.items should have).length(0)
|
||||
result.items shouldBe List()
|
||||
result.nextId shouldBe 0
|
||||
@@ -215,17 +215,19 @@ class MySqlRecordChangeRepositoryIntegrationSpec
|
||||
repo.save(db, ChangeSet(timeSpaced))
|
||||
}
|
||||
saveRecChange.attempt.unsafeRunSync() shouldBe right
|
||||
val page1 = repo.listFailedRecordSetChanges(2, 0).unsafeRunSync()
|
||||
page1.nextId shouldBe 2
|
||||
val page1 = repo.listFailedRecordSetChanges(Some(okZone.id), 2, 0).unsafeRunSync()
|
||||
println(page1.items)
|
||||
page1.nextId shouldBe 3
|
||||
page1.maxItems shouldBe 2
|
||||
(page1.items should contain).theSameElementsInOrderAs(expectedOrder.take(2))
|
||||
|
||||
val page2 = repo.listFailedRecordSetChanges(2, page1.nextId).unsafeRunSync()
|
||||
page2.nextId shouldBe 4
|
||||
val page2 = repo.listFailedRecordSetChanges(Some(okZone.id), 2, page1.nextId).unsafeRunSync()
|
||||
println(page2.items)
|
||||
page2.nextId shouldBe 6
|
||||
page2.maxItems shouldBe 2
|
||||
(page2.items should contain).theSameElementsInOrderAs(expectedOrder.slice(2, 4))
|
||||
(page2.items should contain).theSameElementsInOrderAs(expectedOrder.slice(3, 5))
|
||||
|
||||
val page3 = repo.listFailedRecordSetChanges(2, page2.nextId).unsafeRunSync()
|
||||
val page3 = repo.listFailedRecordSetChanges(Some(okZone.id), 2, 4).unsafeRunSync()
|
||||
page3.nextId shouldBe 0
|
||||
page3.maxItems shouldBe 2
|
||||
page3.items should contain theSameElementsAs expectedOrder.slice(4, 5)
|
||||
|
@@ -63,6 +63,7 @@ class MySqlRecordChangeRepository
|
||||
sql"""
|
||||
|SELECT data
|
||||
| FROM record_change
|
||||
| WHERE zone_id = {zoneId}
|
||||
| ORDER BY created DESC
|
||||
""".stripMargin
|
||||
|
||||
@@ -170,16 +171,17 @@ class MySqlRecordChangeRepository
|
||||
}
|
||||
}
|
||||
|
||||
def listFailedRecordSetChanges(maxItems: Int, startFrom: Int): IO[ListFailedRecordSetChangesResults] =
|
||||
def listFailedRecordSetChanges(zoneId: Option[String], maxItems: Int, startFrom: Int): IO[ListFailedRecordSetChangesResults] =
|
||||
monitor("repo.RecordChange.listFailedRecordSetChanges") {
|
||||
IO {
|
||||
DB.readOnly { implicit s =>
|
||||
val queryResult = LIST_RECORD_CHANGES
|
||||
.bindByName('zoneId -> zoneId.get)
|
||||
.map(toRecordSetChange)
|
||||
.list()
|
||||
.apply()
|
||||
val failedRecordSetChanges = queryResult.filter(rc => rc.status == RecordSetChangeStatus.Failed).drop(startFrom).take(maxItems)
|
||||
val nextId = if (failedRecordSetChanges.size < maxItems) 0 else startFrom + maxItems
|
||||
val nextId = if (failedRecordSetChanges.size < maxItems) 0 else startFrom + maxItems + 1
|
||||
ListFailedRecordSetChangesResults(failedRecordSetChanges,nextId,startFrom,maxItems)
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,8 @@ case class Meta(
|
||||
defaultTtl: Long,
|
||||
manualBatchChangeReviewEnabled: Boolean,
|
||||
scheduledBatchChangesEnabled: Boolean,
|
||||
portalUrl: String
|
||||
portalUrl: String,
|
||||
maxGroupItemsDisplay: Int
|
||||
)
|
||||
object Meta {
|
||||
def apply(config: Configuration): Meta =
|
||||
@@ -35,6 +36,7 @@ object Meta {
|
||||
config.getOptional[Long]("default-ttl").getOrElse(7200L),
|
||||
config.getOptional[Boolean]("manual-batch-review-enabled").getOrElse(false),
|
||||
config.getOptional[Boolean]("scheduled-changes-enabled").getOrElse(false),
|
||||
config.getOptional[String]("portal.vinyldns.url").getOrElse("http://localhost:9001")
|
||||
config.getOptional[String]("portal.vinyldns.url").getOrElse("http://localhost:9001"),
|
||||
config.getOptional[Int]("api.limits.membership-routing-max-groups-list-limit").getOrElse(3000)
|
||||
)
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
@content = {
|
||||
<!-- PAGE CONTENT -->
|
||||
<div class="right_col" role="main" ng-init="batchChangeLimit = @meta.batchChangeLimit; defaultTtl = @meta.defaultTtl;
|
||||
manualReviewEnabled = @meta.manualBatchChangeReviewEnabled">
|
||||
manualReviewEnabled = @meta.manualBatchChangeReviewEnabled; maxGroupItemsDisplay = @meta.maxGroupItemsDisplay">
|
||||
|
||||
<!-- BREADCRUMB -->
|
||||
<ul class="breadcrumb">
|
||||
@@ -336,7 +336,8 @@
|
||||
<button type="button" id="create-batch-changes-button" class="btn btn-primary" ng-click="submitChange(manualReviewEnabled)">Submit</button>
|
||||
</div>
|
||||
<div ng-if="formStatus=='pendingConfirm'" class="pull-right">
|
||||
<span>{{ confirmationPrompt }}</span>
|
||||
<span ng-if="!batchChangeErrors">{{ confirmationPrompt }}</span>
|
||||
<span ng-if="batchChangeErrors" class="batch-change-error-help">There were errors, please review the highlighted rows and then proceed.</span>
|
||||
<button class="btn btn-default" ng-click="cancelSubmit()">Cancel</button>
|
||||
<button class="btn btn-success" type="submit" ng-click="confirmSubmit(createBatchChangeForm)">Confirm</button>
|
||||
</div>
|
||||
|
@@ -70,53 +70,56 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- START RECORD TABLE -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Records {{ getRecordPageTitle() }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="vinyldns-panel-top">
|
||||
<div class="btn-group">
|
||||
<button id="refresh-records-button" class="btn btn-default" ng-click="refreshRecords()"><span class="fa fa-refresh"></span> Refresh</button>
|
||||
<button id="create-record-button" class="btn btn-default" ng-if="canCreateRecords" ng-click="createRecord(defaultTtl)"><span class="fa fa-plus"></span> Create Record Set</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form class="input-group" ng-submit="refreshRecords()">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button id="record-search-button" type="submit" class="btn btn-primary"><span class="fa fa-search"></span></button>
|
||||
</span>
|
||||
<input id="record-search-text" ng-model="query" type="text" class="form-control" placeholder="Record Name">
|
||||
<!-- START RECORD TABLE -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<span class="panel-title bolder-font-weight">Records</span>
|
||||
</div>
|
||||
<div class="col-md-2 pull-right">
|
||||
<form class="input-group remove-bottom-margin" ng-submit="refreshRecords()">
|
||||
<div class="input-group remove-bottom-margin">
|
||||
<span class="input-group-btn">
|
||||
<button id="record-search-button" type="submit" class="btn btn-primary"><span class="fa fa-search"></span></button>
|
||||
</span>
|
||||
<input id="record-search-text" ng-model="query" type="text" class="form-control" placeholder="Record Name">
|
||||
</div>
|
||||
</form>
|
||||
<div class="dropdown">
|
||||
<a class="record-type-filter-heading force-cursor dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">Filters<i class="fa fa-chevron-down"></i></a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
Record Types
|
||||
<div>
|
||||
<ul class="record-type-filters">
|
||||
<li ng-repeat="recordType in readRecordTypes" style="list-style-type:none;"><input type="checkbox" ng-checked="selectedRecordTypes.indexOf(recordType) != -1" ng-click="toggleCheckedRecordType(recordType)"> {{recordType}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a class="record-type-filter-heading force-cursor dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">Filters<i class="fa fa-chevron-down"></i></a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
Record Types
|
||||
<div>
|
||||
<ul class="record-type-filters">
|
||||
<li ng-repeat="recordType in readRecordTypes" style="list-style-type:none;"><input type="checkbox" ng-checked="selectedRecordTypes.indexOf(recordType) != -1" ng-click="toggleCheckedRecordType(recordType)"> {{recordType}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
Record Owner Group
|
||||
<div>
|
||||
<select class="form-control" id="recordOwnerGroup" ng-model="ownerGroupFilter" ng-options="group.id as group.name for group in groups | orderBy: 'name'" ng-click="$event.stopPropagation();">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
Record Owner Group
|
||||
<div>
|
||||
<select class="form-control" id="recordOwnerGroup" ng-model="ownerGroupFilter" ng-options="group.id as group.name for group in groups | orderBy: 'name'" ng-click="$event.stopPropagation();">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="vinyldns-panel-top">
|
||||
<div class="btn-group">
|
||||
<button id="refresh-records-button" class="btn btn-default" ng-click="refreshRecords()"><span class="fa fa-refresh"></span> Refresh</button>
|
||||
<button id="create-record-button" class="btn btn-default" ng-if="canCreateRecords" ng-click="createRecord(defaultTtl)"><span class="fa fa-plus"></span> Create Record Set</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PAGINATION -->
|
||||
<div class="dataTables_paginate">
|
||||
<div class="dataTables_paginate vinyldns_paginate">
|
||||
<span class="vinyldns_page_number">{{ getRecordPageTitle() }}</span>
|
||||
<ul class="pagination">
|
||||
<li class="paginate_button previous">
|
||||
<a ng-if="prevPageEnabled()" ng-click="prevPage()">Previous</a>
|
||||
@@ -383,7 +386,8 @@
|
||||
|
||||
|
||||
<!-- PAGINATION -->
|
||||
<div class="dataTables_paginate">
|
||||
<div class="dataTables_paginate vinyldns_paginate">
|
||||
<span class="vinyldns_page_number">{{ getRecordPageTitle() }}</span>
|
||||
<ul class="pagination">
|
||||
<li class="paginate_button previous">
|
||||
<a ng-if="prevPageEnabled()" ng-click="prevPage()">Previous</a>
|
||||
|
@@ -59,37 +59,41 @@
|
||||
<!-- START RECORD TABLE -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Records {{ getRecordPageTitle() }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="vinyldns-panel-top">
|
||||
<div class="btn-group">
|
||||
<button id="refresh-records-button" class="btn btn-default" ng-click="refreshRecords()"><span class="fa fa-refresh"></span> Refresh</button>
|
||||
<button id="create-record-button" class="btn btn-default" ng-if="canReadZone && (zoneInfo.accessLevel == 'Delete' || canCreateRecordsViaAcl())" ng-click="createRecord(defaultTtl)"><span class="fa fa-plus"></span> Create Record Set</button>
|
||||
<button id="zone-sync-button" class="btn btn-default mb-control" ng-if="zoneInfo.accessLevel=='Delete'" data-toggle="modal" data-target="#mb-sync"><span class="fa fa-exchange"></span> Sync Zone</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form class="input-group" ng-submit="refreshRecords()">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button id="record-search-button" type="submit" class="btn btn-primary"><span class="fa fa-search"></span></button>
|
||||
</span>
|
||||
<input id="record-search-text" ng-model="query" type="text" class="form-control" placeholder="Record Name">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<span class="panel-title bolder-font-weight">Records</span>
|
||||
</div>
|
||||
<div class="col-md-2 pull-right">
|
||||
<form class="input-group remove-bottom-margin" ng-submit="refreshRecords()">
|
||||
<div class="input-group remove-bottom-margin">
|
||||
<span class="input-group-btn">
|
||||
<button id="record-search-button" type="submit" class="btn btn-primary"><span class="fa fa-search"></span></button>
|
||||
</span>
|
||||
<input id="record-search-text" ng-model="query" type="text" class="form-control" placeholder="Record Name">
|
||||
</div>
|
||||
</form>
|
||||
<div class="dropdown">
|
||||
<a class="record-type-filter-heading force-cursor dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">Filter By Record Type <i class="fa fa-chevron-down"></i></a>
|
||||
<ul class="dropdown-menu record-type-filters" aria-labelledby="dropdownMenu1">
|
||||
<li ng-repeat="recordType in readRecordTypes"><input type="checkbox" ng-checked="selectedRecordTypes.indexOf(recordType) != -1" ng-click="toggleCheckedRecordType(recordType)"> {{recordType}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="vinyldns-panel-top">
|
||||
<div class="btn-group">
|
||||
<button id="refresh-records-button" class="btn btn-default" ng-click="refreshRecords()"><span class="fa fa-refresh"></span> Refresh</button>
|
||||
<button id="create-record-button" class="btn btn-default" ng-if="canReadZone && (zoneInfo.accessLevel == 'Delete' || canCreateRecordsViaAcl())" ng-click="createRecord(defaultTtl)"><span class="fa fa-plus"></span> Create Record Set</button>
|
||||
<button id="zone-sync-button" class="btn btn-default mb-control" ng-if="zoneInfo.accessLevel=='Delete'" data-toggle="modal" data-target="#mb-sync"><span class="fa fa-exchange"></span> Sync Zone</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PAGINATION -->
|
||||
<div class="dataTables_paginate">
|
||||
<div class="dataTables_paginate vinyldns_paginate">
|
||||
<span class="vinyldns_page_number">{{ getRecordPageTitle() }}</span>
|
||||
<ul class="pagination">
|
||||
<li class="paginate_button previous">
|
||||
<a ng-if="prevPageEnabled()" ng-click="prevPage()">Previous</a>
|
||||
@@ -345,18 +349,19 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- PAGINATION -->
|
||||
<div class="dataTables_paginate">
|
||||
<ul class="pagination">
|
||||
<li class="paginate_button previous">
|
||||
<a ng-if="prevPageEnabled()" ng-click="prevPage()">Previous</a>
|
||||
</li>
|
||||
<li class="paginate_button next">
|
||||
<a ng-if="nextPageEnabled()" ng-click="nextPage()">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- END PAGINATION -->
|
||||
<!-- PAGINATION -->
|
||||
<div class="dataTables_paginate vinyldns_paginate">
|
||||
<span class="vinyldns_page_number">{{ getRecordPageTitle() }}</span>
|
||||
<ul class="pagination">
|
||||
<li class="paginate_button previous">
|
||||
<a ng-if="prevPageEnabled()" ng-click="prevPage()">Previous</a>
|
||||
</li>
|
||||
<li class="paginate_button next">
|
||||
<a ng-if="nextPageEnabled()" ng-click="nextPage()">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- END PAGINATION -->
|
||||
|
||||
</div>
|
||||
<div class="panel-footer"></div>
|
||||
|
@@ -13,7 +13,7 @@
|
||||
</h3>
|
||||
|
||||
<!-- START ZONE INFO FORM -->
|
||||
<div>
|
||||
<div ng-init="maxGroupItemsDisplay = @meta.maxGroupItemsDisplay">
|
||||
<form class="form-horizontal">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
|
@@ -40,48 +40,42 @@
|
||||
<!-- SIMPLE DATATABLE -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default" ng-click="resetCurrentZone()" data-toggle="modal"
|
||||
data-target="#zone_connection_modal" id="open-zone-modal-button">
|
||||
<span class="fa fa-arrow-right"></span> Connect
|
||||
</button>
|
||||
<button id="zone-refresh-button" class="btn btn-default" ng-click="refreshZones()">
|
||||
<span class="fa fa-refresh"></span> Refresh
|
||||
</button>
|
||||
</div>
|
||||
<!-- SEARCH BOX -->
|
||||
<div class="pull-right">
|
||||
<form class="input-group" ng-submit="refreshZones()">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button id="zone-search-button" type="submit" class="btn btn-primary btn-left-round">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</span>
|
||||
<input ng-model="query" type="text" class="form-control zone-search-text" placeholder="{{!searchByAdminGroup ? 'Zone Name' : 'Admin Group Name'}}"/>
|
||||
</div>
|
||||
<div class="checkbox pull-right">
|
||||
<label>
|
||||
<div class="row flex">
|
||||
<div class="btn-group col-md-9 flex-1">
|
||||
<button class="btn btn-default" ng-click="resetCurrentZone()" data-toggle="modal" data-target="#zone_connection_modal" id="open-zone-modal-button">
|
||||
<span class="fa fa-arrow-right"></span> Connect
|
||||
</button>
|
||||
<button id="zone-refresh-button" class="btn btn-default" ng-click="refreshZones()">
|
||||
<span class="fa fa-refresh"></span> Refresh
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-3 pull-right">
|
||||
<!-- SEARCH BOX -->
|
||||
<form class="input-group remove-bottom-margin full-width" ng-submit="refreshZones()">
|
||||
<div class="input-group remove-bottom-margin">
|
||||
<span class="input-group-btn">
|
||||
<button id="zone-search-button" type="submit" class="btn btn-primary btn-left-round">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</span>
|
||||
<input ng-model="query" type="text" class="form-control zone-search-text" placeholder="{{!searchByAdminGroup ? 'Zone Name' : 'Admin Group Name'}}"/>
|
||||
</div>
|
||||
</form>
|
||||
<!-- END SEARCH BOX -->
|
||||
<div class="flex">
|
||||
<label class="reduce-font-weight remove-bottom-margin flex-1">
|
||||
<input class="isGroupSearch" type="checkbox" ng-model="searchByAdminGroup" ng-change="refreshZones()"> Search by admin group
|
||||
</label>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="input-group" style="padding-right: 10px;">
|
||||
<div class="ptr-zone-filter">
|
||||
<form action="">
|
||||
<div class="checkbox pull-right">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="includeReverse" ng-true-value="false" ng-false-value="true" ng-change="refreshZones()"> Hide PTR Zones
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
<form action="" class="pull-right flex-1">
|
||||
<div>
|
||||
<label class="reduce-font-weight remove-bottom-margin">
|
||||
<input type="checkbox" ng-model="includeReverse" ng-true-value="false" ng-false-value="true" ng-change="refreshZones()"> Hide PTR Zones
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END SEARCH BOX -->
|
||||
|
||||
</div>
|
||||
<div id="zone-list-table" class="panel-body">
|
||||
<p ng-if="!zonesLoaded">Loading zones...</p>
|
||||
@@ -171,44 +165,39 @@
|
||||
<!-- SIMPLE DATATABLE -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
|
||||
<button id="zone-refresh-button" class="btn btn-default" ng-click="refreshZones()">
|
||||
<span class="fa fa-refresh"></span> Refresh
|
||||
</button>
|
||||
|
||||
<!-- SEARCH BOX -->
|
||||
<div class="pull-right">
|
||||
<form class="input-group" ng-submit="refreshZones()">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button id="all-zones-search-button" type="submit" class="btn btn-primary btn-left-round">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</span>
|
||||
<input ng-model="query" type="text" class="form-control zone-search-text" placeholder="{{!searchByAdminGroup ? 'Zone Name' : 'Admin Group Name'}}"/>
|
||||
</div>
|
||||
<div class="checkbox pull-right">
|
||||
<label>
|
||||
<div class="row flex">
|
||||
<div class="btn-group col-md-9 flex-1">
|
||||
<button id="zone-refresh-button" class="btn btn-default" ng-click="refreshZones()">
|
||||
<span class="fa fa-refresh"></span> Refresh
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-3 pull-right">
|
||||
<!-- SEARCH BOX -->
|
||||
<form class="input-group remove-bottom-margin full-width" ng-submit="refreshZones()">
|
||||
<div class="input-group remove-bottom-margin">
|
||||
<span class="input-group-btn">
|
||||
<button id="all-zones-search-button" type="submit" class="btn btn-primary btn-left-round">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</span>
|
||||
<input ng-model="query" type="text" class="form-control zone-search-text" placeholder="{{!searchByAdminGroup ? 'Zone Name' : 'Admin Group Name'}}"/>
|
||||
</div>
|
||||
</form>
|
||||
<!-- END SEARCH BOX -->
|
||||
<div class="flex">
|
||||
<label class="reduce-font-weight remove-bottom-margin flex-1">
|
||||
<input class="isGroupSearch" type="checkbox" ng-model="searchByAdminGroup" ng-change="refreshZones()"> Search by admin group
|
||||
</label>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="input-group" style="padding-right: 10px;">
|
||||
<div class="ptr-zone-filter">
|
||||
<form action="">
|
||||
<div class="checkbox pull-right">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="includeReverse" ng-true-value="false" ng-false-value="true" ng-change="refreshZones()"> Hide PTR Zones
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
<form action="" class="pull-right flex-1">
|
||||
<div>
|
||||
<label class="reduce-font-weight remove-bottom-margin">
|
||||
<input type="checkbox" ng-model="includeReverse" ng-true-value="false" ng-false-value="true" ng-change="refreshZones()"> Hide PTR Zones
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END SEARCH BOX -->
|
||||
|
||||
</div>
|
||||
<div id="zone-list-table" class="panel-body">
|
||||
<p ng-if="!allZonesLoaded">Loading zones...</p>
|
||||
|
@@ -76,6 +76,18 @@ crypto {
|
||||
secret = ${?CRYPTO_SECRET}
|
||||
}
|
||||
|
||||
api {
|
||||
limits {
|
||||
batchchange-routing-max-items-limit = 100
|
||||
membership-routing-default-max-items = 100
|
||||
membership-routing-max-items-limit = 1000
|
||||
membership-routing-max-groups-list-limit = 3000
|
||||
recordset-routing-default-max-items= 100
|
||||
zone-routing-default-max-items = 100
|
||||
zone-routing-max-items-limit = 100
|
||||
}
|
||||
}
|
||||
|
||||
http.port = 9001
|
||||
http.port = ${?PORTAL_PORT}
|
||||
|
||||
|
@@ -458,10 +458,6 @@ input[type="file"] {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.paginate_left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.vinyldns_page_number {
|
||||
margin-right: 10px;
|
||||
}
|
||||
@@ -570,3 +566,27 @@ input[type="file"] {
|
||||
#set-dropdown-width {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.remove-bottom-margin {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.reduce-font-weight {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.bolder-font-weight{
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-1{
|
||||
flex: 1;
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ angular.module('controller.groups', []).controller('GroupsController', function
|
||||
$scope.hasGroups = false;
|
||||
$scope.query = "";
|
||||
$scope.validEmailDomains= [];
|
||||
$scope.maxGroupItemsDisplay = 3000;
|
||||
|
||||
// Paging status for group sets
|
||||
var groupsPaging = pagingService.getNewPagingParams(100);
|
||||
@@ -203,7 +204,7 @@ angular.module('controller.groups', []).controller('GroupsController', function
|
||||
}
|
||||
|
||||
return groupsService
|
||||
.getGroups($scope.ignoreAccess, $scope.query)
|
||||
.getGroups($scope.ignoreAccess, $scope.query, $scope.maxGroupItemsDisplay)
|
||||
.then(success)
|
||||
.catch(function (error) {
|
||||
handleError(error, 'groupsService::getGroups-failure');
|
||||
|
@@ -85,7 +85,7 @@
|
||||
$.ajax({
|
||||
url: "/api/recordsets?maxItems=100",
|
||||
dataType: "json",
|
||||
data: "recordNameFilter="+request.term+"%25&nameSort=asc",
|
||||
data: {recordNameFilter: request.term, nameSort: $scope.nameSort},
|
||||
success: function( data ) {
|
||||
const recordSearch = JSON.parse(JSON.stringify(data));
|
||||
response($.map(recordSearch.recordSets, function(item) {
|
||||
|
@@ -74,12 +74,12 @@ angular.module('service.groups', [])
|
||||
return $http.delete(url, {headers: utilityService.getCsrfHeader()});
|
||||
};
|
||||
|
||||
this.getGroups = function (ignoreAccess, query) {
|
||||
this.getGroups = function (ignoreAccess, query, maxItems) {
|
||||
if (query == "") {
|
||||
query = null;
|
||||
}
|
||||
var params = {
|
||||
"maxItems": 3000,
|
||||
"maxItems": maxItems,
|
||||
"groupNameFilter": query,
|
||||
"ignoreAccess": ignoreAccess
|
||||
};
|
||||
|
@@ -65,5 +65,13 @@ class MetaSpec extends Specification with Mockito {
|
||||
val config = Map("scheduled-changes-enabled" -> true)
|
||||
Meta(Configuration.from(config)).scheduledBatchChangesEnabled must beTrue
|
||||
}
|
||||
"default to 3000 if membership-routing-max-groups-list-limit is not found" in {
|
||||
val config = Map("vinyldns.version" -> "foo-bar")
|
||||
Meta(Configuration.from(config)).maxGroupItemsDisplay must beEqualTo(3000)
|
||||
}
|
||||
"get the membership-routing-max-groups-list-limit value in config" in {
|
||||
val config = Map("api.limits.membership-routing-max-groups-list-limit" -> 3100)
|
||||
Meta(Configuration.from(config)).maxGroupItemsDisplay must beEqualTo(3100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user