mirror of
https://github.com/google/nomulus
synced 2026-02-08 22:10:28 +00:00
Compare commits
169 Commits
nomulus-20
...
tlds-20240
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4eee7b8c0d | ||
|
|
ecb39d5899 | ||
|
|
42b508427b | ||
|
|
20b5b43501 | ||
|
|
08285f5de7 | ||
|
|
fb4c5b457d | ||
|
|
781c212275 | ||
|
|
c73f7a6bd3 | ||
|
|
8d793b2349 | ||
|
|
55d5f8c6f8 | ||
|
|
9006312253 | ||
|
|
e5e2370923 | ||
|
|
b3b0efd47e | ||
|
|
e82cbe60a9 | ||
|
|
923bc13e3a | ||
|
|
4893ea307b | ||
|
|
01f868cefc | ||
|
|
1b0919eaff | ||
|
|
92b23bac16 | ||
|
|
cc9b3f5965 | ||
|
|
dd86c56ddc | ||
|
|
08551f7bc7 | ||
|
|
e7171a326b | ||
|
|
c3eae7b76f | ||
|
|
2687181045 | ||
|
|
68750569db | ||
|
|
028e5cc958 | ||
|
|
853e571d01 | ||
|
|
9b79f5af2c | ||
|
|
4195871541 | ||
|
|
504d7ccaac | ||
|
|
36a8908712 | ||
|
|
e42c11051e | ||
|
|
85b588b51f | ||
|
|
572b7101cb | ||
|
|
445825957d | ||
|
|
7ab76f3573 | ||
|
|
9e3c58989a | ||
|
|
cf9c1ec7c3 | ||
|
|
69ea87be31 | ||
|
|
779d0c9d37 | ||
|
|
2855944214 | ||
|
|
992d1c1349 | ||
|
|
f50290ce1d | ||
|
|
e647d4e215 | ||
|
|
08471242df | ||
|
|
cd23fea698 | ||
|
|
ba54208dad | ||
|
|
b5e131ecba | ||
|
|
87e99f59bc | ||
|
|
30accea383 | ||
|
|
72e0101746 | ||
|
|
3090df9a78 | ||
|
|
7332b1fa38 | ||
|
|
9330e3a50d | ||
|
|
1d6b119340 | ||
|
|
8158f761c8 | ||
|
|
08838e091f | ||
|
|
59720a207d | ||
|
|
26bae65e1e | ||
|
|
23a2861b37 | ||
|
|
341238305d | ||
|
|
d210bed744 | ||
|
|
fe710e5510 | ||
|
|
8f8ffe7020 | ||
|
|
16e5018489 | ||
|
|
af303bd26f | ||
|
|
bf3bb5d804 | ||
|
|
dcb16e05bd | ||
|
|
2facedd60f | ||
|
|
b1ec81f054 | ||
|
|
779da518df | ||
|
|
4f53ae0e89 | ||
|
|
da04caeea2 | ||
|
|
a63916b08e | ||
|
|
36bd508bf9 | ||
|
|
bbdbfe85ed | ||
|
|
2a7e9a266a | ||
|
|
bd0d8af7b3 | ||
|
|
2da8ea0185 | ||
|
|
7a84844000 | ||
|
|
1580555d30 | ||
|
|
4fb8a1b50b | ||
|
|
e07f25000d | ||
|
|
cc1777af0c | ||
|
|
87e54c001f | ||
|
|
2dc87d42b4 | ||
|
|
1eed9c82dc | ||
|
|
cf43de7755 | ||
|
|
f54bec7553 | ||
|
|
cf698c2586 | ||
|
|
cb240a8f03 | ||
|
|
0801679173 | ||
|
|
a87c4a31a3 | ||
|
|
58c7e3a52c | ||
|
|
dded258864 | ||
|
|
759143535f | ||
|
|
46fdf2c996 | ||
|
|
fc1857717d | ||
|
|
e182692a5f | ||
|
|
a65e85f9e1 | ||
|
|
2713a10a07 | ||
|
|
5eb44c165c | ||
|
|
6c18ea9cff | ||
|
|
43692d3409 | ||
|
|
38b73b9ecd | ||
|
|
954537291f | ||
|
|
9434d01234 | ||
|
|
3dafaff2c0 | ||
|
|
ca25e4dfbd | ||
|
|
6047c16f3e | ||
|
|
1248c25041 | ||
|
|
001e9363a1 | ||
|
|
9a6a7116da | ||
|
|
335af52112 | ||
|
|
1929654f8c | ||
|
|
6b5ec36eed | ||
|
|
ebf07833e5 | ||
|
|
ee3ece8c56 | ||
|
|
57592d787c | ||
|
|
e6f9b1c7e6 | ||
|
|
7b59c4abbf | ||
|
|
f01adfb060 | ||
|
|
739a15851d | ||
|
|
2c961b6283 | ||
|
|
bcb2b2c784 | ||
|
|
a91ed0f1ad | ||
|
|
da28a2021c | ||
|
|
ffd952a60e | ||
|
|
97676d1a1f | ||
|
|
1dcbc9e0cb | ||
|
|
f59c387b9c | ||
|
|
cfcafeefc6 | ||
|
|
c32d831dd6 | ||
|
|
b38e0efe9a | ||
|
|
67cb411c99 | ||
|
|
9f551eb552 | ||
|
|
655f05c58c | ||
|
|
95c810ddf4 | ||
|
|
ec9a220bc3 | ||
|
|
68d35d2d95 | ||
|
|
99840488a1 | ||
|
|
ee7c8fb018 | ||
|
|
c6f62dcffd | ||
|
|
ee66805d2e | ||
|
|
d7a3c0c439 | ||
|
|
45666773ee | ||
|
|
b8b5152336 | ||
|
|
0f6302e92b | ||
|
|
e594bd13a1 | ||
|
|
00051dbc0f | ||
|
|
aab89fb816 | ||
|
|
6ea548a35d | ||
|
|
733e9a4a6a | ||
|
|
10d28efa1c | ||
|
|
1e0a0cf29e | ||
|
|
0c824fed5a | ||
|
|
4aa1bd0856 | ||
|
|
f5839777d1 | ||
|
|
43d325d2a5 | ||
|
|
9b17adcb28 | ||
|
|
9873772150 | ||
|
|
342051e11d | ||
|
|
5f5cb8df9f | ||
|
|
311d5ac9b6 | ||
|
|
3403399f38 | ||
|
|
7a386c4577 | ||
|
|
dfc7947a2f | ||
|
|
c33d2cb0b8 |
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -29,6 +29,12 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Java version
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -31,6 +31,7 @@ tmp/
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.DS_Store
|
||||
|
||||
# Eclipse Core
|
||||
.project
|
||||
@@ -78,6 +79,7 @@ autogenerated/
|
||||
**/*.iml
|
||||
nomulus.ipr
|
||||
nomulus.iws
|
||||
**/classpath.index
|
||||
|
||||
# Auto-generated java classes by Intellij
|
||||
*/src/main/generated/
|
||||
|
||||
28
build.gradle
28
build.gradle
@@ -37,8 +37,10 @@ buildscript {
|
||||
|
||||
plugins {
|
||||
// Java static analysis plugins. Keep versions consistent with
|
||||
// ./buildSrc/build.gradle
|
||||
id 'nebula.lint' version '16.0.2'
|
||||
// ./buildSrc/build.gradle.kts
|
||||
|
||||
// Re-enable when compatible with Gradle 8
|
||||
// id 'nebula.lint' version '16.0.2'
|
||||
id 'net.ltgt.errorprone' version '2.0.2'
|
||||
id 'checkstyle'
|
||||
id 'com.github.johnrengelman.shadow' version '5.1.0'
|
||||
@@ -47,7 +49,7 @@ plugins {
|
||||
id "com.github.node-gradle.node" version "3.0.1"
|
||||
|
||||
id 'idea'
|
||||
id 'com.diffplug.gradle.spotless' version '3.25.0'
|
||||
id 'com.diffplug.spotless' version '6.20.0'
|
||||
|
||||
id 'jacoco'
|
||||
id 'com.dorongold.task-tree' version '2.1.0'
|
||||
@@ -58,9 +60,8 @@ dependencyLocking {
|
||||
}
|
||||
|
||||
node {
|
||||
download = true
|
||||
version = "16.14.0"
|
||||
npmVersion = "6.14.11"
|
||||
download = false
|
||||
version = "16.19.0"
|
||||
}
|
||||
|
||||
wrapper {
|
||||
@@ -110,7 +111,8 @@ tasks.build.dependsOn(tasks.checkLicense)
|
||||
// Provide defaults for all of the project properties.
|
||||
|
||||
// Only do linting if the build is successful.
|
||||
gradleLint.autoLintAfterFailure = false
|
||||
// Re-enable when compatible with Gradle 8
|
||||
// gradleLint.autoLintAfterFailure = false
|
||||
|
||||
// Paths to main and test sources.
|
||||
ext.projectRootDir = "${rootDir}"
|
||||
@@ -207,8 +209,8 @@ allprojects {
|
||||
gradle.projectsEvaluated {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.fork = true
|
||||
options.forkOptions.javaHome =
|
||||
file("${System.env.REAL_JAVA_HOME}")
|
||||
options.forkOptions.executable =
|
||||
file("${System.env.JAVA_HOME}/bin/javac")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,14 +271,14 @@ subprojects {
|
||||
project.tasks.create(
|
||||
taskName, com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
|
||||
mergeServiceFiles()
|
||||
baseName = binaryName
|
||||
archiveBaseName = binaryName
|
||||
if (mainClass != '') {
|
||||
manifest {
|
||||
attributes 'Main-Class': mainClass
|
||||
}
|
||||
}
|
||||
zip64 = true
|
||||
classifier = ''
|
||||
archiveClassifier = ''
|
||||
archiveVersion = ''
|
||||
configurations = configs
|
||||
from srcOutput
|
||||
@@ -345,6 +347,7 @@ subprojects {
|
||||
|
||||
def services = [':services:default',
|
||||
':services:backend',
|
||||
':services:bsa',
|
||||
':services:tools',
|
||||
':services:pubapi']
|
||||
|
||||
@@ -516,7 +519,6 @@ task javaIncrementalFormatCheck {
|
||||
println("Omitting format check: not in a git directory.")
|
||||
}
|
||||
}
|
||||
dependsOn('console-webapp:checkFormatting')
|
||||
}
|
||||
|
||||
// Shows how modified lines in Java source files will change after formatting.
|
||||
@@ -534,7 +536,6 @@ task javaIncrementalFormatApply {
|
||||
doLast {
|
||||
invokeJavaDiffFormatScript("format")
|
||||
}
|
||||
dependsOn('console-webapp:applyFormatting')
|
||||
}
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
@@ -561,6 +562,7 @@ tasks.build.dependsOn(tasks.javadoc)
|
||||
// core Nomulus codebase, and runs all presubmits.
|
||||
task coreDev {
|
||||
dependsOn 'javaIncrementalFormatApply'
|
||||
dependsOn 'console-webapp:applyFormatting'
|
||||
dependsOn 'javadoc'
|
||||
dependsOn 'checkDependenciesDotGradle'
|
||||
dependsOn 'checkLicense'
|
||||
|
||||
@@ -32,10 +32,13 @@ buildscript {
|
||||
|
||||
plugins {
|
||||
// Java static analysis plugins. Keep versions consistent with ../build.gradle
|
||||
// id("nebula.lint") version "16.0.2" // unsupported for kotlin
|
||||
|
||||
// We don't anticipate enabling the Gradle lint plugin because they will not support Kotlin
|
||||
// See https://github.com/nebula-plugins/gradle-lint-plugin/issues/166
|
||||
// id 'nebula.lint' version '16.0.2'
|
||||
id("net.ltgt.errorprone") version "2.0.2"
|
||||
checkstyle
|
||||
id("com.diffplug.gradle.spotless") version "3.25.0"
|
||||
id("com.diffplug.spotless") version "6.20.0"
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
@@ -84,12 +87,8 @@ project.the<SourceSetContainer>()["main"].java {
|
||||
srcDir("${project.buildDir}/generated/source/apt/main")
|
||||
}
|
||||
|
||||
// checkstyle {
|
||||
// configDir file("../config/checkstyle")
|
||||
// }
|
||||
|
||||
dependencies {
|
||||
val deps = project.ext["dependencyMap"] as Map<String, String>
|
||||
val deps = project.ext["dependencyMap"] as Map<*, *>
|
||||
val implementation by configurations
|
||||
val testImplementation by configurations
|
||||
val annotationProcessor by configurations
|
||||
@@ -119,13 +118,6 @@ gradle.projectsEvaluated {
|
||||
}
|
||||
|
||||
tasks.register("exportDependencies") {
|
||||
val outputFileProperty = "dependencyExportFile"
|
||||
val output = if (project.hasProperty(outputFileProperty)) {
|
||||
PrintStream(file(project.ext.properties[outputFileProperty]))
|
||||
} else {
|
||||
System.out
|
||||
}
|
||||
|
||||
doLast {
|
||||
project.configurations.forEach {
|
||||
println("dependency is $it")
|
||||
|
||||
@@ -4,21 +4,26 @@
|
||||
com.diffplug.durian:durian-collect:1.2.0=classpath
|
||||
com.diffplug.durian:durian-core:1.2.0=classpath
|
||||
com.diffplug.durian:durian-io:1.2.0=classpath
|
||||
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.25.0=classpath
|
||||
com.diffplug.spotless:spotless-lib-extra:1.25.0=classpath
|
||||
com.diffplug.spotless:spotless-lib:1.25.0=classpath
|
||||
com.diffplug.spotless:spotless-plugin-gradle:3.25.0=classpath
|
||||
com.diffplug.durian:durian-swt.os:4.2.0=classpath
|
||||
com.diffplug.spotless:com.diffplug.spotless.gradle.plugin:6.20.0=classpath
|
||||
com.diffplug.spotless:spotless-lib-extra:2.40.0=classpath
|
||||
com.diffplug.spotless:spotless-lib:2.40.0=classpath
|
||||
com.diffplug.spotless:spotless-plugin-gradle:6.20.0=classpath
|
||||
com.googlecode.concurrent-trees:concurrent-trees:2.6.1=classpath
|
||||
com.googlecode.javaewah:JavaEWAH:1.1.6=classpath
|
||||
com.jcraft:jsch:0.1.55=classpath
|
||||
com.jcraft:jzlib:1.1.1=classpath
|
||||
com.googlecode.javaewah:JavaEWAH:1.2.3=classpath
|
||||
com.squareup.okhttp3:okhttp:4.10.0=classpath
|
||||
com.squareup.okio:okio-jvm:3.0.0=classpath
|
||||
com.squareup.okio:okio:3.0.0=classpath
|
||||
dev.equo.ide:solstice:1.3.1=classpath
|
||||
net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:2.0.2=classpath
|
||||
net.ltgt.gradle:gradle-errorprone-plugin:2.0.2=classpath
|
||||
org.bouncycastle:bcpg-jdk15on:1.61=classpath
|
||||
org.bouncycastle:bcpkix-jdk15on:1.61=classpath
|
||||
org.bouncycastle:bcprov-jdk15on:1.61=classpath
|
||||
org.codehaus.groovy:groovy-xml:2.4.7=classpath
|
||||
org.codehaus.groovy:groovy:2.4.7=classpath
|
||||
org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r=classpath
|
||||
org.slf4j:slf4j-api:1.7.2=classpath
|
||||
org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r=classpath
|
||||
org.eclipse.platform:org.eclipse.osgi:3.18.300=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.9.0=classpath
|
||||
org.jetbrains:annotations:13.0=classpath
|
||||
org.slf4j:slf4j-api:1.7.36=classpath
|
||||
org.tukaani:xz:1.9=classpath
|
||||
empty=
|
||||
|
||||
@@ -1,148 +1,110 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
antlr:antlr:2.7.7=checkstyle
|
||||
aopalliance:aopalliance:1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
args4j:args4j:2.0.23=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.14.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson:jackson-bom:2.14.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0=annotationProcessor,testAnnotationProcessor
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.android:annotations:4.1.1.4=testRuntimeClasspath
|
||||
com.google.api-client:google-api-client:2.2.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-common-protos:2.20.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.15.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:api-common:2.12.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-grpc:2.29.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:0.114.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.29.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20230617-2.0.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.17.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.17.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.10.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto.value:auto-value:1.10.2=annotationProcessor
|
||||
com.google.auto:auto-common:0.10=annotationProcessor,testAnnotationProcessor
|
||||
com.google.cloud:google-cloud-core-grpc:2.19.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.19.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core:2.19.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-storage:2.23.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.10.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.common.html.types:types:1.0.6=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.18.0=compileClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.19.1=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor,checkstyle,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.3.4=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4=annotationProcessor,testAnnotationProcessor
|
||||
com.google.escapevelocity:escapevelocity:0.9.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,checkstyle,compileClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:guava:27.0.1-jre=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:29.0-jre=checkstyle
|
||||
com.google.guava:guava:32.1.1-jre=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,testAnnotationProcessor
|
||||
com.google.http-client:google-http-client-apache-v2:1.43.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:1.43.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-gson:1.43.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-jackson2:1.43.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:1.43.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.inject.extensions:guice-multibindings:4.1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.inject:guice:4.1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:1.3=checkstyle
|
||||
com.google.j2objc:j2objc-annotations:2.8=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.oauth-client:google-oauth-client:1.34.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:3.23.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:3.23.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.re2j:re2j:1.7=testRuntimeClasspath
|
||||
com.google.template:soy:2021-02-01=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.truth.extensions:truth-java8-extension:1.1.3=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.truth:truth:1.1.5=testCompileClasspath,testRuntimeClasspath
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0=annotationProcessor,testAnnotationProcessor
|
||||
com.ibm.icu:icu4j:57.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.puppycrawl.tools:checkstyle:8.37=checkstyle
|
||||
commons-beanutils:commons-beanutils:1.9.4=checkstyle
|
||||
commons-codec:commons-codec:1.15=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
commons-logging:commons-logging:1.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
info.picocli:picocli:4.5.2=checkstyle
|
||||
io.grpc:grpc-alts:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-api:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-auth:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-context:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-core:1.56.0=testRuntimeClasspath
|
||||
io.grpc:grpc-googleapis:1.56.0=testRuntimeClasspath
|
||||
io.grpc:grpc-grpclb:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-netty-shaded:1.56.0=testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf-lite:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-rls:1.56.0=testRuntimeClasspath
|
||||
io.grpc:grpc-services:1.56.0=testRuntimeClasspath
|
||||
io.grpc:grpc-stub:1.56.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-xds:1.56.0=testRuntimeClasspath
|
||||
io.opencensus:opencensus-api:0.31.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opencensus:opencensus-contrib-http-util:0.31.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opencensus:opencensus-proto:0.2.0=testRuntimeClasspath
|
||||
io.perfmark:perfmark-api:0.26.0=testRuntimeClasspath
|
||||
javax.annotation:javax.annotation-api:1.3.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
javax.annotation:jsr250-api:1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
javax.inject:javax.inject:1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.12.19=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.12.19=testCompileClasspath,testRuntimeClasspath
|
||||
net.sf.saxon:Saxon-HE:10.3=checkstyle
|
||||
org.antlr:antlr4-runtime:4.8-1=checkstyle
|
||||
org.apache.commons:commons-lang3:3.12.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.commons:commons-text:1.10.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.httpcomponents:httpclient:4.5.14=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.httpcomponents:httpcore:4.4.16=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
|
||||
org.checkerframework:checker-qual:2.11.1=checkstyle
|
||||
org.checkerframework:checker-qual:3.0.0=annotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.33.0=compileClasspath
|
||||
org.checkerframework:checker-qual:3.35.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.checkerframework:dataflow:3.0.0=annotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:javacutil:3.0.0=annotationProcessor,testAnnotationProcessor
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,testAnnotationProcessor
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.23=testRuntimeClasspath
|
||||
org.conscrypt:conscrypt-openjdk-uber:2.5.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
|
||||
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
|
||||
org.javassist:javassist:3.26.0-GA=checkstyle
|
||||
org.json:json:20160212=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:5.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:4.11.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-commons:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-tree:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-util:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:7.0=compileClasspath
|
||||
org.ow2.asm:asm:9.1=jacocoAnt
|
||||
org.ow2.asm:asm:9.5=testCompileClasspath,testRuntimeClasspath
|
||||
org.pcollections:pcollections:2.1.2=annotationProcessor,testAnnotationProcessor
|
||||
org.plumelib:plume-util:1.0.6=annotationProcessor,testAnnotationProcessor
|
||||
org.plumelib:reflection-util:0.0.2=annotationProcessor,testAnnotationProcessor
|
||||
org.plumelib:require-javadoc:0.1.0=annotationProcessor,testAnnotationProcessor
|
||||
org.reflections:reflections:0.9.12=checkstyle
|
||||
org.threeten:threetenbp:1.6.8=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
aopalliance:aopalliance:1.0=buildScriptClasspath,compileClasspath
|
||||
args4j:args4j:2.0.23=buildScriptClasspath,compileClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.14.2=buildScriptClasspath,compileClasspath
|
||||
com.fasterxml.jackson:jackson-bom:2.14.2=buildScriptClasspath,compileClasspath
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0=annotationProcessor
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor
|
||||
com.google.android:annotations:4.1.1.4=buildScriptClasspath
|
||||
com.google.api-client:google-api-client:2.2.0=buildScriptClasspath,compileClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.22.6-alpha=buildScriptClasspath,compileClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.22.6-alpha=buildScriptClasspath,compileClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-v2:2.22.6-alpha=buildScriptClasspath,compileClasspath
|
||||
com.google.api.grpc:proto-google-common-protos:2.22.0=buildScriptClasspath,compileClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.17.0=buildScriptClasspath,compileClasspath
|
||||
com.google.api:api-common:2.14.0=buildScriptClasspath,compileClasspath
|
||||
com.google.api:gax-grpc:2.31.0=buildScriptClasspath,compileClasspath
|
||||
com.google.api:gax-httpjson:2.31.0=buildScriptClasspath,compileClasspath
|
||||
com.google.api:gax:2.31.0=buildScriptClasspath,compileClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20230301-2.0.0=buildScriptClasspath,compileClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.19.0=buildScriptClasspath,compileClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.19.0=buildScriptClasspath,compileClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.10.1=buildScriptClasspath,compileClasspath
|
||||
com.google.auto.value:auto-value:1.10.4=annotationProcessor
|
||||
com.google.auto:auto-common:0.10=annotationProcessor
|
||||
com.google.cloud:google-cloud-core-grpc:2.21.0=buildScriptClasspath,compileClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.21.0=buildScriptClasspath,compileClasspath
|
||||
com.google.cloud:google-cloud-core:2.21.0=buildScriptClasspath,compileClasspath
|
||||
com.google.cloud:google-cloud-storage:2.22.6=buildScriptClasspath,compileClasspath
|
||||
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,buildScriptClasspath,compileClasspath
|
||||
com.google.code.gson:gson:2.10.1=buildScriptClasspath,compileClasspath
|
||||
com.google.common.html.types:types:1.0.6=buildScriptClasspath,compileClasspath
|
||||
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.18.0=buildScriptClasspath,compileClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor
|
||||
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.3.4=annotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4=annotationProcessor
|
||||
com.google.escapevelocity:escapevelocity:0.9.1=buildScriptClasspath,compileClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,buildScriptClasspath,compileClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=buildScriptClasspath,compileClasspath
|
||||
com.google.guava:guava:27.0.1-jre=annotationProcessor
|
||||
com.google.guava:guava:32.1.1-jre=buildScriptClasspath,compileClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor
|
||||
com.google.http-client:google-http-client-apache-v2:1.43.3=buildScriptClasspath,compileClasspath
|
||||
com.google.http-client:google-http-client-appengine:1.43.3=buildScriptClasspath,compileClasspath
|
||||
com.google.http-client:google-http-client-gson:1.43.3=buildScriptClasspath,compileClasspath
|
||||
com.google.http-client:google-http-client-jackson2:1.43.3=buildScriptClasspath,compileClasspath
|
||||
com.google.http-client:google-http-client:1.43.3=buildScriptClasspath,compileClasspath
|
||||
com.google.inject.extensions:guice-multibindings:4.1.0=buildScriptClasspath,compileClasspath
|
||||
com.google.inject:guice:4.1.0=buildScriptClasspath,compileClasspath
|
||||
com.google.j2objc:j2objc-annotations:1.1=annotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:2.8=buildScriptClasspath,compileClasspath
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.1=buildScriptClasspath,compileClasspath
|
||||
com.google.oauth-client:google-oauth-client:1.34.1=buildScriptClasspath,compileClasspath
|
||||
com.google.protobuf:protobuf-java-util:3.23.2=buildScriptClasspath,compileClasspath
|
||||
com.google.protobuf:protobuf-java:3.23.2=buildScriptClasspath,compileClasspath
|
||||
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor
|
||||
com.google.re2j:re2j:1.6=buildScriptClasspath
|
||||
com.google.template:soy:2021-02-01=buildScriptClasspath,compileClasspath
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0=annotationProcessor
|
||||
com.ibm.icu:icu4j:57.1=buildScriptClasspath,compileClasspath
|
||||
commons-codec:commons-codec:1.15=buildScriptClasspath,compileClasspath
|
||||
commons-logging:commons-logging:1.2=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-alts:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-api:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-auth:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-context:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-core:1.55.3=buildScriptClasspath
|
||||
io.grpc:grpc-googleapis:1.55.3=buildScriptClasspath
|
||||
io.grpc:grpc-grpclb:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-netty-shaded:1.55.3=buildScriptClasspath
|
||||
io.grpc:grpc-protobuf-lite:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-protobuf:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-rls:1.55.3=buildScriptClasspath
|
||||
io.grpc:grpc-services:1.55.3=buildScriptClasspath
|
||||
io.grpc:grpc-stub:1.55.3=buildScriptClasspath,compileClasspath
|
||||
io.grpc:grpc-xds:1.55.3=buildScriptClasspath
|
||||
io.opencensus:opencensus-api:0.31.1=buildScriptClasspath,compileClasspath
|
||||
io.opencensus:opencensus-contrib-http-util:0.31.1=buildScriptClasspath,compileClasspath
|
||||
io.opencensus:opencensus-proto:0.2.0=buildScriptClasspath
|
||||
io.perfmark:perfmark-api:0.26.0=buildScriptClasspath
|
||||
javax.annotation:javax.annotation-api:1.3.2=buildScriptClasspath,compileClasspath
|
||||
javax.annotation:jsr250-api:1.0=buildScriptClasspath,compileClasspath
|
||||
javax.inject:javax.inject:1=buildScriptClasspath,compileClasspath
|
||||
org.apache.commons:commons-lang3:3.12.0=buildScriptClasspath,compileClasspath
|
||||
org.apache.commons:commons-text:1.10.0=buildScriptClasspath,compileClasspath
|
||||
org.apache.httpcomponents:httpclient:4.5.14=buildScriptClasspath,compileClasspath
|
||||
org.apache.httpcomponents:httpcore:4.4.16=buildScriptClasspath,compileClasspath
|
||||
org.checkerframework:checker-qual:3.0.0=annotationProcessor
|
||||
org.checkerframework:checker-qual:3.33.0=buildScriptClasspath,compileClasspath
|
||||
org.checkerframework:dataflow:3.0.0=annotationProcessor
|
||||
org.checkerframework:javacutil:3.0.0=annotationProcessor
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.23=buildScriptClasspath
|
||||
org.conscrypt:conscrypt-openjdk-uber:2.5.2=buildScriptClasspath,compileClasspath
|
||||
org.json:json:20160212=buildScriptClasspath,compileClasspath
|
||||
org.ow2.asm:asm-analysis:7.0=buildScriptClasspath,compileClasspath
|
||||
org.ow2.asm:asm-commons:7.0=buildScriptClasspath,compileClasspath
|
||||
org.ow2.asm:asm-tree:7.0=buildScriptClasspath,compileClasspath
|
||||
org.ow2.asm:asm-util:7.0=buildScriptClasspath,compileClasspath
|
||||
org.ow2.asm:asm:7.0=buildScriptClasspath,compileClasspath
|
||||
org.pcollections:pcollections:2.1.2=annotationProcessor
|
||||
org.plumelib:plume-util:1.0.6=annotationProcessor
|
||||
org.plumelib:reflection-util:0.0.2=annotationProcessor
|
||||
org.plumelib:require-javadoc:0.1.0=annotationProcessor
|
||||
org.threeten:threetenbp:1.6.8=buildScriptClasspath,compileClasspath
|
||||
empty=
|
||||
|
||||
@@ -143,7 +143,7 @@ public class ReportUploader extends DefaultTask {
|
||||
.getAsMap()
|
||||
.forEach(
|
||||
(type, report) -> {
|
||||
File destination = report.getDestination();
|
||||
File destination = report.getOutputLocation().get().getAsFile();
|
||||
// The destination could be a file, or a directory. If it's a directory - the Report
|
||||
// could have created multiple files - and we need to know to which one of those to
|
||||
// link.
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
com.diffplug.durian:durian-collect:1.2.0=classpath
|
||||
com.diffplug.durian:durian-core:1.2.0=classpath
|
||||
com.diffplug.durian:durian-io:1.2.0=classpath
|
||||
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.25.0=classpath
|
||||
com.diffplug.spotless:spotless-lib-extra:1.25.0=classpath
|
||||
com.diffplug.spotless:spotless-lib:1.25.0=classpath
|
||||
com.diffplug.spotless:spotless-plugin-gradle:3.25.0=classpath
|
||||
com.diffplug.durian:durian-swt.os:4.2.0=classpath
|
||||
com.diffplug.spotless:com.diffplug.spotless.gradle.plugin:6.20.0=classpath
|
||||
com.diffplug.spotless:spotless-lib-extra:2.40.0=classpath
|
||||
com.diffplug.spotless:spotless-lib:2.40.0=classpath
|
||||
com.diffplug.spotless:spotless-plugin-gradle:6.20.0=classpath
|
||||
com.dorongold.plugins:task-tree:2.1.0=classpath
|
||||
com.dorongold.task-tree:com.dorongold.task-tree.gradle.plugin:2.1.0=classpath
|
||||
com.github.jengelman.gradle.plugins:shadow:5.1.0=classpath
|
||||
@@ -24,56 +25,39 @@ com.google.guava:guava:28.2-jre=classpath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=classpath
|
||||
com.google.j2objc:j2objc-annotations:1.3=classpath
|
||||
com.googlecode.concurrent-trees:concurrent-trees:2.6.1=classpath
|
||||
com.googlecode.javaewah:JavaEWAH:1.1.6=classpath
|
||||
com.jcraft:jsch:0.1.55=classpath
|
||||
com.jcraft:jzlib:1.1.1=classpath
|
||||
com.netflix.nebula:gradle-lint-plugin:16.0.2=classpath
|
||||
com.netflix.nebula:nebula-gradle-interop:1.0.11=classpath
|
||||
com.googlecode.javaewah:JavaEWAH:1.2.3=classpath
|
||||
com.squareup.okhttp3:okhttp:4.10.0=classpath
|
||||
com.squareup.okio:okio-jvm:3.0.0=classpath
|
||||
com.squareup.okio:okio:3.0.0=classpath
|
||||
commons-io:commons-io:2.6=classpath
|
||||
commons-lang:commons-lang:2.6=classpath
|
||||
javax.inject:javax.inject:1=classpath
|
||||
junit:junit:4.12=classpath
|
||||
nebula.lint:nebula.lint.gradle.plugin:16.0.2=classpath
|
||||
dev.equo.ide:solstice:1.3.1=classpath
|
||||
net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:2.0.2=classpath
|
||||
net.ltgt.gradle:gradle-errorprone-plugin:2.0.2=classpath
|
||||
org.apache.ant:ant-launcher:1.9.7=classpath
|
||||
org.apache.ant:ant:1.9.7=classpath
|
||||
org.apache.commons:commons-compress:1.20=classpath
|
||||
org.apache.commons:commons-lang3:3.8.1=classpath
|
||||
org.apache.maven:maven-artifact:3.6.2=classpath
|
||||
org.apache.maven:maven-builder-support:3.6.2=classpath
|
||||
org.apache.maven:maven-model-builder:3.6.2=classpath
|
||||
org.apache.maven:maven-model:3.6.2=classpath
|
||||
org.bouncycastle:bcpg-jdk15on:1.61=classpath
|
||||
org.bouncycastle:bcpkix-jdk15on:1.61=classpath
|
||||
org.bouncycastle:bcprov-jdk15on:1.61=classpath
|
||||
org.apache.commons:commons-lang3:3.5=classpath
|
||||
org.checkerframework:checker-qual:2.10.0=classpath
|
||||
org.codehaus.gpars:gpars:1.2.1=classpath
|
||||
org.codehaus.groovy:groovy-xml:2.4.7=classpath
|
||||
org.codehaus.groovy:groovy:2.4.7=classpath
|
||||
org.codehaus.jsr166-mirror:jsr166y:1.7.0=classpath
|
||||
org.codehaus.plexus:plexus-interpolation:1.25=classpath
|
||||
org.codehaus.plexus:plexus-utils:3.2.1=classpath
|
||||
org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r=classpath
|
||||
org.eclipse.sisu:org.eclipse.sisu.inject:0.3.3=classpath
|
||||
org.codehaus.plexus:plexus-utils:3.0.24=classpath
|
||||
org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r=classpath
|
||||
org.eclipse.platform:org.eclipse.osgi:3.18.300=classpath
|
||||
org.glassfish:javax.json:1.0.4=classpath
|
||||
org.hamcrest:hamcrest-core:1.3=classpath
|
||||
org.jdom:jdom2:2.0.6=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.3.50=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.6.20=classpath
|
||||
org.jetbrains:annotations:13.0=classpath
|
||||
org.multiverse:multiverse-core:0.7.0=classpath
|
||||
org.ow2.asm:asm-analysis:7.1=classpath
|
||||
org.ow2.asm:asm-commons:7.1=classpath
|
||||
org.ow2.asm:asm-tree:7.1=classpath
|
||||
org.ow2.asm:asm:7.1=classpath
|
||||
org.slf4j:slf4j-api:1.7.2=classpath
|
||||
org.ow2.asm:asm-analysis:7.0-beta=classpath
|
||||
org.ow2.asm:asm-commons:7.0-beta=classpath
|
||||
org.ow2.asm:asm-tree:7.0-beta=classpath
|
||||
org.ow2.asm:asm:7.0-beta=classpath
|
||||
org.slf4j:slf4j-api:1.7.36=classpath
|
||||
org.sonatype.aether:aether-api:1.13.1=classpath
|
||||
org.sonatype.aether:aether-impl:1.13.1=classpath
|
||||
org.sonatype.aether:aether-spi:1.13.1=classpath
|
||||
org.sonatype.aether:aether-util:1.13.1=classpath
|
||||
org.tukaani:xz:1.9=classpath
|
||||
org.vafer:jdependency:2.1.1=classpath
|
||||
org.yaml:snakeyaml:1.21=classpath
|
||||
empty=
|
||||
|
||||
@@ -1,70 +1,69 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
antlr:antlr:2.7.7=checkstyle
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:2.9.3=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.github.ben-manes.caffeine:caffeine:2.9.3=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.8.1=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.10.1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.auto:auto-common:0.10=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,default,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.18.0=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.19.1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.7.1=checkstyle
|
||||
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.flogger:flogger:0.7.4=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,checkstyle,compileClasspath,default,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.flogger:flogger:0.7.4=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,checkstyle,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.guava:guava-parent:32.1.2-jre=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:guava:27.0.1-jre=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:29.0-jre=checkstyle
|
||||
com.google.guava:guava:32.1.1-jre=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:31.0.1-jre=checkstyle
|
||||
com.google.guava:guava:32.1.2-jre=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:1.3=checkstyle
|
||||
com.google.j2objc:j2objc-annotations:2.8=compileClasspath,testCompileClasspath,testingCompileClasspath
|
||||
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.truth:truth:1.1.3=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.truth:truth:1.1.5=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.puppycrawl.tools:checkstyle:8.37=checkstyle
|
||||
com.puppycrawl.tools:checkstyle:9.3=checkstyle
|
||||
commons-beanutils:commons-beanutils:1.9.4=checkstyle
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
info.picocli:picocli:4.5.2=checkstyle
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
javax.inject:javax.inject:1=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
joda-time:joda-time:2.12.5=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
junit:junit:4.13.2=default,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
net.sf.saxon:Saxon-HE:10.3=checkstyle
|
||||
org.antlr:antlr4-runtime:4.8-1=checkstyle
|
||||
info.picocli:picocli:4.6.2=checkstyle
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
javax.inject:javax.inject:1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
joda-time:joda-time:2.12.5=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
net.sf.saxon:Saxon-HE:10.6=checkstyle
|
||||
org.antlr:antlr4-runtime:4.9.3=checkstyle
|
||||
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
|
||||
org.checkerframework:checker-compat-qual:2.5.3=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.checkerframework:checker-qual:2.11.1=checkstyle
|
||||
org.checkerframework:checker-compat-qual:2.5.3=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.checkerframework:checker-qual:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.33.0=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.checkerframework:checker-qual:3.12.0=checkstyle
|
||||
org.checkerframework:checker-qual:3.35.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.checkerframework:dataflow:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.checkerframework:javacutil:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.hamcrest:hamcrest-core:1.3=default,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
|
||||
org.javassist:javassist:3.26.0-GA=checkstyle
|
||||
org.junit.jupiter:junit-jupiter-api:5.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.10.0-RC1=testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.jacoco:org.jacoco.agent:0.8.9=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.9=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.9=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.9=jacocoAnt
|
||||
org.javassist:javassist:3.28.0-GA=checkstyle
|
||||
org.junit.jupiter:junit-jupiter-api:5.10.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.10.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.10.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.10.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.10.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-commons:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.1=jacocoAnt
|
||||
org.ow2.asm:asm:9.1=compileClasspath,default,deploy_jar,jacocoAnt,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.ow2.asm:asm-commons:9.5=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.5=jacocoAnt
|
||||
org.ow2.asm:asm:9.5=compileClasspath,deploy_jar,jacocoAnt,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.pcollections:pcollections:2.1.2=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.plumelib:plume-util:1.0.6=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.plumelib:reflection-util:0.0.2=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.plumelib:require-javadoc:0.1.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.reflections:reflections:0.9.12=checkstyle
|
||||
empty=archives,errorproneJavac,testingCompile,testingRuntime,testingRuntimeClasspath
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
empty=errorproneJavac,testingCompile,testingRuntime,testingRuntimeClasspath
|
||||
|
||||
@@ -109,13 +109,6 @@ PRESUBMITS = {
|
||||
"System.(out|err).println is only allowed in tools/ packages. Please "
|
||||
"use a logger instead.",
|
||||
|
||||
# PostgreSQLContainer instantiation must specify docker tag
|
||||
# TODO(b/204572437): Fix the pattern to pass DatabaseSnapshotTest.java
|
||||
PresubmitCheck(
|
||||
r"[\s\S]*new\s+PostgreSQLContainer(<[\s\S]*>)?\(\s*\)[\s\S]*",
|
||||
"java", {"DatabaseSnapshotTest.java"}):
|
||||
"PostgreSQLContainer instantiation must specify docker tag.",
|
||||
|
||||
# Various Soy linting checks
|
||||
PresubmitCheck(
|
||||
r".* (/\*)?\* {?@param ",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "less"
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
@@ -22,15 +22,18 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "less",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.less"
|
||||
"src/theme.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["node_modules/"]
|
||||
},
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
@@ -38,8 +41,8 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "1mb"
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
@@ -91,15 +94,18 @@
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"inlineStyleLanguage": "less",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.less"
|
||||
"src/theme.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["node_modules/"]
|
||||
},
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -66,3 +66,4 @@ tasks.runConsoleWebappUnitTests.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.buildConsoleWebappProd.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.applyFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.checkFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.build.dependsOn(tasks.checkFormatting)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
"/console-api":
|
||||
{
|
||||
"target": "http://localhost:8080",
|
||||
"secure": true
|
||||
"secure": false,
|
||||
"logLevel": "debug",
|
||||
"changeOrigin": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,47 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
antlr:antlr:2.7.7=checkstyle
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.auto:auto-common:0.10=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.7.1=checkstyle
|
||||
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor
|
||||
com.google.guava:guava:27.0.1-jre=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.guava:guava:29.0-jre=checkstyle
|
||||
com.google.guava:guava:31.0.1-jre=checkstyle
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:1.3=checkstyle
|
||||
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.puppycrawl.tools:checkstyle:8.37=checkstyle
|
||||
com.puppycrawl.tools:checkstyle:9.3=checkstyle
|
||||
commons-beanutils:commons-beanutils:1.9.4=checkstyle
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
info.picocli:picocli:4.5.2=checkstyle
|
||||
net.sf.saxon:Saxon-HE:10.3=checkstyle
|
||||
org.antlr:antlr4-runtime:4.8-1=checkstyle
|
||||
org.checkerframework:checker-qual:2.11.1=checkstyle
|
||||
info.picocli:picocli:4.6.2=checkstyle
|
||||
net.sf.saxon:Saxon-HE:10.6=checkstyle
|
||||
org.antlr:antlr4-runtime:4.9.3=checkstyle
|
||||
org.checkerframework:checker-qual:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.12.0=checkstyle
|
||||
org.checkerframework:dataflow:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.checkerframework:javacutil:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
|
||||
org.javassist:javassist:3.26.0-GA=checkstyle
|
||||
org.ow2.asm:asm-analysis:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-commons:9.1=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.1=jacocoAnt
|
||||
org.ow2.asm:asm:9.1=jacocoAnt
|
||||
org.jacoco:org.jacoco.agent:0.8.9=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.9=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.9=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.9=jacocoAnt
|
||||
org.javassist:javassist:3.28.0-GA=checkstyle
|
||||
org.ow2.asm:asm-commons:9.5=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.5=jacocoAnt
|
||||
org.ow2.asm:asm:9.5=jacocoAnt
|
||||
org.pcollections:pcollections:2.1.2=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.plumelib:plume-util:1.0.6=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.plumelib:reflection-util:0.0.2=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.plumelib:require-javadoc:0.1.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.reflections:reflections:0.9.12=checkstyle
|
||||
empty=archives,compileClasspath,default,deploy_jar,errorproneJavac,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
empty=compileClasspath,deploy_jar,errorproneJavac,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
|
||||
12293
console-webapp/package-lock.json
generated
12293
console-webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"start": "ng serve --proxy-config dev-proxy.config.json",
|
||||
"build": "ng build --base-href=/console/",
|
||||
"build:local": "ng build --base-href=/default/console/",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
|
||||
@@ -18,51 +18,61 @@ import { TldsComponent } from './tlds/tlds.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { SettingsComponent } from './settings/settings.component';
|
||||
import SettingsContactComponent from './settings/contact/contact.component';
|
||||
import SettingsRegistrarsComponent from './settings/registrars/registrars.component';
|
||||
import SettingsWhoisComponent from './settings/whois/whois.component';
|
||||
import SettingsUsersComponent from './settings/users/users.component';
|
||||
import SettingsSecurityComponent from './settings/security/security.component';
|
||||
import { RegistrarGuard } from './registrar/registrar.guard';
|
||||
import { RegistrarComponent } from './registrar/registrar.component';
|
||||
import { RegistrarComponent } from './registrar/registrarsTable.component';
|
||||
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
|
||||
import ContactComponent from './settings/contact/contact.component';
|
||||
import WhoisComponent from './settings/whois/whois.component';
|
||||
import SecurityComponent from './settings/security/security.component';
|
||||
import UsersComponent from './settings/users/users.component';
|
||||
import { DomainListComponent } from './domains/domainList.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||
{ path: 'registrars', component: RegistrarComponent },
|
||||
{ path: 'empty-registrar', component: EmptyRegistrar },
|
||||
{ path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] },
|
||||
{ path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] },
|
||||
{
|
||||
path: 'settings',
|
||||
component: SettingsComponent,
|
||||
path: DomainListComponent.PATH,
|
||||
component: DomainListComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: SettingsComponent.PATH,
|
||||
component: SettingsComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'contact',
|
||||
redirectTo: 'registrars',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
path: ContactComponent.PATH,
|
||||
component: SettingsContactComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'whois',
|
||||
path: WhoisComponent.PATH,
|
||||
component: SettingsWhoisComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'security',
|
||||
path: SecurityComponent.PATH,
|
||||
component: SettingsSecurityComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'epp-password',
|
||||
component: SettingsSecurityComponent,
|
||||
},
|
||||
{
|
||||
path: 'users',
|
||||
path: UsersComponent.PATH,
|
||||
component: SettingsUsersComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'registrars',
|
||||
component: SettingsRegistrarsComponent,
|
||||
path: RegistrarComponent.PATH,
|
||||
component: RegistrarComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="console-app">
|
||||
<app-header (toggleNavOpen)="sidenav.toggle()"></app-header>
|
||||
<mat-sidenav-container class="console-app__content-wrapper">
|
||||
<mat-sidenav-container class="console-app__container">
|
||||
<mat-sidenav #sidenav class="console-app__sidebar">
|
||||
<mat-nav-list>
|
||||
<a mat-list-item [routerLink]="'/home'" routerLinkActive="active">
|
||||
@@ -12,13 +12,15 @@
|
||||
<a mat-list-item [routerLink]="'/settings'" routerLinkActive="active">
|
||||
Settings
|
||||
</a>
|
||||
<a mat-list-item [routerLink]="'/registrars'" routerLinkActive="active">
|
||||
Select Registrar
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content class="console-app__content">
|
||||
<router-outlet></router-outlet>
|
||||
<mat-sidenav-content class="console-app__content-wrapper">
|
||||
<div *ngIf="globalLoader.isLoading" class="console-app__global-spinner">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div class="console-app__content" *ngIf="renderRouter">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
</div>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
:host {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
|
||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-family: Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
|
||||
"Segoe UI Emoji", "Segoe UI Symbol" !important;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
@@ -26,7 +26,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
&__content-wrapper {
|
||||
&__container {
|
||||
flex: 1;
|
||||
margin-top: -12px;
|
||||
padding-bottom: 36px;
|
||||
@@ -37,10 +37,17 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
.active {
|
||||
background: #eae1e1;
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
}
|
||||
&__content {
|
||||
&__content-wrapper {
|
||||
margin: 12px 24px;
|
||||
}
|
||||
&__content {
|
||||
max-width: 1340px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&__global-spinner {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,13 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from './material.module';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
imports: [RouterTestingModule, MaterialModule, BrowserAnimationsModule],
|
||||
declarations: [AppComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
@@ -12,11 +12,43 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||
import { RegistrarService } from './registrar/registrar.service';
|
||||
import { UserDataService } from './shared/services/userData.service';
|
||||
import { GlobalLoaderService } from './shared/services/globalLoader.service';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { MatSidenav } from '@angular/material/sidenav';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.less'],
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent {}
|
||||
export class AppComponent implements AfterViewInit {
|
||||
renderRouter: boolean = true;
|
||||
|
||||
@ViewChild('sidenav')
|
||||
sidenav!: MatSidenav;
|
||||
|
||||
constructor(
|
||||
protected registrarService: RegistrarService,
|
||||
protected userDataService: UserDataService,
|
||||
protected globalLoader: GlobalLoaderService,
|
||||
protected router: Router
|
||||
) {
|
||||
registrarService.activeRegistrarIdChange.subscribe(() => {
|
||||
this.renderRouter = false;
|
||||
setTimeout(() => {
|
||||
this.renderRouter = true;
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.router.events.subscribe((event) => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
this.sidenav.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,29 +31,75 @@ import SettingsContactComponent, {
|
||||
ContactDetailsDialogComponent,
|
||||
} from './settings/contact/contact.component';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { RegistrarComponent } from './registrar/registrar.component';
|
||||
import { RegistrarComponent } from './registrar/registrarsTable.component';
|
||||
import { RegistrarGuard } from './registrar/registrar.guard';
|
||||
import SecurityComponent from './settings/security/security.component';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
|
||||
import { RegistrarSelectorComponent } from './registrar/registrarSelector.component';
|
||||
import { GlobalLoaderService } from './shared/services/globalLoader.service';
|
||||
import { ContactWidgetComponent } from './home/widgets/contactWidget.component';
|
||||
import { PromotionsWidgetComponent } from './home/widgets/promotionsWidget.component';
|
||||
import { TldsWidgetComponent } from './home/widgets/tldsWidget.component';
|
||||
import { ResourcesWidgetComponent } from './home/widgets/resourcesWidget.component';
|
||||
import { EppWidgetComponent } from './home/widgets/eppWidget.component';
|
||||
import { BillingWidgetComponent } from './home/widgets/billingWidget.component';
|
||||
import { DomainsWidgetComponent } from './home/widgets/domainsWidget.component';
|
||||
import { SettingsWidgetComponent } from './home/widgets/settingsWidget.component';
|
||||
import { UserDataService } from './shared/services/userData.service';
|
||||
import WhoisComponent from './settings/whois/whois.component';
|
||||
import { SnackBarModule } from './snackbar.module';
|
||||
import { RegistrarDetailsComponent } from './registrar/registrarDetails.component';
|
||||
import { DomainListComponent } from './domains/domainList.component';
|
||||
import { DialogBottomSheetWrapper } from './shared/components/dialogBottomSheet.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HomeComponent,
|
||||
TldsComponent,
|
||||
DialogBottomSheetWrapper,
|
||||
BillingWidgetComponent,
|
||||
ContactDetailsDialogComponent,
|
||||
ContactWidgetComponent,
|
||||
DomainListComponent,
|
||||
DomainsWidgetComponent,
|
||||
EmptyRegistrar,
|
||||
EppWidgetComponent,
|
||||
HeaderComponent,
|
||||
HomeComponent,
|
||||
PromotionsWidgetComponent,
|
||||
RegistrarComponent,
|
||||
RegistrarDetailsComponent,
|
||||
RegistrarSelectorComponent,
|
||||
ResourcesWidgetComponent,
|
||||
SecurityComponent,
|
||||
SettingsComponent,
|
||||
SettingsContactComponent,
|
||||
ContactDetailsDialogComponent,
|
||||
RegistrarComponent,
|
||||
SettingsWidgetComponent,
|
||||
TldsComponent,
|
||||
TldsWidgetComponent,
|
||||
WhoisComponent,
|
||||
],
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
FormsModule,
|
||||
MaterialModule,
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
MaterialModule,
|
||||
SnackBarModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
GlobalLoaderService,
|
||||
RegistrarGuard,
|
||||
UserDataService,
|
||||
{
|
||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
useValue: {
|
||||
subscriptSizing: 'dynamic',
|
||||
},
|
||||
},
|
||||
],
|
||||
providers: [BackendService, RegistrarGuard],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
60
console-webapp/src/app/domains/domainList.component.html
Normal file
60
console-webapp/src/app/domains/domainList.component.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<div class="console-domains">
|
||||
<mat-form-field>
|
||||
<mat-label>Filter</mat-label>
|
||||
<input
|
||||
type="search"
|
||||
matInput
|
||||
[(ngModel)]="searchTerm"
|
||||
(ngModelChange)="sendInput()"
|
||||
#input
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<div *ngIf="isLoading; else domains_content" class="console-domains__loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<ng-template #domains_content>
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="domainName">
|
||||
<th mat-header-cell *matHeaderCellDef>Domain Name</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.domainName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="creationTime">
|
||||
<th mat-header-cell *matHeaderCellDef>Creation Time</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
{{ element.creationTime.creationTime }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="registrationExpirationTime">
|
||||
<th mat-header-cell *matHeaderCellDef>Expiration Time</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
{{ element.registrationExpirationTime }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="statuses">
|
||||
<th mat-header-cell *matHeaderCellDef>Statuses</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.statuses }}</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
|
||||
<!-- Row shown when there is no matching data. -->
|
||||
<tr class="mat-row" *matNoDataRow>
|
||||
<td class="mat-cell" colspan="4">No domains found</td>
|
||||
</tr>
|
||||
</table>
|
||||
<mat-paginator
|
||||
[length]="totalResults"
|
||||
[pageIndex]="pageNumber"
|
||||
[pageSize]="resultsPerPage"
|
||||
[pageSizeOptions]="[10, 25, 50, 100, 500]"
|
||||
(page)="onPageChange($event)"
|
||||
aria-label="Select page of domain results"
|
||||
showFirstLastButtons
|
||||
></mat-paginator>
|
||||
</ng-template>
|
||||
</div>
|
||||
@@ -14,18 +14,18 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import RegistrarsComponent from './registrars.component';
|
||||
import { DomainListComponent } from './domainList.component';
|
||||
|
||||
describe('RegistrarsComponent', () => {
|
||||
let component: RegistrarsComponent;
|
||||
let fixture: ComponentFixture<RegistrarsComponent>;
|
||||
describe('DomainListComponent', () => {
|
||||
let component: DomainListComponent;
|
||||
let fixture: ComponentFixture<DomainListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RegistrarsComponent],
|
||||
declarations: [DomainListComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RegistrarsComponent);
|
||||
fixture = TestBed.createComponent(DomainListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
98
console-webapp/src/app/domains/domainList.component.ts
Normal file
98
console-webapp/src/app/domains/domainList.component.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
import { Domain, DomainListService } from './domainList.service';
|
||||
import { Subject, debounceTime } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-domain-list',
|
||||
templateUrl: './domainList.component.html',
|
||||
styleUrls: ['./domainList.component.scss'],
|
||||
providers: [DomainListService],
|
||||
})
|
||||
export class DomainListComponent {
|
||||
public static PATH = 'domain-list';
|
||||
private readonly DEBOUNCE_MS = 500;
|
||||
|
||||
displayedColumns: string[] = [
|
||||
'domainName',
|
||||
'creationTime',
|
||||
'registrationExpirationTime',
|
||||
'statuses',
|
||||
];
|
||||
|
||||
dataSource: MatTableDataSource<Domain> = new MatTableDataSource();
|
||||
isLoading = true;
|
||||
|
||||
searchTermSubject = new Subject<string>();
|
||||
searchTerm?: string;
|
||||
|
||||
pageNumber?: number;
|
||||
resultsPerPage = 50;
|
||||
totalResults?: number;
|
||||
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
|
||||
constructor(
|
||||
private backendService: BackendService,
|
||||
private domainListService: DomainListService,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
// Don't spam the server unnecessarily while the user is typing
|
||||
this.searchTermSubject
|
||||
.pipe(debounceTime(this.DEBOUNCE_MS))
|
||||
.subscribe((searchTermValue) => {
|
||||
this.reloadData();
|
||||
});
|
||||
this.reloadData();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.searchTermSubject.complete();
|
||||
}
|
||||
|
||||
reloadData() {
|
||||
this.isLoading = true;
|
||||
this.domainListService
|
||||
.retrieveDomains(
|
||||
this.pageNumber,
|
||||
this.resultsPerPage,
|
||||
this.totalResults,
|
||||
this.searchTerm
|
||||
)
|
||||
.subscribe((domainListResult) => {
|
||||
this.dataSource.data = domainListResult.domains;
|
||||
this.totalResults = domainListResult.totalResults;
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
sendInput() {
|
||||
this.searchTermSubject.next(this.searchTerm!);
|
||||
}
|
||||
|
||||
onPageChange(event: PageEvent) {
|
||||
this.pageNumber = event.pageIndex;
|
||||
this.resultsPerPage = event.pageSize;
|
||||
this.reloadData();
|
||||
}
|
||||
}
|
||||
68
console-webapp/src/app/domains/domainList.service.ts
Normal file
68
console-webapp/src/app/domains/domainList.service.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
import { tap } from 'rxjs';
|
||||
|
||||
export interface CreateAutoTimestamp {
|
||||
creationTime: string;
|
||||
}
|
||||
|
||||
export interface Domain {
|
||||
creationTime: CreateAutoTimestamp;
|
||||
currentSponsorRegistrarId: string;
|
||||
domainName: string;
|
||||
registrationExpirationTime: string;
|
||||
statuses: string[];
|
||||
}
|
||||
|
||||
export interface DomainListResult {
|
||||
checkpointTime: string;
|
||||
domains: Domain[];
|
||||
totalResults: number;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DomainListService {
|
||||
checkpointTime?: string;
|
||||
|
||||
constructor(
|
||||
private backendService: BackendService,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
retrieveDomains(
|
||||
pageNumber?: number,
|
||||
resultsPerPage?: number,
|
||||
totalResults?: number,
|
||||
searchTerm?: string
|
||||
) {
|
||||
return this.backendService
|
||||
.getDomains(
|
||||
this.registrarService.activeRegistrarId,
|
||||
this.checkpointTime,
|
||||
pageNumber,
|
||||
resultsPerPage,
|
||||
totalResults,
|
||||
searchTerm
|
||||
)
|
||||
.pipe(
|
||||
tap((domainListResult: DomainListResult) => {
|
||||
this.checkpointTime = domainListResult.checkpointTime;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,30 @@
|
||||
<p>
|
||||
<p class="console-app__header">
|
||||
<mat-toolbar color="primary">
|
||||
<button mat-icon-button aria-label="Open menu" (click)="toggleNavPane()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<span>Google Registry</span>
|
||||
<a
|
||||
[routerLink]="'/home'"
|
||||
routerLinkActive="active"
|
||||
class="console-app__logo"
|
||||
>
|
||||
Google Registry
|
||||
</a>
|
||||
<span class="spacer"></span>
|
||||
<app-registrar-selector />
|
||||
<button mat-icon-button aria-label="Open FAQ">
|
||||
<mat-icon>question_mark</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button aria-label="Open user info">
|
||||
<button
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="menu"
|
||||
#menuTrigger
|
||||
aria-label="Open user info"
|
||||
>
|
||||
<mat-icon>person</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="logOut()">Log out</button>
|
||||
</mat-menu>
|
||||
</mat-toolbar>
|
||||
</p>
|
||||
|
||||
38
console-webapp/src/app/header/header.component.scss
Normal file
38
console-webapp/src/app/header/header.component.scss
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
.console-app {
|
||||
&__logo {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
&__header {
|
||||
@media (max-width: 599px) {
|
||||
.mat-toolbar {
|
||||
padding: 0;
|
||||
}
|
||||
.console-app__logo {
|
||||
font-size: 16px;
|
||||
}
|
||||
button {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HeaderComponent } from './header.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from '../material.module';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
@@ -22,6 +24,7 @@ describe('HeaderComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
declarations: [HeaderComponent],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Component, EventEmitter, Output } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.less'],
|
||||
styleUrls: ['./header.component.scss'],
|
||||
})
|
||||
export class HeaderComponent {
|
||||
private isNavOpen = false;
|
||||
@@ -28,4 +28,8 @@ export class HeaderComponent {
|
||||
this.isNavOpen = !this.isNavOpen;
|
||||
this.toggleNavOpen.emit(this.isNavOpen);
|
||||
}
|
||||
|
||||
logOut() {
|
||||
window.open('/console?gcp-iap-mode=CLEAR_LOGIN_COOKIE', '_self');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
<h3>Recent Activity</h3>
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
class="mat-elevation-z8 console-home__activity"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="let column of columns"
|
||||
[matColumnDef]="column.columnDef"
|
||||
>
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ column.cell(row) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
<div class="console-app__home">
|
||||
<h1>Welcome to the Google Registry Console</h1>
|
||||
<div class="console-app__home-widgets">
|
||||
<div app-domains-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-contact-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-tlds-widget></div>
|
||||
<div app-promotions-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-settings-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-resources-widget></div>
|
||||
<div app-billing-widget></div>
|
||||
<div app-epp-widget></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
@@ -12,11 +12,26 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
.console-app {
|
||||
&__home {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
&__home-widgets {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
grid-gap: 20px;
|
||||
grid-auto-flow: dense;
|
||||
|
||||
mat-card {
|
||||
height: 100%;
|
||||
h1 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 510px) {
|
||||
.console-app__widget-wrapper__wide {
|
||||
grid-column: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,220 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
export interface ActivityRecord {
|
||||
eventType: string;
|
||||
userName: string;
|
||||
registrarName: string;
|
||||
timestamp: string;
|
||||
details: string;
|
||||
}
|
||||
|
||||
const MOCK_DATA: ActivityRecord[] = [
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
];
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.less'],
|
||||
styleUrls: ['./home.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class HomeComponent {
|
||||
columns = [
|
||||
{
|
||||
columnDef: 'eventType',
|
||||
header: 'Event Type',
|
||||
cell: (record: ActivityRecord) => `${record.eventType}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'userName',
|
||||
header: 'User',
|
||||
cell: (record: ActivityRecord) => `${record.userName}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'registrarName',
|
||||
header: 'Registrar',
|
||||
cell: (record: ActivityRecord) => `${record.registrarName}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'timestamp',
|
||||
header: 'Timestamp',
|
||||
cell: (record: ActivityRecord) => `${record.timestamp}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'details',
|
||||
header: 'Details',
|
||||
cell: (record: ActivityRecord) => `${record.details}`,
|
||||
},
|
||||
];
|
||||
dataSource = MOCK_DATA;
|
||||
displayedColumns = this.columns.map((c) => c.columnDef);
|
||||
}
|
||||
export class HomeComponent {}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<a
|
||||
class="console-app__widget_left"
|
||||
href="{{ driveFolderUrl }}"
|
||||
(click)="openBillingDetails($event)"
|
||||
>
|
||||
<mat-icon class="console-app__widget-icon">account_balance</mat-icon>
|
||||
<h1 class="console-app__widget-title">Billing Info</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
<span *ngIf="driveFolderUrl; else noDriveFolderUrl">
|
||||
View important billing and payments information.
|
||||
</span>
|
||||
<ng-template #noDriveFolderUrl>
|
||||
<span> Your billing folder is pending allocation. </span>
|
||||
</ng-template>
|
||||
</h4>
|
||||
</a>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
|
||||
@Component({
|
||||
selector: '[app-billing-widget]',
|
||||
templateUrl: './billingWidget.component.html',
|
||||
})
|
||||
export class BillingWidgetComponent {
|
||||
constructor(public registrarService: RegistrarService) {}
|
||||
|
||||
public get driveFolderUrl(): string {
|
||||
if (this.registrarService?.registrar.driveFolderId) {
|
||||
return `https://drive.google.com/drive/folders/${this.registrarService?.registrar.driveFolderId}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
openBillingDetails(e: MouseEvent) {
|
||||
if (!this.driveFolderUrl) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">call</mat-icon>
|
||||
<h1 class="console-app__widget-title">Contact Support</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Let us know if you have any questions
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<div class="console-app__widget-section-header">Give us a Call</div>
|
||||
<p class="secondary-text">
|
||||
Call {{ userDataService.userData?.productName }} support at
|
||||
<a href="tel:{{ userDataService.userData?.supportPhoneNumber }}">{{
|
||||
userDataService.userData?.supportPhoneNumber
|
||||
}}</a>
|
||||
</p>
|
||||
<div class="console-app__widget-section-header">Send us an Email</div>
|
||||
<p class="secondary-text">
|
||||
Email {{ userDataService.userData?.productName }} at
|
||||
<a href="mailto:{{ userDataService.userData?.supportEmail }}">{{
|
||||
userDataService.userData?.supportEmail
|
||||
}}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { UserDataService } from 'src/app/shared/services/userData.service';
|
||||
|
||||
@Component({
|
||||
selector: '[app-contact-widget]',
|
||||
templateUrl: './contactWidget.component.html',
|
||||
})
|
||||
export class ContactWidgetComponent {
|
||||
constructor(public userDataService: UserDataService) {}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">view_list</mat-icon>
|
||||
<h1 class="console-app__widget-title">Domains</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Manage domain names and registry lock settings.
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Create a Domain
|
||||
</button>
|
||||
<p class="secondary-text">Register a new domain name</p>
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
class="console-app__widget-link"
|
||||
(click)="openDomainsPage()"
|
||||
>
|
||||
View DUMs
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Download a csv of all domains under management
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { DomainListComponent } from 'src/app/domains/domainList.component';
|
||||
|
||||
@Component({
|
||||
selector: '[app-domains-widget]',
|
||||
templateUrl: './domainsWidget.component.html',
|
||||
})
|
||||
export class DomainsWidgetComponent {
|
||||
constructor(private router: Router) {}
|
||||
|
||||
openDomainsPage() {
|
||||
this.router.navigate([DomainListComponent.PATH]);
|
||||
}
|
||||
}
|
||||
13
console-webapp/src/app/home/widgets/eppWidget.component.html
Normal file
13
console-webapp/src/app/home/widgets/eppWidget.component.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">computer</mat-icon>
|
||||
<h1 class="console-app__widget-title">EPP Console</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Test run and execute EPP commands using XML files.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -15,8 +15,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrars',
|
||||
templateUrl: './registrars.component.html',
|
||||
styleUrls: ['./registrars.component.less'],
|
||||
selector: '[app-epp-widget]',
|
||||
templateUrl: './eppWidget.component.html',
|
||||
})
|
||||
export default class RegistrarsComponent {}
|
||||
export class EppWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<mat-card class="console-app__widget-wrapper__wide">
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">subject</mat-icon>
|
||||
<h1 class="console-app__widget-title">Promotions</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Manage Google Registry promotions and view onboarding process.
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Manage Preferred Partner Program
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Onboard or view current preferred partner status
|
||||
</p>
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Manage Registry Lock Program
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Onboard or view current registry lock status
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-promotions-widget]',
|
||||
templateUrl: './promotionsWidget.component.html',
|
||||
})
|
||||
export class PromotionsWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<a
|
||||
class="console-app__widget_left"
|
||||
href="{{ userDataService.userData?.technicalDocsUrl }}"
|
||||
target="_blank"
|
||||
>
|
||||
<mat-icon class="console-app__widget-icon">menu_book</mat-icon>
|
||||
<h1 class="console-app__widget-title">Resources</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Use Google Drive to view onboarding FAQs, and technical documentation.
|
||||
</h4>
|
||||
</a>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { UserDataService } from 'src/app/shared/services/userData.service';
|
||||
|
||||
@Component({
|
||||
selector: '[app-resources-widget]',
|
||||
templateUrl: './resourcesWidget.component.html',
|
||||
})
|
||||
export class ResourcesWidgetComponent {
|
||||
constructor(public userDataService: UserDataService) {}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<mat-card class="console-app__widget-wrapper__wide">
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">settings</mat-icon>
|
||||
<h1 class="console-app__widget-title">Settings</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Configure registrar settings, manage console users, and view activity
|
||||
log.
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
class="console-app__widget-link"
|
||||
(click)="openContactsPage()"
|
||||
>
|
||||
Contact Information
|
||||
</button>
|
||||
<p class="secondary-text">Manage Primary, Technical, etc contacts.</p>
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
class="console-app__widget-link"
|
||||
(click)="openSecurityPage()"
|
||||
>
|
||||
Security
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Manage IP allow lists and SSL certificates.
|
||||
</p>
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Nomulus Password
|
||||
</button>
|
||||
<p class="secondary-text">Reset your Nomulus password.</p>
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
User Management
|
||||
</button>
|
||||
<p class="secondary-text">Create and manage console user accounts</p>
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
class="console-app__widget-link"
|
||||
(click)="openRegistrarsPage()"
|
||||
>
|
||||
Registrar Management
|
||||
</button>
|
||||
<p class="secondary-text">Create and manage registrar accounts</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { RegistrarComponent } from 'src/app/registrar/registrarsTable.component';
|
||||
import ContactComponent from 'src/app/settings/contact/contact.component';
|
||||
import SecurityComponent from 'src/app/settings/security/security.component';
|
||||
import { SettingsComponent } from 'src/app/settings/settings.component';
|
||||
|
||||
@Component({
|
||||
selector: '[app-settings-widget]',
|
||||
templateUrl: './settingsWidget.component.html',
|
||||
})
|
||||
export class SettingsWidgetComponent {
|
||||
constructor(private router: Router) {}
|
||||
|
||||
openRegistrarsPage() {
|
||||
this.navigate(RegistrarComponent.PATH);
|
||||
}
|
||||
|
||||
openSecurityPage() {
|
||||
this.navigate(SecurityComponent.PATH);
|
||||
}
|
||||
|
||||
openContactsPage() {
|
||||
this.navigate(ContactComponent.PATH);
|
||||
}
|
||||
|
||||
private navigate(route: string) {
|
||||
this.router.navigate([SettingsComponent.PATH, route]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">list_alt</mat-icon>
|
||||
<h1 class="console-app__widget-title">TLDs</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
View launch phase information for all onboarded and available TLDs.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
23
console-webapp/src/app/home/widgets/tldsWidget.component.ts
Normal file
23
console-webapp/src/app/home/widgets/tldsWidget.component.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-tlds-widget]',
|
||||
templateUrl: './tldsWidget.component.html',
|
||||
})
|
||||
export class TldsWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -44,6 +44,8 @@ import { CdkMenuModule } from '@angular/cdk/menu';
|
||||
import { DialogModule } from '@angular/cdk/dialog';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
|
||||
@NgModule({
|
||||
exports: [
|
||||
@@ -79,6 +81,8 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
OverlayModule,
|
||||
DialogModule,
|
||||
MatSnackBarModule,
|
||||
MatPaginatorModule,
|
||||
MatChipsModule,
|
||||
],
|
||||
})
|
||||
export class MaterialModule {}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="console-app__emty-registrar">
|
||||
<h1>
|
||||
<mat-icon class="console-app__emty-registrar-icon">block</mat-icon>
|
||||
</h1>
|
||||
<h1>No registrar selected</h1>
|
||||
<h4 class="mat-body-2">Please select a registrar</h4>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
.console-app {
|
||||
&__emty-registrar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
white-space: nowrap;
|
||||
|
||||
&-icon {
|
||||
transform: scale(3);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,33 +13,33 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { RegistrarService } from './registrar.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar',
|
||||
templateUrl: './registrar.component.html',
|
||||
styleUrls: ['./registrar.component.less'],
|
||||
selector: 'app-empty-registrar',
|
||||
templateUrl: './emptyRegistrar.component.html',
|
||||
styleUrls: ['./emptyRegistrar.component.scss'],
|
||||
})
|
||||
export class RegistrarComponent {
|
||||
private lastActiveRegistrarId: string;
|
||||
export class EmptyRegistrar {
|
||||
private registrarIdChangeSubscription?: Subscription;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
protected registrarService: RegistrarService,
|
||||
private router: Router
|
||||
) {
|
||||
this.lastActiveRegistrarId = registrarService.activeRegistrarId;
|
||||
this.registrarIdChangeSubscription =
|
||||
registrarService.activeRegistrarIdChange.subscribe((newRegistrarId) => {
|
||||
if (newRegistrarId) {
|
||||
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngDoCheck() {
|
||||
if (
|
||||
this.registrarService.activeRegistrarId &&
|
||||
this.registrarService.activeRegistrarId !== this.lastActiveRegistrarId &&
|
||||
this.route.snapshot.paramMap.get('nextUrl')
|
||||
) {
|
||||
this.lastActiveRegistrarId = this.registrarService.activeRegistrarId;
|
||||
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.registrarIdChangeSubscription?.unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<div class="console-app__registrar">
|
||||
<h4 class="console-app__title">
|
||||
{{ registrarService.activeRegistrarId === "" ? "Select" : "Switch" }}
|
||||
registrar:
|
||||
</h4>
|
||||
<mat-form-field>
|
||||
<mat-label>Registrar</mat-label>
|
||||
<mat-select [(ngModel)]="registrarService.activeRegistrarId">
|
||||
<mat-option
|
||||
*ngFor="let registrar of registrarService.registrars"
|
||||
[value]="registrar"
|
||||
>
|
||||
{{ registrar }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@@ -1,11 +0,0 @@
|
||||
.console-app {
|
||||
&__registrar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
&__title {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ describe('RegistrarGuard', () => {
|
||||
|
||||
it('should not be able to activate when activeRegistrarId is empty', () => {
|
||||
guard = TestBed.inject(RegistrarGuard);
|
||||
const res = guard.canActivate(dummyRoute);
|
||||
const res = guard.canActivate();
|
||||
expect(res).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -48,14 +48,14 @@ describe('RegistrarGuard', () => {
|
||||
useValue: { activeRegistrarId: 'value' },
|
||||
});
|
||||
guard = TestBed.inject(RegistrarGuard);
|
||||
const res = guard.canActivate(dummyRoute);
|
||||
const res = guard.canActivate();
|
||||
expect(res).toBeTrue();
|
||||
});
|
||||
|
||||
it('should navigate to registrars when activeRegistrarId is empty', () => {
|
||||
const dummyRoute = { url: '/value' } as RouterStateSnapshot;
|
||||
guard = TestBed.inject(RegistrarGuard);
|
||||
guard.canActivate(dummyRoute);
|
||||
guard.canActivate();
|
||||
expect(routeSpy.navigate).toHaveBeenCalledOnceWith([
|
||||
'/registrars',
|
||||
{ nextUrl: '/value' },
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router, RouterStateSnapshot } from '@angular/router';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from '@angular/router';
|
||||
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
@Injectable({
|
||||
@@ -25,10 +30,16 @@ export class RegistrarGuard {
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
canActivate(state: RouterStateSnapshot): Promise<boolean> | boolean {
|
||||
canActivate(
|
||||
_: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
): Promise<boolean> | boolean {
|
||||
if (this.registrarService.activeRegistrarId) {
|
||||
return true;
|
||||
}
|
||||
return this.router.navigate([`/registrars`, { nextUrl: state.url }]);
|
||||
return this.router.navigate([
|
||||
`/empty-registrar`,
|
||||
{ nextUrl: state.url || '' },
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,82 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject, tap } from 'rxjs';
|
||||
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import {
|
||||
GlobalLoader,
|
||||
GlobalLoaderService,
|
||||
} from '../shared/services/globalLoader.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
export interface Address {
|
||||
street?: string[];
|
||||
city?: string;
|
||||
countryCode?: string;
|
||||
zip?: string;
|
||||
state?: string;
|
||||
}
|
||||
|
||||
export interface Registrar {
|
||||
allowedTlds?: string[];
|
||||
billingAccountMap?: object;
|
||||
driveFolderId?: string;
|
||||
emailAddress?: string;
|
||||
faxNumber?: string;
|
||||
ianaIdentifier?: number;
|
||||
icannReferralEmail?: string;
|
||||
ipAddressAllowList?: string[];
|
||||
localizedAddress?: Address;
|
||||
phoneNumber?: string;
|
||||
registrarId: string;
|
||||
registrarName: string;
|
||||
registryLockAllowed?: boolean;
|
||||
url?: string;
|
||||
whoisServer?: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RegistrarService {
|
||||
export class RegistrarService implements GlobalLoader {
|
||||
activeRegistrarId: string = '';
|
||||
registrars: string[] = [];
|
||||
constructor(private backend: BackendService) {
|
||||
this.backend.getRegistrars().subscribe((r) => {
|
||||
this.registrars = r;
|
||||
registrars: Registrar[] = [];
|
||||
activeRegistrarIdChange: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private globalLoader: GlobalLoaderService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
this.loadRegistrars().subscribe((r) => {
|
||||
this.globalLoader.stopGlobalLoader(this);
|
||||
});
|
||||
this.globalLoader.startGlobalLoader(this);
|
||||
}
|
||||
|
||||
public get registrar(): Registrar {
|
||||
return this.registrars.filter(
|
||||
(r) => r.registrarId === this.activeRegistrarId
|
||||
)[0];
|
||||
}
|
||||
|
||||
public updateSelectedRegistrar(registrarId: string) {
|
||||
this.activeRegistrarId = registrarId;
|
||||
this.activeRegistrarIdChange.next(registrarId);
|
||||
}
|
||||
|
||||
public loadRegistrars(): Observable<Registrar[]> {
|
||||
return this.backend.getRegistrars().pipe(
|
||||
tap((registrars) => {
|
||||
if (registrars) {
|
||||
this.registrars = registrars;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
loadingTimeout() {
|
||||
this._snackBar.open('Timeout loading registrars');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<div class="registrarDetails" *ngIf="registrarInEdit">
|
||||
<h3 mat-dialog-title>Edit Registrar: {{ registrarInEdit.registrarId }}</h3>
|
||||
<div mat-dialog-content>
|
||||
<form (ngSubmit)="saveAndClose()">
|
||||
<mat-form-field class="registrarDetails__input">
|
||||
<mat-label>Registry Lock:</mat-label>
|
||||
<mat-select
|
||||
[(ngModel)]="registrarInEdit.registryLockAllowed"
|
||||
name="registryLockAllowed"
|
||||
>
|
||||
<mat-option [value]="true">True</mat-option>
|
||||
<mat-option [value]="false">False</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="registrarDetails__input">
|
||||
<mat-label>Onboarded TLDs: </mat-label>
|
||||
<mat-chip-grid #chipGrid aria-label="Enter TLD">
|
||||
<mat-chip-row
|
||||
*ngFor="let tld of registrarInEdit.allowedTlds"
|
||||
(removed)="removeTLD(tld)"
|
||||
>
|
||||
{{ tld }}
|
||||
<button matChipRemove aria-label="'remove ' + tld">
|
||||
<mat-icon>cancel</mat-icon>
|
||||
</button>
|
||||
</mat-chip-row>
|
||||
</mat-chip-grid>
|
||||
<input
|
||||
placeholder="New tld..."
|
||||
[matChipInputFor]="chipGrid"
|
||||
(matChipInputTokenEnd)="addTLD($event)"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="this.params?.close()">Cancel</button>
|
||||
<button type="submit" mat-button color="primary">Save</button>
|
||||
</mat-dialog-actions>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
.registrarDetails {
|
||||
min-width: 30vw;
|
||||
|
||||
&__input {
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Registrar, RegistrarService } from './registrar.service';
|
||||
import { MatChipInputEvent } from '@angular/material/chips';
|
||||
import { DialogBottomSheetContent } from '../shared/components/dialogBottomSheet.component';
|
||||
|
||||
type RegistrarDetailsParams = {
|
||||
close: Function;
|
||||
data: {
|
||||
registrar: Registrar;
|
||||
};
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar-details',
|
||||
templateUrl: './registrarDetails.component.html',
|
||||
styleUrls: ['./registrarDetails.component.scss'],
|
||||
})
|
||||
export class RegistrarDetailsComponent implements DialogBottomSheetContent {
|
||||
registrarInEdit!: Registrar;
|
||||
params?: RegistrarDetailsParams;
|
||||
|
||||
constructor(protected registrarService: RegistrarService) {}
|
||||
|
||||
init(params: RegistrarDetailsParams) {
|
||||
this.params = params;
|
||||
this.registrarInEdit = JSON.parse(
|
||||
JSON.stringify(this.params.data.registrar)
|
||||
);
|
||||
}
|
||||
|
||||
saveAndClose() {
|
||||
this.params?.close();
|
||||
}
|
||||
|
||||
addTLD(e: MatChipInputEvent) {
|
||||
this.removeTLD(e.value); // Prevent dups
|
||||
this.registrarInEdit.allowedTlds = this.registrarInEdit.allowedTlds?.concat(
|
||||
[e.value.toLowerCase()]
|
||||
);
|
||||
}
|
||||
|
||||
removeTLD(tld: string) {
|
||||
this.registrarInEdit.allowedTlds = this.registrarInEdit.allowedTlds?.filter(
|
||||
(v) => v != tld
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="console-app__registrar">
|
||||
<button
|
||||
mat-button
|
||||
[routerLink]="'/settings/registrars'"
|
||||
routerLinkActive="active"
|
||||
*ngIf="isMobile; else desktop"
|
||||
>
|
||||
{{ registrarService.activeRegistrarId || "Select registrar" }}
|
||||
<mat-icon>open_in_new</mat-icon>
|
||||
</button>
|
||||
<ng-template #desktop>
|
||||
<mat-form-field class="mat-form-field-density-5" appearance="fill">
|
||||
<mat-label>Registrar</mat-label>
|
||||
<mat-select
|
||||
[ngModel]="registrarService.activeRegistrarId"
|
||||
(selectionChange)="
|
||||
registrarService.updateSelectedRegistrar($event.value)
|
||||
"
|
||||
>
|
||||
<mat-option
|
||||
*ngFor="let registrar of registrarService.registrars"
|
||||
[value]="registrar.registrarId"
|
||||
>
|
||||
{{ registrar.registrarId }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
.console-app {
|
||||
&__registrar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
// Fix for angular v15 label issue
|
||||
// https://github.com/angular/components/issues/26579
|
||||
.mat-mdc-floating-label {
|
||||
display: inline !important;
|
||||
}
|
||||
.mat-mdc-select-arrow-wrapper {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
}
|
||||
&__title {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegistrarSelectorComponent } from './registrarSelector.component';
|
||||
|
||||
describe('RegistrarSelectorComponent', () => {
|
||||
let component: RegistrarSelectorComponent;
|
||||
let fixture: ComponentFixture<RegistrarSelectorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RegistrarSelectorComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RegistrarSelectorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { RegistrarService } from './registrar.service';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { distinctUntilChanged } from 'rxjs';
|
||||
|
||||
const MOBILE_LAYOUT_BREAKPOINT = '(max-width: 599px)';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar-selector',
|
||||
templateUrl: './registrarSelector.component.html',
|
||||
styleUrls: ['./registrarSelector.component.scss'],
|
||||
})
|
||||
export class RegistrarSelectorComponent implements OnInit {
|
||||
protected isMobile: boolean = false;
|
||||
|
||||
readonly breakpoint$ = this.breakpointObserver
|
||||
.observe([MOBILE_LAYOUT_BREAKPOINT])
|
||||
.pipe(distinctUntilChanged());
|
||||
|
||||
constructor(
|
||||
protected registrarService: RegistrarService,
|
||||
protected breakpointObserver: BreakpointObserver
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.breakpoint$.subscribe(() => this.breakpointChanged());
|
||||
}
|
||||
|
||||
private breakpointChanged() {
|
||||
this.isMobile = this.breakpointObserver.isMatched(MOBILE_LAYOUT_BREAKPOINT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<div class="console-app__registrars">
|
||||
<mat-form-field class="console-app__registrars-filter">
|
||||
<mat-label>Search</mat-label>
|
||||
<input
|
||||
matInput
|
||||
(keyup)="applyFilter($event)"
|
||||
placeholder="..."
|
||||
type="search"
|
||||
/>
|
||||
<mat-icon matPrefix>search</mat-icon>
|
||||
</mat-form-field>
|
||||
<mat-table
|
||||
[dataSource]="dataSource"
|
||||
class="mat-elevation-z8"
|
||||
class="console-app__registrars-table"
|
||||
matSort
|
||||
>
|
||||
<ng-container matColumnDef="edit">
|
||||
<mat-header-cell *matHeaderCellDef></mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
aria-label="Edit registrar"
|
||||
(click)="openDetails($event, row)"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngFor="let column of columns"
|
||||
[matColumnDef]="column.columnDef"
|
||||
>
|
||||
<mat-header-cell *matHeaderCellDef> {{ column.header }} </mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></mat-cell>
|
||||
</ng-container>
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
(click)="registrarService.updateSelectedRegistrar(row.registrarId)"
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator
|
||||
class="mat-elevation-z8"
|
||||
[pageSizeOptions]="[5, 10, 20]"
|
||||
showFirstLastButtons
|
||||
></mat-paginator>
|
||||
<app-dialog-bottom-sheet-wrapper
|
||||
#registrarDetailsView
|
||||
></app-dialog-bottom-sheet-wrapper>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
.console-app {
|
||||
$min-width: 756px;
|
||||
|
||||
&__registrars {
|
||||
margin-top: 1.5rem;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&__registrars-filter {
|
||||
min-width: $min-width !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__registrars-table {
|
||||
min-width: $min-width !important;
|
||||
}
|
||||
|
||||
.mat-mdc-paginator {
|
||||
min-width: $min-width !important;
|
||||
}
|
||||
|
||||
.mat-column {
|
||||
&-edit {
|
||||
max-width: 55px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
&-driveId {
|
||||
min-width: 200px;
|
||||
word-break: break-all;
|
||||
}
|
||||
&-registryLockAllowed {
|
||||
max-width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,12 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegistrarComponent } from './registrar.component';
|
||||
import { RegistrarComponent } from './registrarsTable.component';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from '../material.module';
|
||||
|
||||
describe('RegistrarComponent', () => {
|
||||
let component: RegistrarComponent;
|
||||
@@ -26,7 +28,11 @@ describe('RegistrarComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RegistrarComponent],
|
||||
imports: [HttpClientTestingModule],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: ActivatedRoute, useValue: {} as ActivatedRoute },
|
||||
111
console-webapp/src/app/registrar/registrarsTable.component.ts
Normal file
111
console-webapp/src/app/registrar/registrarsTable.component.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { Registrar, RegistrarService } from './registrar.service';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { RegistrarDetailsComponent } from './registrarDetails.component';
|
||||
import { DialogBottomSheetWrapper } from '../shared/components/dialogBottomSheet.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar',
|
||||
templateUrl: './registrarsTable.component.html',
|
||||
styleUrls: ['./registrarsTable.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class RegistrarComponent {
|
||||
public static PATH = 'registrars';
|
||||
dataSource: MatTableDataSource<Registrar>;
|
||||
columns = [
|
||||
{
|
||||
columnDef: 'registrarId',
|
||||
header: 'Registrar Id',
|
||||
cell: (record: Registrar) => `${record.registrarId || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'registrarName',
|
||||
header: 'Name',
|
||||
cell: (record: Registrar) => `${record.registrarName || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'allowedTlds',
|
||||
header: 'TLDs',
|
||||
cell: (record: Registrar) => `${(record.allowedTlds || []).join(', ')}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'emailAddress',
|
||||
header: 'Username',
|
||||
cell: (record: Registrar) => `${record.emailAddress || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'ianaIdentifier',
|
||||
header: 'IANA ID',
|
||||
cell: (record: Registrar) => `${record.ianaIdentifier || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'billingAccountMap',
|
||||
header: 'Billing Accounts',
|
||||
cell: (record: Registrar) =>
|
||||
// @ts-ignore - completely legit line, but TS keeps complaining
|
||||
`${Object.entries(record.billingAccountMap).reduce(
|
||||
(acc, [key, val]) => {
|
||||
return `${acc}${key}=${val}<br/>`;
|
||||
},
|
||||
''
|
||||
)}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'registryLockAllowed',
|
||||
header: 'Registry Lock',
|
||||
cell: (record: Registrar) => `${record.registryLockAllowed}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'driveId',
|
||||
header: 'Drive ID',
|
||||
cell: (record: Registrar) => `${record.driveFolderId || ''}`,
|
||||
},
|
||||
];
|
||||
displayedColumns = ['edit'].concat(this.columns.map((c) => c.columnDef));
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort) sort!: MatSort;
|
||||
@ViewChild('registrarDetailsView')
|
||||
detailsComponentWrapper!: DialogBottomSheetWrapper;
|
||||
|
||||
constructor(protected registrarService: RegistrarService) {
|
||||
this.dataSource = new MatTableDataSource<Registrar>(
|
||||
registrarService.registrars
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
openDetails(event: MouseEvent, registrar: Registrar) {
|
||||
event.stopPropagation();
|
||||
this.detailsComponentWrapper.open<RegistrarDetailsComponent>(
|
||||
RegistrarDetailsComponent,
|
||||
{ registrar }
|
||||
);
|
||||
}
|
||||
|
||||
applyFilter(event: Event) {
|
||||
const filterValue = (event.target as HTMLInputElement).value;
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,15 @@
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div *ngIf="!loading">
|
||||
<div
|
||||
class="contact__empty-contacts"
|
||||
*ngIf="contactService.contacts.length === 0"
|
||||
>
|
||||
<mat-icon class="contact__empty-contacts-icon secondary-text"
|
||||
>apps_outage</mat-icon
|
||||
>
|
||||
<h1>No contacts found</h1>
|
||||
</div>
|
||||
<div *ngFor="let group of groupedData">
|
||||
<div class="contact__cards-wrapper" *ngIf="group.contacts.length">
|
||||
<h3>{{ group.label }}s</h3>
|
||||
@@ -32,4 +41,7 @@
|
||||
<mat-icon>add</mat-icon>Create a Contact
|
||||
</button>
|
||||
</div>
|
||||
<app-dialog-bottom-sheet-wrapper
|
||||
#contactDetailsWrapper
|
||||
></app-dialog-bottom-sheet-wrapper>
|
||||
</div>
|
||||
|
||||
@@ -37,6 +37,18 @@
|
||||
justify-content: flex-start;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
&__empty-contacts {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
&__empty-contacts-icon {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
font-size: 4rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
}
|
||||
.contact-details {
|
||||
&__input {
|
||||
@@ -12,21 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import {
|
||||
MatDialog,
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogRef,
|
||||
} from '@angular/material/dialog';
|
||||
import {
|
||||
MatBottomSheet,
|
||||
MAT_BOTTOM_SHEET_DATA,
|
||||
MatBottomSheetRef,
|
||||
} from '@angular/material/bottom-sheet';
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import {
|
||||
DialogBottomSheetContent,
|
||||
DialogBottomSheetWrapper,
|
||||
} from 'src/app/shared/components/dialogBottomSheet.component';
|
||||
|
||||
enum Operations {
|
||||
DELETE,
|
||||
@@ -40,7 +33,13 @@ interface GroupedContacts {
|
||||
contacts: Array<Contact>;
|
||||
}
|
||||
|
||||
let isMobile: boolean;
|
||||
type ContactDetailsParams = {
|
||||
close: Function;
|
||||
data: {
|
||||
contact: Contact;
|
||||
operation: Operations;
|
||||
};
|
||||
};
|
||||
|
||||
const contactTypes: Array<GroupedContacts> = [
|
||||
{ value: 'ADMIN', label: 'Primary contact', contacts: [] },
|
||||
@@ -52,67 +51,46 @@ const contactTypes: Array<GroupedContacts> = [
|
||||
{ value: 'WHOIS', label: 'WHOIS-Inquiry contact', contacts: [] },
|
||||
];
|
||||
|
||||
class ContactDetailsEventsResponder {
|
||||
private ref?: MatDialogRef<any> | MatBottomSheetRef;
|
||||
constructor() {
|
||||
this.onClose = this.onClose.bind(this);
|
||||
}
|
||||
|
||||
setRef(ref: MatDialogRef<any> | MatBottomSheetRef) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
onClose() {
|
||||
if (this.ref == undefined) {
|
||||
throw "Reference to ContactDetailsDialogComponent hasn't been set. ";
|
||||
}
|
||||
if (this.ref instanceof MatBottomSheetRef) {
|
||||
this.ref.dismiss();
|
||||
} else if (this.ref instanceof MatDialogRef) {
|
||||
this.ref.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact-details-dialog',
|
||||
templateUrl: 'contact-details.component.html',
|
||||
styleUrls: ['./contact.component.less'],
|
||||
templateUrl: 'contactDetails.component.html',
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export class ContactDetailsDialogComponent {
|
||||
onClose!: Function;
|
||||
contact: Contact;
|
||||
export class ContactDetailsDialogComponent implements DialogBottomSheetContent {
|
||||
contact?: Contact;
|
||||
contactTypes = contactTypes;
|
||||
operation: Operations;
|
||||
contactIndex: number;
|
||||
contactIndex?: number;
|
||||
|
||||
params?: ContactDetailsParams;
|
||||
|
||||
constructor(
|
||||
public contactService: ContactService,
|
||||
private _snackBar: MatSnackBar,
|
||||
@Inject(isMobile ? MAT_BOTTOM_SHEET_DATA : MAT_DIALOG_DATA)
|
||||
public data: {
|
||||
onClose: Function;
|
||||
contact: Contact;
|
||||
operation: Operations;
|
||||
}
|
||||
) {
|
||||
this.onClose = data.onClose;
|
||||
this.contactIndex = contactService.contacts.findIndex(
|
||||
(c) => c === data.contact
|
||||
private _snackBar: MatSnackBar
|
||||
) {}
|
||||
|
||||
init(params: ContactDetailsParams) {
|
||||
this.params = params;
|
||||
this.contactIndex = this.contactService.contacts.findIndex(
|
||||
(c) => c === params.data.contact
|
||||
);
|
||||
this.contact = JSON.parse(JSON.stringify(data.contact));
|
||||
this.operation = data.operation;
|
||||
this.contact = JSON.parse(JSON.stringify(params.data.contact));
|
||||
}
|
||||
|
||||
saveAndClose(e: any) {
|
||||
close() {
|
||||
this.params?.close();
|
||||
}
|
||||
|
||||
saveAndClose(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
if (!e.target.checkValidity()) {
|
||||
if (!this.contact || this.contactIndex === undefined) return;
|
||||
if (!(e.target as HTMLFormElement).checkValidity()) {
|
||||
return;
|
||||
}
|
||||
const operation = this.params?.data.operation;
|
||||
let operationObservable;
|
||||
if (this.operation === Operations.ADD) {
|
||||
if (operation === Operations.ADD) {
|
||||
operationObservable = this.contactService.addContact(this.contact);
|
||||
} else if (this.operation === Operations.UPDATE) {
|
||||
} else if (operation === Operations.UPDATE) {
|
||||
operationObservable = this.contactService.updateContact(
|
||||
this.contactIndex,
|
||||
this.contact
|
||||
@@ -122,11 +100,9 @@ export class ContactDetailsDialogComponent {
|
||||
}
|
||||
|
||||
operationObservable.subscribe({
|
||||
complete: this.onClose.bind(this),
|
||||
complete: () => this.close(),
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.statusText, undefined, {
|
||||
duration: 1500,
|
||||
});
|
||||
this._snackBar.open(err.error);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -135,15 +111,18 @@ export class ContactDetailsDialogComponent {
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrls: ['./contact.component.less'],
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export default class ContactComponent {
|
||||
public static PATH = 'contact';
|
||||
|
||||
@ViewChild('contactDetailsWrapper')
|
||||
detailsComponentWrapper!: DialogBottomSheetWrapper;
|
||||
|
||||
loading: boolean = false;
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private bottomSheet: MatBottomSheet,
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
public contactService: ContactService
|
||||
public contactService: ContactService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
// TODO: Refactor to registrarId service
|
||||
this.loading = true;
|
||||
@@ -153,7 +132,7 @@ export default class ContactComponent {
|
||||
}
|
||||
|
||||
public get groupedData() {
|
||||
return this.contactService.contacts.reduce((acc, contact) => {
|
||||
return this.contactService.contacts?.reduce((acc, contact) => {
|
||||
contact.types.forEach((type) => {
|
||||
acc
|
||||
.find((group: GroupedContacts) => group.value === type)
|
||||
@@ -165,11 +144,15 @@ export default class ContactComponent {
|
||||
|
||||
deleteContact(contact: Contact) {
|
||||
if (confirm(`Please confirm contact ${contact.name} delete`)) {
|
||||
this.contactService.deleteContact(contact).subscribe();
|
||||
this.contactService.deleteContact(contact).subscribe({
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
openCreateNew(e: Event) {
|
||||
openCreateNew(e: MouseEvent) {
|
||||
const newContact: Contact = {
|
||||
name: '',
|
||||
phoneNumber: '',
|
||||
@@ -180,25 +163,14 @@ export default class ContactComponent {
|
||||
}
|
||||
|
||||
openDetails(
|
||||
e: Event,
|
||||
e: MouseEvent,
|
||||
contact: Contact,
|
||||
operation: Operations = Operations.UPDATE
|
||||
) {
|
||||
e.preventDefault();
|
||||
// TODO: handle orientation change
|
||||
isMobile = this.breakpointObserver.isMatched('(max-width: 599px)');
|
||||
const responder = new ContactDetailsEventsResponder();
|
||||
const config = { data: { onClose: responder.onClose, contact, operation } };
|
||||
|
||||
if (isMobile) {
|
||||
const bottomSheetRef = this.bottomSheet.open(
|
||||
ContactDetailsDialogComponent,
|
||||
config
|
||||
);
|
||||
responder.setRef(bottomSheetRef);
|
||||
} else {
|
||||
const dialogRef = this.dialog.open(ContactDetailsDialogComponent, config);
|
||||
responder.setRef(dialogRef);
|
||||
}
|
||||
this.detailsComponentWrapper.open<ContactDetailsDialogComponent>(
|
||||
ContactDetailsDialogComponent,
|
||||
{ contact, operation }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class ContactService {
|
||||
return this.backend
|
||||
.getContacts(this.registrarService.activeRegistrarId)
|
||||
.pipe(
|
||||
tap((contacts) => {
|
||||
tap((contacts = []) => {
|
||||
this.contacts = contacts;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<h3 mat-dialog-title>Contact details</h3>
|
||||
<div mat-dialog-content>
|
||||
<div mat-dialog-content *ngIf="contact">
|
||||
<form (ngSubmit)="saveAndClose($event)">
|
||||
<div>
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Name: </mat-label>
|
||||
<input
|
||||
@@ -11,9 +11,9 @@
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Primary account email: </mat-label>
|
||||
<input
|
||||
@@ -25,9 +25,9 @@
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Phone: </mat-label>
|
||||
<input
|
||||
@@ -36,9 +36,9 @@
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Fax: </mat-label>
|
||||
<input
|
||||
@@ -47,7 +47,7 @@
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div class="contact-details__group">
|
||||
<label>Contact type:</label>
|
||||
@@ -97,7 +97,7 @@
|
||||
>
|
||||
</section>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="onClose()">Cancel</button>
|
||||
<button mat-button (click)="close()">Cancel</button>
|
||||
<button type="submit" mat-button>Save</button>
|
||||
</mat-dialog-actions>
|
||||
</form>
|
||||
@@ -1 +0,0 @@
|
||||
<p>registrars component works!</p>
|
||||
@@ -1 +1,98 @@
|
||||
<p>security works!</p>
|
||||
<div *ngIf="loading" class="settings-security__loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div class="settings-security" *ngIf="!loading">
|
||||
<div class="settings-security__section">
|
||||
<div class="settings-security__section-description">
|
||||
<h2>IP Allowlist</h2>
|
||||
<p>
|
||||
Restrict access to EPP production servers to the following IP/IPv6
|
||||
addresses, or ranges like 1.1.1.0/24
|
||||
</p>
|
||||
</div>
|
||||
<div class="settings-security__section-form">
|
||||
<div
|
||||
*ngIf="
|
||||
dataSource.ipAddressAllowList &&
|
||||
dataSource.ipAddressAllowList.length > 0
|
||||
"
|
||||
>
|
||||
<div
|
||||
*ngFor="let item of dataSource.ipAddressAllowList; index as index"
|
||||
class="settings-security__ipRecord"
|
||||
>
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
class="settings-security__ip-allowlist"
|
||||
[(ngModel)]="item.value"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
<button
|
||||
*ngIf="inEdit"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Remove"
|
||||
(click)="removeIpEntry(index)"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<button mat-stroked-button (click)="enableEdit(); createIpEntry()">
|
||||
Add IP
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-security__section">
|
||||
<div class="settings-security__section-description">
|
||||
<h2>SSL Certificate</h2>
|
||||
<p>X.509 PEM certificate for EPP production access.</p>
|
||||
</div>
|
||||
<div class="settings-security__section-form">
|
||||
<textarea
|
||||
matInput
|
||||
class="settings-security__clientCertificate"
|
||||
[(ngModel)]="dataSource.clientCertificate"
|
||||
[disabled]="!inEdit"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-security__section">
|
||||
<div class="settings-security__section-description">
|
||||
<h2>Failover SSL Certificate</h2>
|
||||
<p>X.509 PEM backup certificate for EPP Production Access.</p>
|
||||
</div>
|
||||
<div class="settings-security__section-form">
|
||||
<textarea
|
||||
matInput
|
||||
[(ngModel)]="dataSource.failoverClientCertificate"
|
||||
[disabled]="!inEdit"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-security__actions">
|
||||
<ng-template [ngIf]="inEdit" [ngIfElse]="inView">
|
||||
<button
|
||||
class="settings-security__actions-save"
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="save()"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
class="settings-security__actions-cancel"
|
||||
mat-stroked-button
|
||||
(click)="cancel()"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</ng-template>
|
||||
<ng-template #inView>
|
||||
<button #elseBlock mat-raised-button (click)="enableEdit()">Edit</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
.settings-security {
|
||||
margin-top: 1.5rem;
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
&__ipRecord {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
&__section {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
margin-bottom: 3rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
&__section-description {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
}
|
||||
&__section-form {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
textarea {
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
&__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
button {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
&__loading {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,56 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import SecurityComponent from './security.component';
|
||||
import { SecurityService } from './security.service';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { of } from 'rxjs';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
describe('SecurityComponent', () => {
|
||||
let component: SecurityComponent;
|
||||
let fixture: ComponentFixture<SecurityComponent>;
|
||||
let fetchSecurityDetailsSpy: Function;
|
||||
let saveSpy: Function;
|
||||
|
||||
beforeEach(async () => {
|
||||
const securityServiceSpy = jasmine.createSpyObj(SecurityService, [
|
||||
'fetchSecurityDetails',
|
||||
'saveChanges',
|
||||
]);
|
||||
|
||||
fetchSecurityDetailsSpy =
|
||||
securityServiceSpy.fetchSecurityDetails.and.returnValue(of());
|
||||
|
||||
saveSpy = securityServiceSpy.saveChanges;
|
||||
|
||||
securityServiceSpy.securitySettings = {
|
||||
ipAddressAllowList: [{ value: '123.123.123.123' }],
|
||||
};
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
],
|
||||
declarations: [SecurityComponent],
|
||||
}).compileComponents();
|
||||
providers: [BackendService],
|
||||
})
|
||||
.overrideComponent(SecurityComponent, {
|
||||
set: {
|
||||
providers: [
|
||||
{ provide: SecurityService, useValue: securityServiceSpy },
|
||||
],
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SecurityComponent);
|
||||
component = fixture.componentInstance;
|
||||
@@ -33,4 +71,86 @@ describe('SecurityComponent', () => {
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call fetch spy', () => {
|
||||
expect(fetchSecurityDetailsSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should render ip allow list', waitForAsync(() => {
|
||||
component.enableEdit();
|
||||
fixture.whenStable().then(() => {
|
||||
expect(
|
||||
Array.from(
|
||||
fixture.nativeElement.querySelectorAll(
|
||||
'.settings-security__ip-allowlist'
|
||||
)
|
||||
)
|
||||
).toHaveSize(1);
|
||||
expect(
|
||||
fixture.nativeElement.querySelector('.settings-security__ip-allowlist')
|
||||
.value
|
||||
).toBe('123.123.123.123');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should remove ip', waitForAsync(() => {
|
||||
expect(
|
||||
Array.from(
|
||||
fixture.nativeElement.querySelectorAll(
|
||||
'.settings-security__ip-allowlist'
|
||||
)
|
||||
)
|
||||
).toHaveSize(1);
|
||||
component.removeIpEntry(0);
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(
|
||||
Array.from(
|
||||
fixture.nativeElement.querySelectorAll(
|
||||
'.settings-security__ip-allowlist'
|
||||
)
|
||||
)
|
||||
).toHaveSize(0);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should toggle inEdit', () => {
|
||||
expect(component.inEdit).toBeFalse();
|
||||
component.enableEdit();
|
||||
expect(component.inEdit).toBeTrue();
|
||||
});
|
||||
|
||||
it('should create temporary data structure', () => {
|
||||
expect(component.dataSource).toBe(
|
||||
component.securityService.securitySettings
|
||||
);
|
||||
component.enableEdit();
|
||||
expect(component.dataSource).not.toBe(
|
||||
component.securityService.securitySettings
|
||||
);
|
||||
component.cancel();
|
||||
expect(component.dataSource).toBe(
|
||||
component.securityService.securitySettings
|
||||
);
|
||||
});
|
||||
|
||||
it('should call save', waitForAsync(async () => {
|
||||
component.enableEdit();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const el = fixture.nativeElement.querySelector(
|
||||
'.settings-security__clientCertificate'
|
||||
);
|
||||
el.value = 'test';
|
||||
el.dispatchEvent(new Event('input'));
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.nativeElement
|
||||
.querySelector('.settings-security__actions-save')
|
||||
.click();
|
||||
expect(saveSpy).toHaveBeenCalledOnceWith({
|
||||
ipAddressAllowList: [{ value: '123.123.123.123' }],
|
||||
clientCertificate: 'test',
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -13,10 +13,69 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
SecurityService,
|
||||
SecuritySettings,
|
||||
apiToUiConverter,
|
||||
} from './security.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-security',
|
||||
templateUrl: './security.component.html',
|
||||
styleUrls: ['./security.component.less'],
|
||||
styleUrls: ['./security.component.scss'],
|
||||
providers: [SecurityService],
|
||||
})
|
||||
export default class SecurityComponent {}
|
||||
export default class SecurityComponent {
|
||||
public static PATH = 'security';
|
||||
|
||||
loading: boolean = false;
|
||||
inEdit: boolean = false;
|
||||
dataSource: SecuritySettings = {};
|
||||
|
||||
constructor(
|
||||
public securityService: SecurityService,
|
||||
private _snackBar: MatSnackBar,
|
||||
public registrarService: RegistrarService
|
||||
) {
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar);
|
||||
}
|
||||
|
||||
enableEdit() {
|
||||
this.inEdit = true;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.inEdit = false;
|
||||
this.resetDataSource();
|
||||
}
|
||||
|
||||
createIpEntry() {
|
||||
this.dataSource.ipAddressAllowList?.push({ value: '' });
|
||||
}
|
||||
|
||||
save() {
|
||||
this.loading = true;
|
||||
this.securityService.saveChanges(this.dataSource).subscribe({
|
||||
complete: () => {
|
||||
this.loading = false;
|
||||
this.resetDataSource();
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error);
|
||||
},
|
||||
});
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
removeIpEntry(index: number) {
|
||||
this.dataSource.ipAddressAllowList =
|
||||
this.dataSource.ipAddressAllowList?.filter((_, i) => i != index);
|
||||
}
|
||||
|
||||
resetDataSource() {
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import {
|
||||
SecurityService,
|
||||
SecuritySettings,
|
||||
SecuritySettingsBackendModel,
|
||||
apiToUiConverter,
|
||||
uiToApiConverter,
|
||||
} from './security.service';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import SecurityComponent from './security.component';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
|
||||
describe('SecurityService', () => {
|
||||
const uiMockData: SecuritySettings = {
|
||||
clientCertificate: 'clientCertificateTest',
|
||||
failoverClientCertificate: 'failoverClientCertificateTest',
|
||||
ipAddressAllowList: [{ value: '123.123.123.123' }],
|
||||
};
|
||||
const apiMockData: SecuritySettingsBackendModel = {
|
||||
clientCertificate: 'clientCertificateTest',
|
||||
failoverClientCertificate: 'failoverClientCertificateTest',
|
||||
ipAddressAllowList: ['123.123.123.123'],
|
||||
};
|
||||
|
||||
let service: SecurityService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
declarations: [SecurityComponent],
|
||||
providers: [SecurityService, BackendService],
|
||||
});
|
||||
service = TestBed.inject(SecurityService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should convert from api to ui', () => {
|
||||
expect(apiToUiConverter(apiMockData)).toEqual(uiMockData);
|
||||
});
|
||||
|
||||
it('should convert from ui to api', () => {
|
||||
expect(uiToApiConverter(uiMockData)).toEqual(apiMockData);
|
||||
});
|
||||
});
|
||||
76
console-webapp/src/app/settings/security/security.service.ts
Normal file
76
console-webapp/src/app/settings/security/security.service.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { switchMap } from 'rxjs';
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
|
||||
interface ipAllowListItem {
|
||||
value: string;
|
||||
}
|
||||
export interface SecuritySettings {
|
||||
clientCertificate?: string;
|
||||
failoverClientCertificate?: string;
|
||||
ipAddressAllowList?: Array<ipAllowListItem>;
|
||||
}
|
||||
|
||||
export interface SecuritySettingsBackendModel {
|
||||
clientCertificate?: string;
|
||||
failoverClientCertificate?: string;
|
||||
ipAddressAllowList?: Array<string>;
|
||||
}
|
||||
|
||||
export function apiToUiConverter(
|
||||
securitySettings: SecuritySettingsBackendModel = {}
|
||||
): SecuritySettings {
|
||||
return Object.assign({}, securitySettings, {
|
||||
ipAddressAllowList: (securitySettings.ipAddressAllowList || []).map(
|
||||
(value) => ({ value })
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
export function uiToApiConverter(
|
||||
securitySettings: SecuritySettings
|
||||
): SecuritySettingsBackendModel {
|
||||
return Object.assign({}, securitySettings, {
|
||||
ipAddressAllowList: (securitySettings.ipAddressAllowList || [])
|
||||
.filter((s) => s.value)
|
||||
.map((ipAllowItem: ipAllowListItem) => ipAllowItem.value),
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SecurityService {
|
||||
securitySettings: SecuritySettings = {};
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
saveChanges(newSecuritySettings: SecuritySettings) {
|
||||
return this.backend
|
||||
.postSecuritySettings(
|
||||
this.registrarService.activeRegistrarId,
|
||||
uiToApiConverter(newSecuritySettings)
|
||||
)
|
||||
.pipe(
|
||||
switchMap(() => {
|
||||
return this.registrarService.loadRegistrars();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,9 @@
|
||||
.console-settings {
|
||||
.mdc-tab {
|
||||
&.active-link {
|
||||
border-bottom: 2px solid #673ab7;
|
||||
border-bottom: 2px solid var(--primary);
|
||||
.mdc-tab__text-label {
|
||||
color: #673ab7;
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SettingsComponent } from './settings.component';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('SettingsComponent', () => {
|
||||
let component: SettingsComponent;
|
||||
@@ -22,6 +24,7 @@ describe('SettingsComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
declarations: [SettingsComponent],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import { Component, ViewEncapsulation } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.less'],
|
||||
styleUrls: ['./settings.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class SettingsComponent {}
|
||||
export class SettingsComponent {
|
||||
public static PATH = 'settings';
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
@@ -17,6 +17,8 @@ import { Component } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'app-users',
|
||||
templateUrl: './users.component.html',
|
||||
styleUrls: ['./users.component.less'],
|
||||
styleUrls: ['./users.component.scss'],
|
||||
})
|
||||
export default class UsersComponent {}
|
||||
export default class UsersComponent {
|
||||
public static PATH = 'users';
|
||||
}
|
||||
|
||||
@@ -1 +1,250 @@
|
||||
<p>whois works!</p>
|
||||
<div class="settings-whois">
|
||||
<h2>WHOIS settings</h2>
|
||||
<h3>
|
||||
General registrar information for your WHOIS record. This information is
|
||||
always visible in WHOIS.
|
||||
</h3>
|
||||
<div *ngIf="loading" class="settings-whois__loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Name:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.registrarName"
|
||||
disabled
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>IANA Identifier:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.ianaIdentifier"
|
||||
disabled
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>ICANN Referral Email:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="email"
|
||||
[(ngModel)]="registrar.icannReferralEmail"
|
||||
disabled
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>WHOIS server:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.whoisServer"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Referral URL:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.url"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Email:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="email"
|
||||
[(ngModel)]="registrar.emailAddress"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Phone::</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.phoneNumber"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Fax:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.faxNumber"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-address">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Address Line 1:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
*ngIf="registrar.localizedAddress?.street"
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="(registrar.localizedAddress?.street)![0]"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section-address">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>City:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
*ngIf="registrar.localizedAddress"
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.localizedAddress.city"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-address">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Address Line 2:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
*ngIf="registrar.localizedAddress?.street"
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="(registrar.localizedAddress?.street)![1]"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section-address">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>State/Region:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
*ngIf="registrar.localizedAddress"
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.localizedAddress.state"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section">
|
||||
<div class="settings-whois__section-address">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Address Line 3:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
*ngIf="registrar.localizedAddress?.street"
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="(registrar.localizedAddress?.street)![2]"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__section-address">
|
||||
<div class="settings-whois__section-description">
|
||||
<h3>Country Code:</h3>
|
||||
</div>
|
||||
<div class="settings-whois__section-form">
|
||||
<mat-form-field>
|
||||
<input
|
||||
*ngIf="registrar.localizedAddress"
|
||||
matInput
|
||||
type="text"
|
||||
[(ngModel)]="registrar.localizedAddress.countryCode"
|
||||
[disabled]="!inEdit"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-whois__actions">
|
||||
<ng-template [ngIf]="inEdit" [ngIfElse]="inView">
|
||||
<button
|
||||
class="actions-save"
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="save()"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button class="actions-cancel" mat-stroked-button (click)="cancel()">
|
||||
Cancel
|
||||
</button>
|
||||
</ng-template>
|
||||
<ng-template #inView>
|
||||
<button #elseBlock mat-raised-button (click)="enableEdit()">Edit</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
59
console-webapp/src/app/settings/whois/whois.component.scss
Normal file
59
console-webapp/src/app/settings/whois/whois.component.scss
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
.settings-whois {
|
||||
margin-top: 1.5rem;
|
||||
&__section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
min-width: 400px;
|
||||
}
|
||||
&__section-address {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 5px;
|
||||
min-width: 400px;
|
||||
width: 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
&__section-description {
|
||||
display: inline-block;
|
||||
margin-block-start: 1em;
|
||||
width: 160px;
|
||||
}
|
||||
&__section-form {
|
||||
display: inline-block;
|
||||
width: 70%;
|
||||
mat-form-field {
|
||||
width: 90%;
|
||||
min-width: 300px;
|
||||
}
|
||||
input:disabled {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
&__loading {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
&__actions {
|
||||
margin-top: 50px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-right: 50px;
|
||||
button {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,65 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import {
|
||||
Registrar,
|
||||
RegistrarService,
|
||||
} from 'src/app/registrar/registrar.service';
|
||||
|
||||
import { WhoisService } from './whois.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-whois',
|
||||
templateUrl: './whois.component.html',
|
||||
styleUrls: ['./whois.component.less'],
|
||||
styleUrls: ['./whois.component.scss'],
|
||||
providers: [WhoisService],
|
||||
})
|
||||
export default class WhoisComponent {}
|
||||
export default class WhoisComponent {
|
||||
public static PATH = 'whois';
|
||||
loading = false;
|
||||
inEdit = false;
|
||||
registrar: Registrar;
|
||||
|
||||
constructor(
|
||||
public whoisService: WhoisService,
|
||||
public registrarService: RegistrarService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
this.registrar = JSON.parse(
|
||||
JSON.stringify(this.registrarService.registrar)
|
||||
);
|
||||
}
|
||||
|
||||
enableEdit() {
|
||||
this.inEdit = true;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.inEdit = false;
|
||||
this.resetDataSource();
|
||||
}
|
||||
|
||||
save() {
|
||||
this.loading = true;
|
||||
this.whoisService.saveChanges(this.registrar).subscribe({
|
||||
complete: () => {
|
||||
this.loading = false;
|
||||
this.resetDataSource();
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error);
|
||||
this.loading = false;
|
||||
},
|
||||
});
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
resetDataSource() {
|
||||
this.registrar = JSON.parse(
|
||||
JSON.stringify(this.registrarService.registrar)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
45
console-webapp/src/app/settings/whois/whois.service.ts
Normal file
45
console-webapp/src/app/settings/whois/whois.service.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { switchMap } from 'rxjs';
|
||||
import { Address, RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
|
||||
export interface WhoisRegistrarFields {
|
||||
ianaIdentifier?: number;
|
||||
icannReferralEmail?: string;
|
||||
localizedAddress?: Address;
|
||||
registrarId?: string;
|
||||
url?: string;
|
||||
whoisServer?: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class WhoisService {
|
||||
whoisRegistrarFields: WhoisRegistrarFields = {};
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
saveChanges(newWhoisRegistrarFields: WhoisRegistrarFields) {
|
||||
return this.backend.postWhoisRegistrarFields(newWhoisRegistrarFields).pipe(
|
||||
switchMap(() => {
|
||||
return this.registrarService.loadRegistrars();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { ComponentType } from '@angular/cdk/portal';
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
MatBottomSheet,
|
||||
MatBottomSheetRef,
|
||||
} from '@angular/material/bottom-sheet';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
const MOBILE_LAYOUT_BREAKPOINT = '(max-width: 599px)';
|
||||
|
||||
export interface DialogBottomSheetContent {
|
||||
init(data: Object): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps up a child component in an Angular Material Dalog for desktop or a Bottom Sheet
|
||||
* component for mobile depending on a screen resolution, with Breaking Point being 599px.
|
||||
* Child component is required to implement @see DialogBottomSheetContent interface
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-dialog-bottom-sheet-wrapper',
|
||||
template: '',
|
||||
})
|
||||
export class DialogBottomSheetWrapper {
|
||||
private elementRef?: MatBottomSheetRef | MatDialogRef<any>;
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private bottomSheet: MatBottomSheet,
|
||||
protected breakpointObserver: BreakpointObserver
|
||||
) {}
|
||||
|
||||
open<T extends DialogBottomSheetContent>(
|
||||
component: ComponentType<T>,
|
||||
data: any
|
||||
) {
|
||||
const config = { data, close: () => this.close() };
|
||||
if (this.breakpointObserver.isMatched(MOBILE_LAYOUT_BREAKPOINT)) {
|
||||
this.elementRef = this.bottomSheet.open(component);
|
||||
this.elementRef.instance.init(config);
|
||||
} else {
|
||||
this.elementRef = this.dialog.open(component);
|
||||
this.elementRef.componentInstance.init(config);
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.elementRef instanceof MatBottomSheetRef) {
|
||||
this.elementRef.dismiss();
|
||||
} else if (this.elementRef instanceof MatDialogRef) {
|
||||
this.elementRef.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable, catchError, of } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { catchError, Observable, of } from 'rxjs';
|
||||
import { SecuritySettingsBackendModel } from 'src/app/settings/security/security.service';
|
||||
|
||||
import { Contact } from '../../settings/contact/contact.service';
|
||||
import { Registrar } from '../../registrar/registrar.service';
|
||||
import { UserData } from './userData.service';
|
||||
import { WhoisRegistrarFields } from 'src/app/settings/whois/whois.service';
|
||||
import { DomainListResult } from 'src/app/domains/domainList.service';
|
||||
|
||||
@Injectable()
|
||||
export class BackendService {
|
||||
@@ -54,13 +60,81 @@ export class BackendService {
|
||||
): Observable<Contact[]> {
|
||||
return this.http.post<Contact[]>(
|
||||
`/console-api/settings/contacts?registrarId=${registrarId}`,
|
||||
{ contacts }
|
||||
contacts
|
||||
);
|
||||
}
|
||||
|
||||
getRegistrars(): Observable<string[]> {
|
||||
getDomains(
|
||||
registrarId: string,
|
||||
checkpointTime?: string,
|
||||
pageNumber?: number,
|
||||
resultsPerPage?: number,
|
||||
totalResults?: number,
|
||||
searchTerm?: string
|
||||
): Observable<DomainListResult> {
|
||||
var url = `/console-api/domain-list?registrarId=${registrarId}`;
|
||||
if (checkpointTime) {
|
||||
url += `&checkpointTime=${checkpointTime}`;
|
||||
}
|
||||
if (pageNumber) {
|
||||
url += `&pageNumber=${pageNumber}`;
|
||||
}
|
||||
if (resultsPerPage) {
|
||||
url += `&resultsPerPage=${resultsPerPage}`;
|
||||
}
|
||||
if (totalResults) {
|
||||
url += `&totalResults=${totalResults}`;
|
||||
}
|
||||
if (searchTerm) {
|
||||
url += `&searchTerm=${searchTerm}`;
|
||||
}
|
||||
return this.http
|
||||
.get<string[]>('/console-api/registrars')
|
||||
.pipe(catchError((err) => this.errorCatcher<string[]>(err)));
|
||||
.get<DomainListResult>(url)
|
||||
.pipe(catchError((err) => this.errorCatcher<DomainListResult>(err)));
|
||||
}
|
||||
|
||||
getRegistrars(): Observable<Registrar[]> {
|
||||
return this.http
|
||||
.get<Registrar[]>('/console-api/registrars')
|
||||
.pipe(catchError((err) => this.errorCatcher<Registrar[]>(err)));
|
||||
}
|
||||
|
||||
getSecuritySettings(
|
||||
registrarId: string
|
||||
): Observable<SecuritySettingsBackendModel> {
|
||||
return this.http
|
||||
.get<SecuritySettingsBackendModel>(
|
||||
`/console-api/settings/security?registrarId=${registrarId}`
|
||||
)
|
||||
.pipe(
|
||||
catchError((err) =>
|
||||
this.errorCatcher<SecuritySettingsBackendModel>(err)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
postSecuritySettings(
|
||||
registrarId: string,
|
||||
securitySettings: SecuritySettingsBackendModel
|
||||
): Observable<SecuritySettingsBackendModel> {
|
||||
return this.http.post<SecuritySettingsBackendModel>(
|
||||
`/console-api/settings/security?registrarId=${registrarId}`,
|
||||
securitySettings
|
||||
);
|
||||
}
|
||||
|
||||
getUserData(): Observable<UserData> {
|
||||
return this.http
|
||||
.get<UserData>('/console-api/userdata')
|
||||
.pipe(catchError((err) => this.errorCatcher<UserData>(err)));
|
||||
}
|
||||
|
||||
postWhoisRegistrarFields(
|
||||
whoisRegistrarFields: WhoisRegistrarFields
|
||||
): Observable<WhoisRegistrarFields> {
|
||||
return this.http.post<WhoisRegistrarFields>(
|
||||
'/console-api/settings/whois-fields',
|
||||
whoisRegistrarFields
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subscription, timeout } from 'rxjs';
|
||||
|
||||
export interface GlobalLoader {
|
||||
loadingTimeout: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class responsible for global application loading indicator
|
||||
*
|
||||
* <p>Only to be used for when the activity should indicate that the entire application is busy
|
||||
* For instance - when initial user information is loading, which is crucial for any subsequent
|
||||
* interaction with the application
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class GlobalLoaderService {
|
||||
private static readonly TIMEOUT_MS = 3000;
|
||||
private loaders = new Map<GlobalLoader, Subscription>();
|
||||
public isLoading: boolean = false;
|
||||
|
||||
private syncLoading() {
|
||||
this.isLoading = this.loaders.size > 0;
|
||||
}
|
||||
|
||||
startGlobalLoader(c: GlobalLoader) {
|
||||
const subscription = new Observable(() => {})
|
||||
.pipe(timeout(GlobalLoaderService.TIMEOUT_MS))
|
||||
.subscribe({
|
||||
error: () => {
|
||||
this.loaders.delete(c);
|
||||
c.loadingTimeout();
|
||||
this.syncLoading();
|
||||
},
|
||||
});
|
||||
this.loaders.set(c, subscription);
|
||||
this.syncLoading();
|
||||
}
|
||||
|
||||
stopGlobalLoader(c: GlobalLoader) {
|
||||
this.loaders.get(c)?.unsubscribe();
|
||||
this.loaders.delete(c);
|
||||
this.syncLoading();
|
||||
}
|
||||
}
|
||||
57
console-webapp/src/app/shared/services/userData.service.ts
Normal file
57
console-webapp/src/app/shared/services/userData.service.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import { BackendService } from './backend.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { GlobalLoader, GlobalLoaderService } from './globalLoader.service';
|
||||
|
||||
export interface UserData {
|
||||
globalRole: string;
|
||||
isAdmin: boolean;
|
||||
productName: string;
|
||||
supportEmail: string;
|
||||
supportPhoneNumber: string;
|
||||
technicalDocsUrl: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UserDataService implements GlobalLoader {
|
||||
public userData?: UserData;
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
protected globalLoader: GlobalLoaderService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
this.getUserData().subscribe(() => {
|
||||
this.globalLoader.stopGlobalLoader(this);
|
||||
});
|
||||
this.globalLoader.startGlobalLoader(this);
|
||||
}
|
||||
|
||||
getUserData(): Observable<UserData> {
|
||||
return this.backend.getUserData().pipe(
|
||||
tap((userData: UserData) => {
|
||||
this.userData = userData;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
loadingTimeout() {
|
||||
this._snackBar.open('Timeout loading user data');
|
||||
}
|
||||
}
|
||||
24
console-webapp/src/app/snackbar.module.ts
Normal file
24
console-webapp/src/app/snackbar.module.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
||||
|
||||
/** Provides a default set of options for the snack bar. */
|
||||
@NgModule({
|
||||
providers: [
|
||||
{ provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 5000 } },
|
||||
],
|
||||
})
|
||||
export class SnackBarModule {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user