mirror of
https://github.com/google/nomulus
synced 2026-01-22 21:53:02 +00:00
Compare commits
304 Commits
proxy-2023
...
proxy-2024
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e492936cec | ||
|
|
d1d59c1afd | ||
|
|
7b786eaf1f | ||
|
|
45c5d12743 | ||
|
|
73ab95bd9d | ||
|
|
f85cf57e36 | ||
|
|
5e36cf30c3 | ||
|
|
829be0777b | ||
|
|
c0ac9bdba4 | ||
|
|
58ec0f826d | ||
|
|
f9e0908022 | ||
|
|
b21e1a1935 | ||
|
|
0112b3ae06 | ||
|
|
a4903c27b9 | ||
|
|
2166c28d6d | ||
|
|
891e7c0174 | ||
|
|
64f5971275 | ||
|
|
818944317f | ||
|
|
ea96ed300f | ||
|
|
8415c8bbe4 | ||
|
|
dc48c257b5 | ||
|
|
2bf3867532 | ||
|
|
44f44be643 | ||
|
|
f61579b350 | ||
|
|
c414e38a98 | ||
|
|
2cf2d7e7b1 | ||
|
|
432871add9 | ||
|
|
2621b2d679 | ||
|
|
7a5db3b8fe | ||
|
|
055f9c012c | ||
|
|
14ab9423f8 | ||
|
|
9223b81ab3 | ||
|
|
1dcf34ccc2 | ||
|
|
9273d2bf15 | ||
|
|
036d35c11a | ||
|
|
a8ce34586d | ||
|
|
26fb04f00c | ||
|
|
9d4c38684a | ||
|
|
d7edd27cdd | ||
|
|
265d69051b | ||
|
|
b5d2b56426 | ||
|
|
e79c63142a | ||
|
|
f8ac7afc33 | ||
|
|
e56e751652 | ||
|
|
cfdf12aa7d | ||
|
|
811b385544 | ||
|
|
3f5c9d1246 | ||
|
|
5315752bc0 | ||
|
|
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 | ||
|
|
304e7c9726 | ||
|
|
3ea31d024e | ||
|
|
c24177e8a6 | ||
|
|
bef28d2e34 | ||
|
|
cc3901691c | ||
|
|
8d22c2a8d8 | ||
|
|
fe19f0fe78 | ||
|
|
599a55d5b1 | ||
|
|
845f792044 | ||
|
|
ad68052524 | ||
|
|
04c6652793 | ||
|
|
5658fbe8bd | ||
|
|
a4540a847a | ||
|
|
fdfbb9572d | ||
|
|
cf1a148208 | ||
|
|
6b54b69163 | ||
|
|
a839ec434e | ||
|
|
86b62ebe76 | ||
|
|
952a92a5db | ||
|
|
bc57f319e5 | ||
|
|
a9aaa11801 | ||
|
|
b319eff7cd | ||
|
|
894d05ce4e | ||
|
|
cf0486a5d3 | ||
|
|
798a6ffc74 | ||
|
|
fe86ef0a7d | ||
|
|
9dd41947e0 | ||
|
|
931a350f3d | ||
|
|
db1b92638f | ||
|
|
74baae397a | ||
|
|
fddecea18e | ||
|
|
36a60bdf8b | ||
|
|
58ed53314c | ||
|
|
5eaf99e02a | ||
|
|
9a5f094d1d | ||
|
|
6cbc2fa5ef | ||
|
|
6883093735 | ||
|
|
a6078bc4f4 | ||
|
|
6b75cf8496 | ||
|
|
219e9d3afb | ||
|
|
acdbc65c51 | ||
|
|
d510531f65 | ||
|
|
0d4dd57fe7 | ||
|
|
2667a0e977 | ||
|
|
1aef31efff | ||
|
|
4d19245c29 | ||
|
|
4b34307a6e | ||
|
|
55243e7cf6 | ||
|
|
e14764b4c8 | ||
|
|
68810f7a30 | ||
|
|
14d245b1e3 | ||
|
|
61ab29ae9e | ||
|
|
6742e5bf23 | ||
|
|
c7f69eba1d | ||
|
|
578988d5ea | ||
|
|
c17b8285f9 | ||
|
|
ff8a08f40e | ||
|
|
a341058282 | ||
|
|
16758879f0 | ||
|
|
2021247ab4 | ||
|
|
4fc7038690 | ||
|
|
9272e7fd14 | ||
|
|
e1afe00758 | ||
|
|
203c20c040 | ||
|
|
bd0cea0d87 | ||
|
|
23fb69a682 | ||
|
|
597f63a603 | ||
|
|
5ec73f3809 | ||
|
|
b474e50e87 | ||
|
|
6f3d062c32 | ||
|
|
371d83b4cc | ||
|
|
e1f29a8103 | ||
|
|
055a52f67e | ||
|
|
d17678959c | ||
|
|
79ba1b94c4 | ||
|
|
33a771b13e | ||
|
|
bd65c6eee6 | ||
|
|
20c673840e | ||
|
|
11c60b8c8f | ||
|
|
e330fd1c66 | ||
|
|
57c17042b6 | ||
|
|
8623fce119 | ||
|
|
7243575433 | ||
|
|
8eab43d371 | ||
|
|
34d329c158 | ||
|
|
425ecdcd87 | ||
|
|
77ee124374 |
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: '17'
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
|
||||
4
.gitignore
vendored
4
.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/
|
||||
@@ -103,7 +105,7 @@ nomulus.iws
|
||||
.gradle/
|
||||
**/build
|
||||
cloudbuild-caches/
|
||||
node_modules/**
|
||||
**/node_modules/**
|
||||
/repos/
|
||||
|
||||
# Compiled JS/CSS code
|
||||
|
||||
@@ -103,7 +103,7 @@ explodeWar.doLast {
|
||||
file("${it.explodedAppDirectory}/WEB-INF/lib/tools.jar").setWritable(true)
|
||||
}
|
||||
|
||||
appengineDeployAll.finalizedBy ':cloudSchedulerDeployer'
|
||||
appengineDeployAll.finalizedBy ':deployCloudSchedulerAndQueue'
|
||||
rootProject.deploy.dependsOn appengineDeployAll
|
||||
rootProject.stage.dependsOn appengineStage
|
||||
tasks['war'].dependsOn ':console-webapp:buildConsoleWebappProd'
|
||||
|
||||
114
build.gradle
114
build.gradle
@@ -29,7 +29,7 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.4.1'
|
||||
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:2.0.2'
|
||||
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:3.1.0'
|
||||
classpath 'org.sonatype.aether:aether-api:1.13.1'
|
||||
classpath 'org.sonatype.aether:aether-impl:1.13.1'
|
||||
}
|
||||
@@ -37,17 +37,19 @@ buildscript {
|
||||
|
||||
plugins {
|
||||
// Java static analysis plugins. Keep versions consistent with
|
||||
// ./buildSrc/build.gradle
|
||||
id 'nebula.lint' version '16.0.2'
|
||||
id 'net.ltgt.errorprone' version '2.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 '3.1.0'
|
||||
id 'checkstyle'
|
||||
id 'com.github.johnrengelman.shadow' version '5.1.0'
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1'
|
||||
|
||||
// NodeJs plugin
|
||||
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 = "20.10.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,32 @@ 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")
|
||||
options.compilerArgs = ["--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"]
|
||||
options.forkOptions.jvmArgs = ["-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,14 +295,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
|
||||
@@ -305,8 +331,7 @@ subprojects {
|
||||
|
||||
afterEvaluate {
|
||||
if (rootProject.enableDependencyLocking.toBoolean()
|
||||
&& project.name != 'integration'
|
||||
&& project.name != 'java8compatibility') {
|
||||
&& project.name != 'integration') {
|
||||
// The ':integration' project runs server/schema integration tests using
|
||||
// dynamically specified jars with no transitive dependency. Therefore
|
||||
// dependency-locking does not make sense. Furthermore, during
|
||||
@@ -314,9 +339,6 @@ subprojects {
|
||||
// immutable. Locking activation would trigger an invalid operation
|
||||
// exception.
|
||||
//
|
||||
// The ':java8compatibility' project is test-only. Its source does not go
|
||||
// into production.
|
||||
//
|
||||
// For all other projects, due to problem with the gradle-license-report
|
||||
// plugin, the dependencyLicenseReport configuration must opt out of
|
||||
// dependency-locking. See dependency_lic.gradle for the reason why.
|
||||
@@ -332,8 +354,20 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
// 'listenablefuture' is folded into guava since v32. This block is required
|
||||
// until all transitive dependencies have upgraded past guava v32.
|
||||
// TODO(periodically): remove this block and see if build succeeds.
|
||||
configurations.all {
|
||||
resolutionStrategy
|
||||
.capabilitiesResolution
|
||||
.withCapability("com.google.guava:listenablefuture") {
|
||||
select("com.google.guava:guava:0")
|
||||
}
|
||||
}
|
||||
|
||||
def services = [':services:default',
|
||||
':services:backend',
|
||||
':services:bsa',
|
||||
':services:tools',
|
||||
':services:pubapi']
|
||||
|
||||
@@ -348,12 +382,11 @@ subprojects {
|
||||
|
||||
apply from: "${rootDir.path}/java_common.gradle"
|
||||
|
||||
if (project.name != 'docs') {
|
||||
compileJava {
|
||||
// TODO: Remove this once we migrate off AppEngine.
|
||||
options.release = 8
|
||||
}
|
||||
}
|
||||
// When changing Java version here, be sure to update BEAM Java runtime:
|
||||
// in core/build.gradle, search for `flex-template-base-image` and update
|
||||
// the parameter value.
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
project.tasks.test.dependsOn runPresubmits
|
||||
|
||||
@@ -465,10 +498,14 @@ def createGetBuildSrcDirectDepsTask(outputFileName) {
|
||||
|
||||
rootProject.ext {
|
||||
invokeJavaDiffFormatScript = { action ->
|
||||
println("JAVA_HOME=${System.env.JAVA_HOME}")
|
||||
println("PATH=${System.env.PATH}")
|
||||
println(ext.execInBash("type java", "${rootDir}"))
|
||||
println(ext.execInBash("java -version", "${rootDir}"))
|
||||
def javaHome = project.findProperty('org.gradle.java.home')
|
||||
def javaBin
|
||||
if (javaHome != null) {
|
||||
javaBin = "$javaHome/bin/java"
|
||||
} else {
|
||||
javaBin = ext.execInBash("which java", rootDir)
|
||||
}
|
||||
println("Running the formatting tool with $javaBin")
|
||||
def scriptDir = rootDir.path.endsWith('buildSrc')
|
||||
? "${rootDir}/../java-format"
|
||||
: "${rootDir}/java-format"
|
||||
@@ -479,7 +516,7 @@ rootProject.ext {
|
||||
def pythonExe = getPythonExecutable()
|
||||
|
||||
return ext.execInBash(
|
||||
"PYTHON=${pythonExe} ${formatDiffScript} ${action}", "${workingDir}")
|
||||
"JAVA=${javaBin} PYTHON=${pythonExe} ${formatDiffScript} ${action}", "${workingDir}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,6 +585,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'
|
||||
@@ -558,17 +596,27 @@ task coreDev {
|
||||
|
||||
javadocDependentTasks.each { tasks.javadoc.dependsOn(it) }
|
||||
|
||||
// Runs the script, which deploys cloud scheduler tasks based on the config
|
||||
task cloudSchedulerDeployer {
|
||||
// Runs the script, which deploys cloud scheduler and tasks based on the config
|
||||
task deployCloudSchedulerAndQueue {
|
||||
doLast {
|
||||
def env = environment
|
||||
if (!prodOrSandboxEnv) {
|
||||
exec {
|
||||
workingDir "${rootDir}/release/builder/"
|
||||
commandLine 'go', 'run',
|
||||
"${rootDir}/release/builder/cloudSchedulerDeployer.go",
|
||||
"./deployCloudSchedulerAndQueue.go",
|
||||
"${rootDir}/core/src/main/java/google/registry/config/files/nomulus-config-${env}.yaml",
|
||||
"${rootDir}/core/src/main/java/google/registry/env/${env}/default/WEB-INF/cloud-scheduler-tasks.xml",
|
||||
"domain-registry-${env}"
|
||||
}
|
||||
exec {
|
||||
workingDir "${rootDir}/release/builder/"
|
||||
commandLine 'go', 'run',
|
||||
"./deployCloudSchedulerAndQueue.go",
|
||||
"${rootDir}/core/src/main/java/google/registry/config/files/nomulus-config-${env}.yaml",
|
||||
"${rootDir}/core/src/main/java/google/registry/env/common/default/WEB-INF/cloud-tasks-queue.xml",
|
||||
"domain-registry-${env}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
id("net.ltgt.errorprone") version "2.0.2"
|
||||
|
||||
// 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 "3.1.0"
|
||||
checkstyle
|
||||
id("com.diffplug.gradle.spotless") version "3.25.0"
|
||||
id("com.diffplug.spotless") version "6.20.0"
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
@@ -69,16 +72,23 @@ apply(from = "../dependencies.gradle")
|
||||
apply(from = "../dependency_lic.gradle")
|
||||
apply(from = "../java_common.gradle")
|
||||
|
||||
// 'listenablefuture' is folded into guava since v32. This block is required
|
||||
// until all transitive dependencies have upgraded past guava v32.
|
||||
// TODO(periodically): remove this block and see if build succeeds.
|
||||
configurations.all {
|
||||
resolutionStrategy
|
||||
.capabilitiesResolution
|
||||
.withCapability("com.google.guava:listenablefuture") {
|
||||
select("com.google.guava:guava:0")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -108,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
|
||||
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
|
||||
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:3.1.0=classpath
|
||||
net.ltgt.gradle:gradle-errorprone-plugin:3.1.0=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.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.9.20=classpath
|
||||
org.jetbrains:annotations:13.0=classpath
|
||||
org.slf4j:slf4j-api:1.7.36=classpath
|
||||
org.tukaani:xz:1.9=classpath
|
||||
empty=
|
||||
|
||||
@@ -1,142 +1,106 @@
|
||||
# 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.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson:jackson-bom:2.14.1=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.1.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-common-protos:2.13.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.8.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:api-common:2.5.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-grpc:2.22.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:0.107.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.22.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20220705-2.0.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.14.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.14.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.1=annotationProcessor,compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto:auto-common:0.10=annotationProcessor,testAnnotationProcessor
|
||||
com.google.cloud:google-cloud-core-grpc:2.9.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.9.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core:2.9.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-storage:2.17.2=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,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:27.0.1-jre=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:29.0-jre=checkstyle
|
||||
com.google.guava:guava:31.1-jre=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:1.42.3=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:1.42.3=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-gson:1.42.3=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-jackson2:1.42.3=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:1.42.3=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,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.21.12=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:3.21.12=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.re2j:re2j:1.6=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.3=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.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-api:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-auth:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-context:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-core:1.52.1=testRuntimeClasspath
|
||||
io.grpc:grpc-googleapis:1.52.1=testRuntimeClasspath
|
||||
io.grpc:grpc-grpclb:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-netty-shaded:1.52.1=testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf-lite:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-services:1.52.1=testRuntimeClasspath
|
||||
io.grpc:grpc-stub:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-xds:1.52.1=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.22=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.12.22=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.13=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.httpcomponents:httpcore:4.4.15=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.29.0=compileClasspath,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.22=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.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.2.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,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.5=compileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
aopalliance:aopalliance:1.0=annotationProcessor,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:3.0.5=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.service:auto-service-annotations:1.0.1=annotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.10.1=buildScriptClasspath,compileClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor
|
||||
com.google.auto.value:auto-value:1.10.4=annotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=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: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.23.0=annotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,buildScriptClasspath,compileClasspath
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.23.0=annotationProcessor
|
||||
com.google.escapevelocity:escapevelocity:0.9.1=buildScriptClasspath,compileClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor
|
||||
com.google.guava:failureaccess:1.0.2=buildScriptClasspath,compileClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=annotationProcessor
|
||||
com.google.guava:guava:32.1.1-jre=annotationProcessor
|
||||
com.google.guava:guava:33.0.0-jre=buildScriptClasspath,compileClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=buildScriptClasspath,compileClasspath
|
||||
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.inject:guice:5.1.0=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.19.6=annotationProcessor
|
||||
com.google.protobuf:protobuf-java:3.23.2=buildScriptClasspath,compileClasspath
|
||||
com.google.re2j:re2j:1.6=buildScriptClasspath
|
||||
com.google.template:soy:2021-02-01=buildScriptClasspath,compileClasspath
|
||||
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.github.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor
|
||||
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=annotationProcessor,buildScriptClasspath,compileClasspath
|
||||
org.apache.commons:commons-lang3:3.13.0=buildScriptClasspath,compileClasspath
|
||||
org.apache.commons:commons-text:1.11.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.33.0=annotationProcessor
|
||||
org.checkerframework:checker-qual:3.41.0=buildScriptClasspath,compileClasspath
|
||||
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:3.1.4=annotationProcessor
|
||||
org.threeten:threetenbp:1.6.8=buildScriptClasspath,compileClasspath
|
||||
empty=
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Creates the files for a web-page summary of a given {@Link ProjectData}.
|
||||
* Creates the files for a web-page summary of a given {@link ProjectData}.
|
||||
*
|
||||
* <p>The main job of this class is rendering a tailored cover page that includes information about
|
||||
* the project and any task that ran.
|
||||
|
||||
@@ -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,14 +4,15 @@
|
||||
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
|
||||
com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:5.1.0=classpath
|
||||
com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:8.1.1=classpath
|
||||
com.github.johnrengelman:shadow:8.1.1=classpath
|
||||
com.github.node-gradle.node:com.github.node-gradle.node.gradle.plugin:3.0.1=classpath
|
||||
com.github.node-gradle:gradle-node-plugin:3.0.1=classpath
|
||||
com.google.cloud.tools:appengine-gradle-plugin:2.4.1=classpath
|
||||
@@ -24,56 +25,38 @@ 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
|
||||
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
|
||||
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
|
||||
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.11.0=classpath
|
||||
dev.equo.ide:solstice:1.3.1=classpath
|
||||
net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:3.1.0=classpath
|
||||
net.ltgt.gradle:gradle-errorprone-plugin:3.1.0=classpath
|
||||
org.apache.ant:ant-launcher:1.10.13=classpath
|
||||
org.apache.ant:ant:1.10.13=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.5.1=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.jdom:jdom2:2.0.6.1=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-commons:9.4=classpath
|
||||
org.ow2.asm:asm-tree:9.4=classpath
|
||||
org.ow2.asm:asm:9.4=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.vafer:jdependency:2.1.1=classpath
|
||||
org.tukaani:xz:1.9=classpath
|
||||
org.vafer:jdependency:2.8.0=classpath
|
||||
org.yaml:snakeyaml:1.21=classpath
|
||||
empty=
|
||||
|
||||
@@ -1,68 +1,67 @@
|
||||
# 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
|
||||
aopalliance:aopalliance:1.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:2.9.3=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.github.ben-manes.caffeine:caffeine:3.0.5=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
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: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.errorprone:error_prone_annotation:2.3.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.11.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_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:27.0.1-jre=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:29.0-jre=checkstyle
|
||||
com.google.guava:guava:31.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,compileClasspath,default,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,compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,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.googlecode.java-diff-utils:diffutils:1.3.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.puppycrawl.tools:checkstyle:8.37=checkstyle
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.10.4=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
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.23.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.7.1=checkstyle
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:javac:9+181-r4173-1=errorproneJavac
|
||||
com.google.flogger:flogger:0.8=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,checkstyle,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.2=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:31.0.1-jre=checkstyle
|
||||
com.google.guava:guava:32.1.1-jre=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:33.0.0-jre=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.inject:guice:5.1.0=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.19.6=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.truth:truth:1.2.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
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.2=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.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
javax.inject:javax.inject:1=annotationProcessor,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
joda-time:joda-time:2.12.6=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-qual:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.19.0=compileClasspath,default,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.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.2.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.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.checkerframework:checker-compat-qual:2.5.3=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.checkerframework:checker-qual:3.12.0=checkstyle
|
||||
org.checkerframework:checker-qual:3.33.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.42.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
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.1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.10.1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.10.1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.10.1=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.10.1=testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.5=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.5=jacocoAnt
|
||||
org.ow2.asm:asm:9.5=jacocoAnt
|
||||
org.ow2.asm:asm:9.6=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
empty=testingCompile,testingRuntime,testingRuntimeClasspath
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
|
||||
package google.registry.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.Iterators.partition;
|
||||
import static com.google.common.collect.Iterators.transform;
|
||||
import static com.google.common.collect.Streams.stream;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/** Utilities for breaking up a {@link Stream} into batches. */
|
||||
public final class BatchedStreams {
|
||||
|
||||
static final int MAX_BATCH = 1024 * 1024;
|
||||
|
||||
private BatchedStreams() {}
|
||||
|
||||
/**
|
||||
* Transform a flat {@link Stream} into a {@code Stream} of batches.
|
||||
*
|
||||
* <p>Closing the returned stream does not close the original stream.
|
||||
*/
|
||||
public static <T> Stream<ImmutableList<T>> toBatches(Stream<T> stream, int batchSize) {
|
||||
checkArgument(batchSize > 0, "batchSize must be a positive integer.");
|
||||
return stream(
|
||||
transform(partition(stream.iterator(), min(MAX_BATCH, batchSize)), ImmutableList::copyOf));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// 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.
|
||||
|
||||
package google.registry.util;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.util.BatchedStreams.toBatches;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link BatchedStreams}. */
|
||||
public class BatchedStreamsTest {
|
||||
|
||||
@Test
|
||||
void invalidBatchSize() {
|
||||
assertThat(assertThrows(IllegalArgumentException.class, () -> toBatches(Stream.of(), 0)))
|
||||
.hasMessageThat()
|
||||
.contains("must be a positive integer");
|
||||
}
|
||||
|
||||
@Test
|
||||
void batch_success() {
|
||||
// 900_002 elements -> 900 1K-batches + 1 2-element-batch
|
||||
Stream<Integer> data = IntStream.rangeClosed(0, 900_001).boxed();
|
||||
assertThat(
|
||||
toBatches(data, 1000).map(ImmutableList::size).collect(groupingBy(x -> x, counting())))
|
||||
.containsExactly(1000, 900L, 2, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void batch_partialBatch() {
|
||||
Stream<Integer> data = Stream.of(1, 2, 3);
|
||||
assertThat(
|
||||
toBatches(data, 1000).map(ImmutableList::size).collect(groupingBy(x -> x, counting())))
|
||||
.containsExactly(3, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void batch_truncateBatchSize() {
|
||||
// 2M elements -> 2 1M-batches despite the user-specified 2M batch size.
|
||||
Stream<Integer> data = IntStream.range(0, 1024 * 2048).boxed();
|
||||
assertThat(
|
||||
toBatches(data, 2_000_000)
|
||||
.map(ImmutableList::size)
|
||||
.collect(groupingBy(x -> x, counting())))
|
||||
.containsExactly(1024 * 1024, 2L);
|
||||
}
|
||||
}
|
||||
@@ -49,13 +49,11 @@ public final class SystemInfo {
|
||||
/**
|
||||
* Returns {@code true} if system command can be run from path.
|
||||
*
|
||||
* <p><b>Warning:</b> The command is actually run! So there could be side-effects. You might
|
||||
* need to specify a version flag or something. Return code is ignored.
|
||||
* <p><b>Warning:</b> The command is actually run! So there could be side-effects. You might need
|
||||
* to specify a version flag or something. Return code is ignored.
|
||||
*
|
||||
* <p>This result is a memoized. If multiple therads try to get the same result at once, the
|
||||
* heavy lifting will only be performed by the first thread and the rest will wait.
|
||||
*
|
||||
* @throws ExecutionException
|
||||
* <p>This result is a memoized. If multiple therads try to get the same result at once, the heavy
|
||||
* lifting will only be performed by the first thread and the rest will wait.
|
||||
*/
|
||||
public static boolean hasCommand(String cmd) throws ExecutionException {
|
||||
return hasCommandCache.get(cmd);
|
||||
|
||||
@@ -287,6 +287,12 @@
|
||||
"moduleLicense": null,
|
||||
"moduleName": "com.fasterxml.jackson:jackson-bom"
|
||||
},
|
||||
{
|
||||
// Part of Guava with "Apache License, Version 2.0". The plugin is unable
|
||||
// to parse its license for unknown reason.
|
||||
"moduleLicense": null,
|
||||
"moduleName": "com.google.guava:guava-parent"
|
||||
},
|
||||
{
|
||||
// "Apache License, Version 2.0". The plugin is able to parse up to
|
||||
// 2.0.33.Final but not this verson.
|
||||
@@ -301,6 +307,24 @@
|
||||
},
|
||||
{
|
||||
"moduleLicense": "The W3C Software License"
|
||||
},
|
||||
{
|
||||
// "Apache License, Version 2.0".
|
||||
"moduleLicense": null,
|
||||
"moduleName": "com.squareup.okhttp3:okhttp"
|
||||
},
|
||||
{
|
||||
// "Apache License, Version 2.0".
|
||||
"moduleLicense": null,
|
||||
"moduleName": "com.squareup.okio:okio"
|
||||
},
|
||||
{
|
||||
"moduleLicense": "(GPL-2.0-only WITH Classpath-exception-2.0)",
|
||||
"moduleName": "io.github.eisop:dataflow-errorprone"
|
||||
},
|
||||
{
|
||||
"moduleLicense": "GNU General Public License, version 2 (GPL2), with the classpath exception",
|
||||
"moduleName": "io.github.eisop:dataflow-errorprone"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -99,8 +99,6 @@ PROPERTIES = [
|
||||
'If true, show all test output in near-realtime.',
|
||||
'false',
|
||||
bool),
|
||||
Property('flowDocsFile',
|
||||
'Output filename for the flowDocsTool command.'),
|
||||
Property('enableDependencyLocking',
|
||||
'Enables dependency locking.',
|
||||
'true',
|
||||
|
||||
@@ -25,7 +25,7 @@ import textwrap
|
||||
import re
|
||||
|
||||
# We should never analyze any generated files
|
||||
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "cloudbuild-caches", "/out/", ".git/", ".gradle/", "/dist/", "karma.conf.js", "polyfills.ts", "test.ts"}
|
||||
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "cloudbuild-caches", "/out/", ".git/", ".gradle/", "/dist/", "karma.conf.js", "polyfills.ts", "test.ts", "/docs/console-endpoints/"}
|
||||
# We can't rely on CI to have the Enum package installed so we do this instead.
|
||||
FORBIDDEN = 1
|
||||
REQUIRED = 2
|
||||
@@ -87,7 +87,7 @@ PRESUBMITS = {
|
||||
PresubmitCheck(
|
||||
r".*Copyright 20\d{2} The Nomulus Authors\. All Rights Reserved\.",
|
||||
("java", "js", "soy", "sql", "py", "sh", "gradle", "ts"), {
|
||||
".git", "/build/", "/generated/", "/generated_tests/",
|
||||
".git", "/build/", "/bin/generated-sources/", "/bin/generated-test-sources/",
|
||||
"node_modules/", "LoggerConfig.java", "registrar_bin.",
|
||||
"registrar_dbg.", "google-java-format-diff.py",
|
||||
"nomulus.golden.sql", "soyutils_usegoog.js", "javascript/checks.js"
|
||||
@@ -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 ",
|
||||
|
||||
50
console-webapp/.eslintrc.json
Normal file
50
console-webapp/.eslintrc.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
],
|
||||
"eol-last": [
|
||||
"error",
|
||||
"always"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
0
console-webapp/.prettierignore
Normal file
0
console-webapp/.prettierignore
Normal file
1
console-webapp/.prettierrc.json
Normal file
1
console-webapp/.prettierrc.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -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,19 +94,37 @@
|
||||
"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": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false,
|
||||
"schematicCollections": [
|
||||
"@angular-eslint/schematics"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,5 +50,20 @@ task buildConsoleWebappProd(type: Exec) {
|
||||
args 'run', 'build'
|
||||
}
|
||||
|
||||
task applyFormatting(type: Exec) {
|
||||
workingDir "${consoleDir}/"
|
||||
executable 'npm'
|
||||
args 'run', 'prettify'
|
||||
}
|
||||
|
||||
task checkFormatting(type: Exec) {
|
||||
workingDir "${consoleDir}/"
|
||||
executable 'npm'
|
||||
args 'run', 'prettify:check'
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"/registrar":
|
||||
"/console-api":
|
||||
{
|
||||
"target": "http://localhost:8080/registrar",
|
||||
"secure": false
|
||||
"target": "http://localhost:8080",
|
||||
"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
|
||||
aopalliance:aopalliance:1.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:3.0.5=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.auto.service:auto-service-annotations:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=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_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.errorprone:error_prone_annotation:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.7.1=checkstyle
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:javac:9+181-r4173-1=errorproneJavac
|
||||
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: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.guava:guava-parent:32.1.1-jre=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.guava:guava:31.0.1-jre=checkstyle
|
||||
com.google.guava:guava:32.1.1-jre=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle
|
||||
com.google.inject:guice:5.1.0=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.google.protobuf:protobuf-java:3.19.6=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
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
|
||||
org.checkerframework:checker-qual:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
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.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
|
||||
info.picocli:picocli:4.6.2=checkstyle
|
||||
io.github.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
javax.inject:javax.inject:1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
net.sf.saxon:Saxon-HE:10.6=checkstyle
|
||||
org.antlr:antlr4-runtime:4.9.3=checkstyle
|
||||
org.checkerframework:checker-qual:3.12.0=checkstyle
|
||||
org.checkerframework:checker-qual:3.33.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
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:3.1.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
empty=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
|
||||
19725
console-webapp/package-lock.json
generated
19725
console-webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,43 +3,55 @@
|
||||
"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",
|
||||
"test": "ng test --browsers=ChromeHeadless --watch=false",
|
||||
"run:dev": "",
|
||||
"start:dev": "concurrently \"./../gradlew :core:runTestServer\" \"ng serve --proxy-config dev-proxy.config.json\""
|
||||
"prettify": "npx prettier --write ./src/",
|
||||
"prettify:check": "npx prettier --check ./src/",
|
||||
"start:dev": "concurrently \"./../gradlew :core:runTestServer\" \"ng serve --proxy-config dev-proxy.config.json\"",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^15.2.2",
|
||||
"@angular/cdk": "^15.2.2",
|
||||
"@angular/common": "^15.2.2",
|
||||
"@angular/compiler": "^15.2.2",
|
||||
"@angular/core": "^15.2.2",
|
||||
"@angular/forms": "^15.2.2",
|
||||
"@angular/material": "^15.2.2",
|
||||
"@angular/platform-browser": "^15.2.2",
|
||||
"@angular/platform-browser-dynamic": "^15.2.2",
|
||||
"@angular/router": "^15.2.2",
|
||||
"@angular/animations": "^17.0.7",
|
||||
"@angular/cdk": "^17.0.4",
|
||||
"@angular/common": "^17.0.7",
|
||||
"@angular/compiler": "^17.0.7",
|
||||
"@angular/core": "^17.0.7",
|
||||
"@angular/forms": "^17.0.7",
|
||||
"@angular/material": "^17.0.4",
|
||||
"@angular/platform-browser": "^17.0.7",
|
||||
"@angular/platform-browser-dynamic": "^17.0.7",
|
||||
"@angular/router": "^17.0.7",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4"
|
||||
"zone.js": "~0.14.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.2.4",
|
||||
"@angular/cli": "~15.2.4",
|
||||
"@angular/compiler-cli": "^15.2.2",
|
||||
"@angular-devkit/build-angular": "^17.0.7",
|
||||
"@angular-eslint/builder": "17.1.1",
|
||||
"@angular-eslint/eslint-plugin": "17.1.1",
|
||||
"@angular-eslint/eslint-plugin-template": "17.1.1",
|
||||
"@angular-eslint/schematics": "17.1.1",
|
||||
"@angular-eslint/template-parser": "17.1.1",
|
||||
"@angular/cli": "~17.0.7",
|
||||
"@angular/compiler-cli": "^17.0.7",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
||||
"@typescript-eslint/parser": "^5.59.2",
|
||||
"concurrently": "^7.6.0",
|
||||
"eslint": "^8.39.0",
|
||||
"jasmine-core": "~4.3.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"typescript": "~4.9.4"
|
||||
"prettier": "2.8.7",
|
||||
"typescript": "~5.2.2"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||
// 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.
|
||||
@@ -14,16 +14,72 @@
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import {TldsComponent} from './tlds/tlds.component';
|
||||
import {HomeComponent} from './home/home.component';
|
||||
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 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/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: 'home', component: HomeComponent },
|
||||
{ path: 'tlds', component: TldsComponent },
|
||||
{ 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: DomainListComponent.PATH,
|
||||
component: DomainListComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: SettingsComponent.PATH,
|
||||
component: SettingsComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'registrars',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: ContactComponent.PATH,
|
||||
component: SettingsContactComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: WhoisComponent.PATH,
|
||||
component: SettingsWhoisComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: SecurityComponent.PATH,
|
||||
component: SettingsSecurityComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: UsersComponent.PATH,
|
||||
component: SettingsUsersComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: RegistrarComponent.PATH,
|
||||
component: RegistrarComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
imports: [RouterModule.forRoot(routes, { useHash: true })],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
export class AppRoutingModule {}
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
<div class="toolbar" role="banner">
|
||||
Nomulus Console
|
||||
<div class="console-app">
|
||||
<app-header (toggleNavOpen)="sidenav.toggle()"></app-header>
|
||||
<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">
|
||||
Home page
|
||||
</a>
|
||||
<a mat-list-item [routerLink]="'/tlds'" routerLinkActive="active">
|
||||
TLDS
|
||||
</a>
|
||||
<a mat-list-item [routerLink]="'/settings'" routerLinkActive="active">
|
||||
Settings
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
</mat-sidenav>
|
||||
<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>
|
||||
|
||||
<div class="content" role="main">
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a routerLink="/home" routerLinkActive="active" ariaCurrentWhenActive="page">Home page</a></li>
|
||||
<li><a routerLink="/tlds" routerLinkActive="active" ariaCurrentWhenActive="page">TLDs</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
53
console-webapp/src/app/app.component.scss
Normal file
53
console-webapp/src/app/app.component.scss
Normal file
@@ -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.
|
||||
|
||||
:host {
|
||||
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;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.console-app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
&__container {
|
||||
flex: 1;
|
||||
margin-top: -12px;
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
&__sidebar {
|
||||
min-width: 300px;
|
||||
a::before {
|
||||
background-color: transparent;
|
||||
}
|
||||
.active {
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
}
|
||||
&__content-wrapper {
|
||||
margin: 12px 24px;
|
||||
}
|
||||
&__content {
|
||||
max-width: 1340px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&__global-spinner {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,22 @@
|
||||
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';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { BackendService } from './shared/services/backend.service';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: [BackendService],
|
||||
declarations: [AppComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
@@ -33,5 +39,4 @@ describe('AppComponent', () => {
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -12,13 +12,45 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild, effect } 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
|
||||
) {
|
||||
effect(() => {
|
||||
if (registrarService.registrarId()) {
|
||||
this.renderRouter = false;
|
||||
setTimeout(() => {
|
||||
this.renderRouter = true;
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.router.events.subscribe((event) => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
this.sidenav.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||
// 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.
|
||||
@@ -14,28 +14,92 @@
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import {MaterialModule} from './material.module';
|
||||
import { MaterialModule } from './material.module';
|
||||
|
||||
import { BackendService } from './shared/services/backend.service';
|
||||
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { TldsComponent } from './tlds/tlds.component';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { SettingsComponent } from './settings/settings.component';
|
||||
import SettingsContactComponent, {
|
||||
ContactDetailsDialogComponent,
|
||||
} from './settings/contact/contact.component';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
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,
|
||||
DialogBottomSheetWrapper,
|
||||
BillingWidgetComponent,
|
||||
ContactDetailsDialogComponent,
|
||||
ContactWidgetComponent,
|
||||
DomainListComponent,
|
||||
DomainsWidgetComponent,
|
||||
EmptyRegistrar,
|
||||
EppWidgetComponent,
|
||||
HeaderComponent,
|
||||
HomeComponent,
|
||||
PromotionsWidgetComponent,
|
||||
RegistrarComponent,
|
||||
RegistrarDetailsComponent,
|
||||
RegistrarSelectorComponent,
|
||||
ResourcesWidgetComponent,
|
||||
SecurityComponent,
|
||||
SettingsComponent,
|
||||
SettingsContactComponent,
|
||||
SettingsWidgetComponent,
|
||||
TldsComponent,
|
||||
TldsWidgetComponent,
|
||||
WhoisComponent,
|
||||
],
|
||||
imports: [
|
||||
MaterialModule,
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
MaterialModule,
|
||||
SnackBarModule,
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
providers: [
|
||||
BackendService,
|
||||
GlobalLoaderService,
|
||||
RegistrarGuard,
|
||||
UserDataService,
|
||||
{
|
||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
useValue: {
|
||||
subscriptSizing: 'dynamic',
|
||||
},
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule { }
|
||||
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>
|
||||
46
console-webapp/src/app/domains/domainList.component.spec.ts
Normal file
46
console-webapp/src/app/domains/domainList.component.spec.ts
Normal file
@@ -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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DomainListComponent } from './domainList.component';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('DomainListComponent', () => {
|
||||
let component: DomainListComponent;
|
||||
let fixture: ComponentFixture<DomainListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [DomainListComponent],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: [BackendService],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DomainListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
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.registrarId(),
|
||||
this.checkpointTime,
|
||||
pageNumber,
|
||||
resultsPerPage,
|
||||
totalResults,
|
||||
searchTerm
|
||||
)
|
||||
.pipe(
|
||||
tap((domainListResult: DomainListResult) => {
|
||||
this.checkpointTime = domainListResult.checkpointTime;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
30
console-webapp/src/app/header/header.component.html
Normal file
30
console-webapp/src/app/header/header.component.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<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>
|
||||
<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
|
||||
[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>
|
||||
40
console-webapp/src/app/header/header.component.scss
Normal file
40
console-webapp/src/app/header/header.component.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
@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;
|
||||
}
|
||||
39
console-webapp/src/app/header/header.component.spec.ts
Normal file
39
console-webapp/src/app/header/header.component.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 { HeaderComponent } from './header.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from '../material.module';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
let fixture: ComponentFixture<HeaderComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
declarations: [HeaderComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
35
console-webapp/src/app/header/header.component.ts
Normal file
35
console-webapp/src/app/header/header.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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, EventEmitter, Output } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss'],
|
||||
})
|
||||
export class HeaderComponent {
|
||||
private isNavOpen = false;
|
||||
|
||||
@Output() toggleNavOpen = new EventEmitter<boolean>();
|
||||
|
||||
toggleNavPane() {
|
||||
this.isNavOpen = !this.isNavOpen;
|
||||
this.toggleNavOpen.emit(this.isNavOpen);
|
||||
}
|
||||
|
||||
logOut() {
|
||||
window.open('/console?gcp-iap-mode=CLEAR_LOGIN_COOKIE', '_self');
|
||||
}
|
||||
}
|
||||
@@ -1,14 +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>
|
||||
|
||||
@@ -12,24 +12,26 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// 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-size: 14px;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.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;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
mat-card {
|
||||
height: 100%;
|
||||
h1 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 510px) {
|
||||
.console-app__widget-wrapper__wide {
|
||||
grid-column: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
import {MaterialModule} from '../material.module';
|
||||
import { MaterialModule } from '../material.module';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
@@ -24,9 +24,8 @@ describe('HomeComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule],
|
||||
declarations: [ HomeComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
declarations: [HomeComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
@@ -12,83 +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);
|
||||
|
||||
constructor() {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
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,39 @@
|
||||
// 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>
|
||||
23
console-webapp/src/app/home/widgets/eppWidget.component.ts
Normal file
23
console-webapp/src/app/home/widgets/eppWidget.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-epp-widget]',
|
||||
templateUrl: './eppWidget.component.html',
|
||||
})
|
||||
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() {}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||
// 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.
|
||||
@@ -12,15 +12,77 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import {MatTableModule} from '@angular/material/table';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { A11yModule } from '@angular/cdk/a11y';
|
||||
import { CdkTableModule } from '@angular/cdk/table';
|
||||
import { CdkTreeModule } from '@angular/cdk/tree';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatNativeDateModule, MatRippleModule } from '@angular/material/core';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatTreeModule } from '@angular/material/tree';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
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';
|
||||
|
||||
const MATERIAL_MODULES = [
|
||||
MatCardModule,
|
||||
MatTableModule,
|
||||
];
|
||||
|
||||
@NgModule({imports: MATERIAL_MODULES, exports: MATERIAL_MODULES})
|
||||
export class MaterialModule {
|
||||
}
|
||||
@NgModule({
|
||||
exports: [
|
||||
A11yModule,
|
||||
CdkMenuModule,
|
||||
CdkTableModule,
|
||||
CdkTreeModule,
|
||||
MatBadgeModule,
|
||||
MatButtonModule,
|
||||
MatButtonToggleModule,
|
||||
MatBottomSheetModule,
|
||||
MatCardModule,
|
||||
MatCheckboxModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
MatGridListModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatListModule,
|
||||
MatMenuModule,
|
||||
MatNativeDateModule,
|
||||
MatProgressBarModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatRadioModule,
|
||||
MatRippleModule,
|
||||
MatSelectModule,
|
||||
MatSidenavModule,
|
||||
MatTableModule,
|
||||
MatTabsModule,
|
||||
MatToolbarModule,
|
||||
MatTooltipModule,
|
||||
MatTreeModule,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
console-webapp/src/app/registrar/emptyRegistrar.component.ts
Normal file
37
console-webapp/src/app/registrar/emptyRegistrar.component.ts
Normal file
@@ -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, effect } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-empty-registrar',
|
||||
templateUrl: './emptyRegistrar.component.html',
|
||||
styleUrls: ['./emptyRegistrar.component.scss'],
|
||||
})
|
||||
export class EmptyRegistrar {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
protected registrarService: RegistrarService,
|
||||
private router: Router
|
||||
) {
|
||||
effect(() => {
|
||||
if (registrarService.registrarId()) {
|
||||
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
68
console-webapp/src/app/registrar/registrar.guard.spec.ts
Normal file
68
console-webapp/src/app/registrar/registrar.guard.spec.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 { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegistrarGuard } from './registrar.guard';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from '@angular/router';
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
describe('RegistrarGuard', () => {
|
||||
let guard: RegistrarGuard;
|
||||
let dummyRegistrarService: RegistrarService;
|
||||
let routeSpy: Router;
|
||||
let dummyRoute: RouterStateSnapshot;
|
||||
|
||||
beforeEach(() => {
|
||||
routeSpy = jasmine.createSpyObj<Router>('Router', ['navigate']);
|
||||
dummyRegistrarService = { activeRegistrarId: '' } as RegistrarService;
|
||||
dummyRoute = { url: '/value' } as RouterStateSnapshot;
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
RegistrarGuard,
|
||||
{ provide: Router, useValue: routeSpy },
|
||||
{ provide: RegistrarService, useValue: dummyRegistrarService },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should not be able to activate when activeRegistrarId is empty', () => {
|
||||
guard = TestBed.inject(RegistrarGuard);
|
||||
const res = guard.canActivate(new ActivatedRouteSnapshot(), dummyRoute);
|
||||
expect(res).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should be able to activate when activeRegistrarId is not empty', () => {
|
||||
TestBed.overrideProvider(RegistrarService, {
|
||||
useValue: { activeRegistrarId: 'value' },
|
||||
});
|
||||
guard = TestBed.inject(RegistrarGuard);
|
||||
const res = guard.canActivate(new ActivatedRouteSnapshot(), dummyRoute);
|
||||
expect(res).toBeTrue();
|
||||
});
|
||||
|
||||
it('should navigate to empty-registrar screen when activeRegistrarId is empty', () => {
|
||||
guard = TestBed.inject(RegistrarGuard);
|
||||
guard.canActivate(new ActivatedRouteSnapshot(), dummyRoute);
|
||||
expect(routeSpy.navigate).toHaveBeenCalledOnceWith([
|
||||
'/empty-registrar',
|
||||
{ nextUrl: dummyRoute.url },
|
||||
]);
|
||||
});
|
||||
});
|
||||
45
console-webapp/src/app/registrar/registrar.guard.ts
Normal file
45
console-webapp/src/app/registrar/registrar.guard.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 {
|
||||
ActivatedRouteSnapshot,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from '@angular/router';
|
||||
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RegistrarGuard {
|
||||
constructor(
|
||||
private router: Router,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
canActivate(
|
||||
_: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
): Promise<boolean> | boolean {
|
||||
if (this.registrarService.registrarId()) {
|
||||
return true;
|
||||
}
|
||||
return this.router.navigate([
|
||||
`/empty-registrar`,
|
||||
{ nextUrl: state.url || '' },
|
||||
]);
|
||||
}
|
||||
}
|
||||
36
console-webapp/src/app/registrar/registrar.service.spec.ts
Normal file
36
console-webapp/src/app/registrar/registrar.service.spec.ts
Normal file
@@ -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 { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegistrarService } from './registrar.service';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
describe('RegistrarService', () => {
|
||||
let service: RegistrarService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
providers: [BackendService, MatSnackBar],
|
||||
});
|
||||
service = TestBed.inject(RegistrarService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
89
console-webapp/src/app/registrar/registrar.service.ts
Normal file
89
console-webapp/src/app/registrar/registrar.service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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, computed, signal } from '@angular/core';
|
||||
import { Observable, 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 implements GlobalLoader {
|
||||
registrarId = signal<string>('');
|
||||
registrars = signal<Registrar[]>([]);
|
||||
registrar = computed<Registrar | undefined>(() =>
|
||||
this.registrars().find((r) => r.registrarId === this.registrarId())
|
||||
);
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private globalLoader: GlobalLoaderService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
this.loadRegistrars().subscribe((r) => {
|
||||
this.globalLoader.stopGlobalLoader(this);
|
||||
});
|
||||
this.globalLoader.startGlobalLoader(this);
|
||||
}
|
||||
|
||||
public updateSelectedRegistrar(registrarId: string) {
|
||||
this.registrarId.set(registrarId);
|
||||
}
|
||||
|
||||
public loadRegistrars(): Observable<Registrar[]> {
|
||||
return this.backend.getRegistrars().pipe(
|
||||
tap((registrars) => {
|
||||
if (registrars) {
|
||||
this.registrars.set(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.registrarId() || "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.registrarId()"
|
||||
(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,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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegistrarSelectorComponent } from './registrarSelector.component';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('RegistrarSelectorComponent', () => {
|
||||
let component: RegistrarSelectorComponent;
|
||||
let fixture: ComponentFixture<RegistrarSelectorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: [BackendService],
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 { 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;
|
||||
let fixture: ComponentFixture<RegistrarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RegistrarComponent],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: ActivatedRoute, useValue: {} as ActivatedRoute },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RegistrarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
@if (loading) {
|
||||
<div class="contact__loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
} @else {
|
||||
<div>
|
||||
@if (contactService.contacts().length === 0) {
|
||||
<div class="contact__empty-contacts">
|
||||
<mat-icon class="contact__empty-contacts-icon secondary-text"
|
||||
>apps_outage</mat-icon
|
||||
>
|
||||
<h1>No contacts found</h1>
|
||||
</div>
|
||||
} @else { @for (group of groupedContacts(); track group.emailAddress) {
|
||||
<div class="contact__cards-wrapper">
|
||||
<h3>{{ group.label }}s</h3>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="contact__cards">
|
||||
<mat-card class="contact__card" *ngFor="let contact of group.contacts">
|
||||
<mat-card-title>{{ contact.name }}</mat-card-title>
|
||||
<p *ngIf="contact.phoneNumber">{{ contact.phoneNumber }}</p>
|
||||
<p *ngIf="contact.emailAddress">{{ contact.emailAddress }}</p>
|
||||
<mat-card-actions class="contact__card-actions">
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
(click)="openDetails($event, contact)"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>Edit
|
||||
</button>
|
||||
<button mat-button color="accent" (click)="deleteContact(contact)">
|
||||
<mat-icon>delete</mat-icon>Delete
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
} }
|
||||
<div class="contact__actions">
|
||||
<button mat-raised-button color="primary" (click)="openCreateNew($event)">
|
||||
<mat-icon>add</mat-icon>Create a Contact
|
||||
</button>
|
||||
</div>
|
||||
<app-dialog-bottom-sheet-wrapper
|
||||
#contactDetailsWrapper
|
||||
></app-dialog-bottom-sheet-wrapper>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// 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.
|
||||
|
||||
.contact {
|
||||
&__cards-wrapper {
|
||||
margin-top: 22px;
|
||||
}
|
||||
&__card {
|
||||
width: 400px;
|
||||
padding: 15px;
|
||||
}
|
||||
&__card-actions {
|
||||
padding: 0;
|
||||
}
|
||||
&__loading {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
&__cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
&__actions {
|
||||
display: flex;
|
||||
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 {
|
||||
width: 100%;
|
||||
}
|
||||
&__group {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
&__group-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
max-width: 450px;
|
||||
* {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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 ContactComponent from './contact.component';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
|
||||
describe('ContactComponent', () => {
|
||||
let component: ContactComponent;
|
||||
let fixture: ComponentFixture<ContactComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ContactComponent],
|
||||
imports: [HttpClientTestingModule, MaterialModule],
|
||||
providers: [BackendService],
|
||||
}).compileComponents();
|
||||
fixture = TestBed.createComponent(ContactComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
175
console-webapp/src/app/settings/contact/contact.component.ts
Normal file
175
console-webapp/src/app/settings/contact/contact.component.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
// 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, computed } from '@angular/core';
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
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,
|
||||
ADD,
|
||||
UPDATE,
|
||||
}
|
||||
|
||||
interface GroupedContacts {
|
||||
value: string;
|
||||
label: string;
|
||||
contacts: Array<Contact>;
|
||||
}
|
||||
|
||||
type ContactDetailsParams = {
|
||||
close: Function;
|
||||
data: {
|
||||
contact: Contact;
|
||||
operation: Operations;
|
||||
};
|
||||
};
|
||||
|
||||
const contactTypes: Array<GroupedContacts> = [
|
||||
{ value: 'ADMIN', label: 'Primary contact', contacts: [] },
|
||||
{ value: 'ABUSE', label: 'Abuse contact', contacts: [] },
|
||||
{ value: 'BILLING', label: 'Billing contact', contacts: [] },
|
||||
{ value: 'LEGAL', label: 'Legal contact', contacts: [] },
|
||||
{ value: 'MARKETING', label: 'Marketing contact', contacts: [] },
|
||||
{ value: 'TECH', label: 'Technical contact', contacts: [] },
|
||||
{ value: 'WHOIS', label: 'WHOIS-Inquiry contact', contacts: [] },
|
||||
];
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact-details-dialog',
|
||||
templateUrl: 'contactDetails.component.html',
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export class ContactDetailsDialogComponent implements DialogBottomSheetContent {
|
||||
contact?: Contact;
|
||||
contactTypes = contactTypes;
|
||||
contactIndex?: number;
|
||||
|
||||
params?: ContactDetailsParams;
|
||||
|
||||
constructor(
|
||||
public contactService: ContactService,
|
||||
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(params.data.contact));
|
||||
}
|
||||
|
||||
close() {
|
||||
this.params?.close();
|
||||
}
|
||||
|
||||
saveAndClose(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
if (!this.contact || this.contactIndex === undefined) return;
|
||||
if (!(e.target as HTMLFormElement).checkValidity()) {
|
||||
return;
|
||||
}
|
||||
const operation = this.params?.data.operation;
|
||||
let operationObservable;
|
||||
if (operation === Operations.ADD) {
|
||||
operationObservable = this.contactService.addContact(this.contact);
|
||||
} else if (operation === Operations.UPDATE) {
|
||||
operationObservable = this.contactService.updateContact(
|
||||
this.contactIndex,
|
||||
this.contact
|
||||
);
|
||||
} else {
|
||||
throw 'Unknown operation type';
|
||||
}
|
||||
|
||||
operationObservable.subscribe({
|
||||
complete: () => this.close(),
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export default class ContactComponent {
|
||||
public static PATH = 'contact';
|
||||
public groupedContacts = computed(() => {
|
||||
return this.contactService.contacts().reduce((acc, contact) => {
|
||||
contact.types.forEach((contactType) => {
|
||||
acc
|
||||
.find((group: GroupedContacts) => group.value === contactType)
|
||||
?.contacts.push(contact);
|
||||
});
|
||||
return acc;
|
||||
}, JSON.parse(JSON.stringify(contactTypes)));
|
||||
});
|
||||
|
||||
@ViewChild('contactDetailsWrapper')
|
||||
detailsComponentWrapper!: DialogBottomSheetWrapper;
|
||||
|
||||
loading: boolean = false;
|
||||
constructor(
|
||||
public contactService: ContactService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
// TODO: Refactor to registrarId service
|
||||
this.loading = true;
|
||||
this.contactService.fetchContacts().subscribe(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
deleteContact(contact: Contact) {
|
||||
if (confirm(`Please confirm contact ${contact.name} delete`)) {
|
||||
this.contactService.deleteContact(contact).subscribe({
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
openCreateNew(e: MouseEvent) {
|
||||
const newContact: Contact = {
|
||||
name: '',
|
||||
phoneNumber: '',
|
||||
emailAddress: '',
|
||||
types: [contactTypes[0].value],
|
||||
};
|
||||
this.openDetails(e, newContact, Operations.ADD);
|
||||
}
|
||||
|
||||
openDetails(
|
||||
e: MouseEvent,
|
||||
contact: Contact,
|
||||
operation: Operations = Operations.UPDATE
|
||||
) {
|
||||
e.preventDefault();
|
||||
this.detailsComponentWrapper.open<ContactDetailsDialogComponent>(
|
||||
ContactDetailsDialogComponent,
|
||||
{ contact, operation }
|
||||
);
|
||||
}
|
||||
}
|
||||
78
console-webapp/src/app/settings/contact/contact.service.ts
Normal file
78
console-webapp/src/app/settings/contact/contact.service.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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, signal } from '@angular/core';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
|
||||
export interface Contact {
|
||||
name: string;
|
||||
phoneNumber: string;
|
||||
emailAddress: string;
|
||||
registrarId?: string;
|
||||
faxNumber?: string;
|
||||
types: Array<string>;
|
||||
visibleInWhoisAsAdmin?: boolean;
|
||||
visibleInWhoisAsTech?: boolean;
|
||||
visibleInDomainWhoisAsAbuse?: boolean;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ContactService {
|
||||
contacts = signal<Contact[]>([]);
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
// TODO: Come up with a better handling for registrarId
|
||||
fetchContacts(): Observable<Contact[]> {
|
||||
return this.backend.getContacts(this.registrarService.registrarId()).pipe(
|
||||
tap((contacts = []) => {
|
||||
this.contacts.set(contacts);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
saveContacts(contacts: Contact[]): Observable<Contact[]> {
|
||||
return this.backend
|
||||
.postContacts(this.registrarService.registrarId(), contacts)
|
||||
.pipe(
|
||||
tap((_) => {
|
||||
this.contacts.set(contacts);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
updateContact(index: number, contact: Contact) {
|
||||
const newContacts = this.contacts().map((c, i) =>
|
||||
i === index ? contact : c
|
||||
);
|
||||
return this.saveContacts(newContacts);
|
||||
}
|
||||
|
||||
addContact(contact: Contact) {
|
||||
const newContacts = this.contacts().concat([contact]);
|
||||
return this.saveContacts(newContacts);
|
||||
}
|
||||
|
||||
deleteContact(contact: Contact) {
|
||||
const newContacts = this.contacts().filter((c) => c !== contact);
|
||||
return this.saveContacts(newContacts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<h3 mat-dialog-title>Contact details</h3>
|
||||
<div mat-dialog-content *ngIf="contact">
|
||||
<form (ngSubmit)="saveAndClose($event)">
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Name: </mat-label>
|
||||
<input
|
||||
matInput
|
||||
[required]="true"
|
||||
[(ngModel)]="contact.name"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Primary account email: </mat-label>
|
||||
<input
|
||||
type="email"
|
||||
matInput
|
||||
[email]="true"
|
||||
[required]="true"
|
||||
[(ngModel)]="contact.emailAddress"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Phone: </mat-label>
|
||||
<input
|
||||
matInput
|
||||
[(ngModel)]="contact.phoneNumber"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<mat-form-field class="contact-details__input">
|
||||
<mat-label>Fax: </mat-label>
|
||||
<input
|
||||
matInput
|
||||
[(ngModel)]="contact.faxNumber"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
|
||||
<div class="contact-details__group">
|
||||
<label>Contact type:</label>
|
||||
<div class="contact-details__group-content">
|
||||
<mat-checkbox
|
||||
*ngFor="let contactType of contactTypes"
|
||||
[checked]="contact.types.includes(contactType.value)"
|
||||
(change)="
|
||||
$event.checked
|
||||
? contact.types.push(contactType.value)
|
||||
: contact.types.splice(
|
||||
contact.types.indexOf(contactType.value),
|
||||
1
|
||||
)
|
||||
"
|
||||
[disabled]="
|
||||
contact.types.length === 1 && contact.types[0] === contactType.value
|
||||
"
|
||||
>
|
||||
{{ contactType.label }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<mat-checkbox
|
||||
[(ngModel)]="contact.visibleInWhoisAsAdmin"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>Show in Registrar WHOIS record as admin contact</mat-checkbox
|
||||
>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<mat-checkbox
|
||||
[(ngModel)]="contact.visibleInWhoisAsTech"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>Show in Registrar WHOIS record as technical contact</mat-checkbox
|
||||
>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<mat-checkbox
|
||||
[(ngModel)]="contact.visibleInDomainWhoisAsAbuse"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>Show Phone and Email in Domain WHOIS Record as registrar abuse contact
|
||||
(per CL&D requirements)</mat-checkbox
|
||||
>
|
||||
</section>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="close()">Cancel</button>
|
||||
<button type="submit" mat-button>Save</button>
|
||||
</mat-dialog-actions>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,98 @@
|
||||
<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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
// 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, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import SecurityComponent from './security.component';
|
||||
import { SecurityService, apiToUiConverter } 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';
|
||||
import {
|
||||
Registrar,
|
||||
RegistrarService,
|
||||
} from 'src/app/registrar/registrar.service';
|
||||
|
||||
describe('SecurityComponent', () => {
|
||||
let component: SecurityComponent;
|
||||
let fixture: ComponentFixture<SecurityComponent>;
|
||||
let fetchSecurityDetailsSpy: Function;
|
||||
let saveSpy: Function;
|
||||
let dummyRegistrarService: RegistrarService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const securityServiceSpy = jasmine.createSpyObj(SecurityService, [
|
||||
'fetchSecurityDetails',
|
||||
'saveChanges',
|
||||
]);
|
||||
|
||||
fetchSecurityDetailsSpy =
|
||||
securityServiceSpy.fetchSecurityDetails.and.returnValue(of());
|
||||
|
||||
saveSpy = securityServiceSpy.saveChanges;
|
||||
|
||||
dummyRegistrarService = {
|
||||
registrar: { ipAddressAllowList: ['123.123.123.123'] },
|
||||
} as RegistrarService;
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
],
|
||||
declarations: [SecurityComponent],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: RegistrarService, useValue: dummyRegistrarService },
|
||||
],
|
||||
})
|
||||
.overrideComponent(SecurityComponent, {
|
||||
set: {
|
||||
providers: [
|
||||
{ provide: SecurityService, useValue: securityServiceSpy },
|
||||
],
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SecurityComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
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).toEqual(
|
||||
apiToUiConverter(dummyRegistrarService.registrar)
|
||||
);
|
||||
component.removeIpEntry(0);
|
||||
expect(component.dataSource).toEqual({ ipAddressAllowList: [] });
|
||||
expect(dummyRegistrarService.registrar).toEqual({
|
||||
ipAddressAllowList: ['123.123.123.123'],
|
||||
} as Registrar);
|
||||
component.cancel();
|
||||
expect(component.dataSource).toEqual(
|
||||
apiToUiConverter(dummyRegistrarService.registrar)
|
||||
);
|
||||
});
|
||||
|
||||
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',
|
||||
});
|
||||
}));
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
// 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 {
|
||||
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.scss'],
|
||||
providers: [SecurityService],
|
||||
})
|
||||
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,63 @@
|
||||
// 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';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
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: [MatSnackBar, 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.registrarId(),
|
||||
uiToApiConverter(newSecuritySettings)
|
||||
)
|
||||
.pipe(
|
||||
switchMap(() => {
|
||||
return this.registrarService.loadRegistrars();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
24
console-webapp/src/app/settings/settings.component.html
Normal file
24
console-webapp/src/app/settings/settings.component.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="console-settings">
|
||||
<h1>Settings</h1>
|
||||
<nav mat-tab-nav-bar [tabPanel]="tabPanel">
|
||||
<a mat-tab-link routerLink="contact" routerLinkActive="active-link"
|
||||
>Contact Info</a
|
||||
>
|
||||
<a mat-tab-link routerLink="whois" routerLinkActive="active-link"
|
||||
>WHOIS Info</a
|
||||
>
|
||||
<a mat-tab-link routerLink="security" routerLinkActive="active-link"
|
||||
>Security</a
|
||||
>
|
||||
<a mat-tab-link routerLink="epp-password" routerLinkActive="active-link"
|
||||
>EPP Password</a
|
||||
>
|
||||
<a mat-tab-link routerLink="users" routerLinkActive="active-link">Users</a>
|
||||
<a mat-tab-link routerLink="registrars" routerLinkActive="active-link"
|
||||
>Registrars</a
|
||||
>
|
||||
</nav>
|
||||
<mat-tab-nav-panel #tabPanel>
|
||||
<router-outlet></router-outlet>
|
||||
</mat-tab-nav-panel>
|
||||
</div>
|
||||
24
console-webapp/src/app/settings/settings.component.scss
Normal file
24
console-webapp/src/app/settings/settings.component.scss
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.
|
||||
|
||||
.console-settings {
|
||||
.mdc-tab {
|
||||
&.active-link {
|
||||
border-bottom: 2px solid var(--primary);
|
||||
.mdc-tab__text-label {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
console-webapp/src/app/settings/settings.component.spec.ts
Normal file
39
console-webapp/src/app/settings/settings.component.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 { SettingsComponent } from './settings.component';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('SettingsComponent', () => {
|
||||
let component: SettingsComponent;
|
||||
let fixture: ComponentFixture<SettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
declarations: [SettingsComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
25
console-webapp/src/app/settings/settings.component.ts
Normal file
25
console-webapp/src/app/settings/settings.component.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class SettingsComponent {
|
||||
public static PATH = 'settings';
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<p>users works!</p>
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||
// 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.
|
||||
@@ -11,4 +11,3 @@
|
||||
// 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.
|
||||
|
||||
@@ -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 UsersComponent from './users.component';
|
||||
|
||||
describe('UsersComponent', () => {
|
||||
let component: UsersComponent;
|
||||
let fixture: ComponentFixture<UsersComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [UsersComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(UsersComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
24
console-webapp/src/app/settings/users/users.component.ts
Normal file
24
console-webapp/src/app/settings/users/users.component.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 { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-users',
|
||||
templateUrl: './users.component.html',
|
||||
styleUrls: ['./users.component.scss'],
|
||||
})
|
||||
export default class UsersComponent {
|
||||
public static PATH = 'users';
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user