20221221 sync deploy (#1285)

This commit is contained in:
Firstyear 2022-12-22 18:03:29 +10:00 committed by GitHub
parent c5bcc7aaf3
commit def8f3f1bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 126 additions and 77 deletions

View file

@ -23,7 +23,7 @@ ipa_ca = "/path/to/kanidm-ipa-ca.pem"
# The DN of an account with content sync rights. By default cn=Directory Manager has # The DN of an account with content sync rights. By default cn=Directory Manager has
# this access. # this access.
ipa_sync_dn = "cn=Directory Manager" ipa_sync_dn = "cn=Directory Manager"
ipa_sync_pw = "pi9aix6balaqu8Maerah" ipa_sync_pw = "directory manager password"
# The basedn to examine. # The basedn to examine.
ipa_sync_base_dn = "dc=ipa,dc=dev,dc=kanidm,dc=com" ipa_sync_base_dn = "dc=ipa,dc=dev,dc=kanidm,dc=com"

View file

@ -1,4 +1,4 @@
dn: cn=Retro Changelog Plugin,cn=plugins,cn=config dn: cn=Retro Changelog Plugin,cn=plugins,cn=config
changetype: modify changetype: modify
add: nsslapd-include-suffix replace: nsslapd-include-suffix
nsslapd-include-suffix: dc=ipa,dc=dev,dc=kanidm,dc=com nsslapd-include-suffix: dc=ipa,dc=dev,dc=kanidm,dc=com

View file

@ -27,18 +27,44 @@ This example is located in [examples/kanidm-ipa-sync](https://github.com/kanidm/
In addition to this, you must make some configuration changes to FreeIPA to enable synchronisation. In addition to this, you must make some configuration changes to FreeIPA to enable synchronisation.
You must modify the retro changelog plugin to include the full scope of the database suffix. You can find the name of your 389 Directory Server instance with:
dsconf --list
Using this you can show the current status of the retro changelog plugin to see if you need
to change it's configuration.
dsconf <instance name> plugin retro-changelog show
dsconf slapd-DEV-KANIDM-COM plugin retro-changelog show
You must modify the retro changelog plugin to include the full scope of the database suffix so that
the sync tool can view the changes to the database. Currently dsconf can not modify the include-suffix
so you must do this manually.
You need to change the `nsslapd-include-suffix` to match your FreeIPA baseDN here. You can
access the basedn with:
ldapsearch -H ldaps://<IPA SERVER HOSTNAME/IP> -x -b '' -s base namingContexts
# namingContexts: dc=ipa,dc=dev,dc=kanidm,dc=com
You should ignore `cn=changelog` and `o=ipaca` as these are system internal namingContexts. You
can then create an ldapmodify like the following.
``` ```
{{#rustdoc_include ../../../iam_migrations/freeipa/00config-mod.ldif}} {{#rustdoc_include ../../../iam_migrations/freeipa/00config-mod.ldif}}
``` ```
You must then restart your FreeIPA server. And apply it with:
ldapmodify -f change.ldif -H ldaps://<IPA SERVER HOSTNAME/IP> -x -D 'cn=Directory Manager' -W
# Enter LDAP Password:
You must then reboot your FreeIPA server.
## Running the Sync Tool Manually ## Running the Sync Tool Manually
You can perform a dry run with the sync tool manually to check your configurations are You can perform a dry run with the sync tool manually to check your configurations are
correct. correct and that the tool can synchronise from FreeIPA.
kanidm-ipa-sync [-c /path/to/kanidm/config] -i /path/to/kanidm-ipa-sync -n kanidm-ipa-sync [-c /path/to/kanidm/config] -i /path/to/kanidm-ipa-sync -n
kanidm-ipa-sync -i /etc/kanidm/ipa-sync -n kanidm-ipa-sync -i /etc/kanidm/ipa-sync -n

View file

@ -327,12 +327,14 @@ impl fmt::Display for AuthType {
pub enum UiHint { pub enum UiHint {
ExperimentalFeatures = 0, ExperimentalFeatures = 0,
PosixAccount = 1, PosixAccount = 1,
CredentialUpdate = 2,
} }
impl fmt::Display for UiHint { impl fmt::Display for UiHint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
UiHint::PosixAccount => write!(f, "PosixAccount"), UiHint::PosixAccount => write!(f, "PosixAccount"),
UiHint::CredentialUpdate => write!(f, "CredentialUpdate"),
UiHint::ExperimentalFeatures => write!(f, "ExperimentalFeatures"), UiHint::ExperimentalFeatures => write!(f, "ExperimentalFeatures"),
} }
} }
@ -343,6 +345,7 @@ impl FromStr for UiHint {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { match s {
"CredentialUpdate" => Ok(UiHint::CredentialUpdate),
"PosixAccount" => Ok(UiHint::PosixAccount), "PosixAccount" => Ok(UiHint::PosixAccount),
"ExperimentalFeatures" => Ok(UiHint::ExperimentalFeatures), "ExperimentalFeatures" => Ok(UiHint::ExperimentalFeatures),
_ => Err(()), _ => Err(()),

View file

@ -99,6 +99,10 @@ macro_rules! try_from_entry {
.copied() .copied()
.collect(); .collect();
if !$value.attribute_equality("class", &PVCLASS_SYNC_OBJECT) {
ui_hints.insert(UiHint::CredentialUpdate);
}
if $value.attribute_equality("class", &PVCLASS_POSIXACCOUNT) { if $value.attribute_equality("class", &PVCLASS_POSIXACCOUNT) {
ui_hints.insert(UiHint::PosixAccount); ui_hints.insert(UiHint::PosixAccount);
} }
@ -722,7 +726,8 @@ mod tests {
.expect("Unable to create uat"); .expect("Unable to create uat");
// Check the ui hints are as expected. // Check the ui hints are as expected.
assert!(uat.ui_hints.is_empty()); assert!(uat.ui_hints.len() == 1);
assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate));
// Modify the user to be a posix account, ensure they get the hint. // Modify the user to be a posix account, ensure they get the hint.
let me_posix = unsafe { let me_posix = unsafe {
@ -748,8 +753,9 @@ mod tests {
.to_userauthtoken(session_id, ct, AuthType::Passkey, None) .to_userauthtoken(session_id, ct, AuthType::Passkey, None)
.expect("Unable to create uat"); .expect("Unable to create uat");
assert!(uat.ui_hints.len() == 1); assert!(uat.ui_hints.len() == 2);
assert!(uat.ui_hints.contains(&UiHint::PosixAccount)); assert!(uat.ui_hints.contains(&UiHint::PosixAccount));
assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate));
// Add a group with a ui hint, and then check they get the hint. // Add a group with a ui hint, and then check they get the hint.
let e = entry_init!( let e = entry_init!(
@ -772,9 +778,10 @@ mod tests {
.to_userauthtoken(session_id, ct, AuthType::Passkey, None) .to_userauthtoken(session_id, ct, AuthType::Passkey, None)
.expect("Unable to create uat"); .expect("Unable to create uat");
assert!(uat.ui_hints.len() == 2); assert!(uat.ui_hints.len() == 3);
assert!(uat.ui_hints.contains(&UiHint::PosixAccount)); assert!(uat.ui_hints.contains(&UiHint::PosixAccount));
assert!(uat.ui_hints.contains(&UiHint::ExperimentalFeatures)); assert!(uat.ui_hints.contains(&UiHint::ExperimentalFeatures));
assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate));
assert!(idms_prox_write.commit().is_ok()); assert!(idms_prox_write.commit().is_ok());
}) })

View file

@ -233,7 +233,7 @@ function addBorrowedObject(obj) {
} }
function __wbg_adapter_48(arg0, arg1, arg2) { function __wbg_adapter_48(arg0, arg1, arg2) {
try { try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h871c42aaca1d3703(arg0, arg1, addBorrowedObject(arg2)); wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hdb7f5bd2101eb559(arg0, arg1, addBorrowedObject(arg2));
} finally { } finally {
heap[stack_pointer++] = undefined; heap[stack_pointer++] = undefined;
} }
@ -261,11 +261,11 @@ function makeClosure(arg0, arg1, dtor, f) {
return real; return real;
} }
function __wbg_adapter_51(arg0, arg1, arg2) { function __wbg_adapter_51(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h6073fca8e152ad8e(arg0, arg1, addHeapObject(arg2)); wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd6c53cf713a6c0ff(arg0, arg1, addHeapObject(arg2));
} }
function __wbg_adapter_54(arg0, arg1, arg2) { function __wbg_adapter_54(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h501c623b6f23b8ff(arg0, arg1, addHeapObject(arg2)); wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3b581d83a45c2264(arg0, arg1, addHeapObject(arg2));
} }
/** /**
@ -345,6 +345,10 @@ async function load(module, imports) {
function getImports() { function getImports() {
const imports = {}; const imports = {};
imports.wbg = {}; imports.wbg = {};
imports.wbg.__wbindgen_is_undefined = function(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
};
imports.wbg.__wbindgen_number_get = function(arg0, arg1) { imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
const obj = getObject(arg1); const obj = getObject(arg1);
const ret = typeof(obj) === 'number' ? obj : undefined; const ret = typeof(obj) === 'number' ? obj : undefined;
@ -386,10 +390,6 @@ function getImports() {
imports.wbg.__wbindgen_object_drop_ref = function(arg0) { imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0); takeObject(arg0);
}; };
imports.wbg.__wbindgen_is_undefined = function(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
};
imports.wbg.__wbindgen_in = function(arg0, arg1) { imports.wbg.__wbindgen_in = function(arg0, arg1) {
const ret = getObject(arg0) in getObject(arg1); const ret = getObject(arg0) in getObject(arg1);
return ret; return ret;
@ -542,6 +542,29 @@ function getImports() {
imports.wbg.__wbg_log_4b5638ad60bdc54a = function(arg0) { imports.wbg.__wbg_log_4b5638ad60bdc54a = function(arg0) {
console.log(getObject(arg0)); console.log(getObject(arg0));
}; };
imports.wbg.__wbg_getItem_845e475f85f593e4 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
}, arguments) };
imports.wbg.__wbg_removeItem_9da69ede4eea3326 = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_setItem_9c469d634d0c321c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
}, arguments) };
imports.wbg.__wbg_instanceof_HtmlFormElement_1c489ff7e99e43d3 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof HTMLFormElement;
} catch {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_value_ccb32485ee1b3928 = function(arg0, arg1) { imports.wbg.__wbg_value_ccb32485ee1b3928 = function(arg0, arg1) {
const ret = getObject(arg1).value; const ret = getObject(arg1).value;
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -566,39 +589,6 @@ function getImports() {
imports.wbg.__wbg_set_992c1d31586b2957 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { imports.wbg.__wbg_set_992c1d31586b2957 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
}, arguments) }; }, arguments) };
imports.wbg.__wbg_instanceof_HtmlFormElement_1c489ff7e99e43d3 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof HTMLFormElement;
} catch {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_getItem_845e475f85f593e4 = function() { return handleError(function (arg0, arg1, arg2, arg3) {
const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
}, arguments) };
imports.wbg.__wbg_removeItem_9da69ede4eea3326 = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_setItem_9c469d634d0c321c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
}, arguments) };
imports.wbg.__wbg_new_ca4d3a3eca340210 = function() { return handleError(function () {
const ret = new URLSearchParams();
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_add_89a4f3b0846cf0aa = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).add(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_remove_1a26eb5d822902ed = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_pathname_78a642e573bf8169 = function(arg0, arg1) { imports.wbg.__wbg_pathname_78a642e573bf8169 = function(arg0, arg1) {
const ret = getObject(arg1).pathname; const ret = getObject(arg1).pathname;
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -620,6 +610,10 @@ function getImports() {
const ret = new URL(getStringFromWasm0(arg0, arg1)); const ret = new URL(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_new_ca4d3a3eca340210 = function() { return handleError(function () {
const ret = new URLSearchParams();
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_instanceof_HtmlInputElement_970e4026de0fccff = function(arg0) { imports.wbg.__wbg_instanceof_HtmlInputElement_970e4026de0fccff = function(arg0) {
let result; let result;
try { try {
@ -643,13 +637,11 @@ function getImports() {
imports.wbg.__wbg_setvalue_e5b519cca37d82a7 = function(arg0, arg1, arg2) { imports.wbg.__wbg_setvalue_e5b519cca37d82a7 = function(arg0, arg1, arg2) {
getObject(arg0).value = getStringFromWasm0(arg1, arg2); getObject(arg0).value = getStringFromWasm0(arg1, arg2);
}; };
imports.wbg.__wbg_create_53c6ddb068a22172 = function() { return handleError(function (arg0, arg1) { imports.wbg.__wbg_add_89a4f3b0846cf0aa = function() { return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).create(getObject(arg1)); getObject(arg0).add(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_get_da97585bbb5a63bb = function() { return handleError(function (arg0, arg1) { imports.wbg.__wbg_remove_1a26eb5d822902ed = function() { return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).get(getObject(arg1)); getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_href_90ff36b5040e3b76 = function(arg0, arg1) { imports.wbg.__wbg_href_90ff36b5040e3b76 = function(arg0, arg1) {
const ret = getObject(arg1).href; const ret = getObject(arg1).href;
@ -720,10 +712,14 @@ function getImports() {
imports.wbg.__wbg_focus_adfe4cc61e2c09bc = function() { return handleError(function (arg0) { imports.wbg.__wbg_focus_adfe4cc61e2c09bc = function() { return handleError(function (arg0) {
getObject(arg0).focus(); getObject(arg0).focus();
}, arguments) }; }, arguments) };
imports.wbg.__wbg_credentials_eab5c0bffc3e9cc5 = function(arg0) { imports.wbg.__wbg_create_53c6ddb068a22172 = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg0).credentials; const ret = getObject(arg0).create(getObject(arg1));
return addHeapObject(ret); return addHeapObject(ret);
}; }, arguments) };
imports.wbg.__wbg_get_da97585bbb5a63bb = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg0).get(getObject(arg1));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_getClientExtensionResults_0381c2792f96b9fa = function(arg0) { imports.wbg.__wbg_getClientExtensionResults_0381c2792f96b9fa = function(arg0) {
const ret = getObject(arg0).getClientExtensionResults(); const ret = getObject(arg0).getClientExtensionResults();
return addHeapObject(ret); return addHeapObject(ret);
@ -757,6 +753,10 @@ function getImports() {
const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2)); const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbg_credentials_eab5c0bffc3e9cc5 = function(arg0) {
const ret = getObject(arg0).credentials;
return addHeapObject(ret);
};
imports.wbg.__wbg_addEventListener_1fc744729ac6dc27 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { imports.wbg.__wbg_addEventListener_1fc744729ac6dc27 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
}, arguments) }; }, arguments) };
@ -786,6 +786,20 @@ function getImports() {
const ret = getObject(arg0).removeChild(getObject(arg1)); const ret = getObject(arg0).removeChild(getObject(arg1));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_instanceof_WorkerGlobalScope_16bb97a4549a3f21 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof WorkerGlobalScope;
} catch {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_fetch_749a56934f95c96c = function(arg0, arg1) {
const ret = getObject(arg0).fetch(getObject(arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_pushState_38917fb88b4add30 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { imports.wbg.__wbg_pushState_38917fb88b4add30 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5));
}, arguments) }; }, arguments) };
@ -1016,10 +1030,6 @@ function getImports() {
const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
return ret; return ret;
}, arguments) }; }, arguments) };
imports.wbg.__wbg_stringify_d6471d300ded9b68 = function() { return handleError(function (arg0) {
const ret = JSON.stringify(getObject(arg0));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbindgen_bigint_get_as_i64 = function(arg0, arg1) { imports.wbg.__wbindgen_bigint_get_as_i64 = function(arg0, arg1) {
const v = getObject(arg1); const v = getObject(arg1);
const ret = typeof(v) === 'bigint' ? v : undefined; const ret = typeof(v) === 'bigint' ? v : undefined;
@ -1040,16 +1050,16 @@ function getImports() {
const ret = wasm.memory; const ret = wasm.memory;
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_closure_wrapper4814 = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper4824 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1014, __wbg_adapter_48); const ret = makeMutClosure(arg0, arg1, 1020, __wbg_adapter_48);
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_closure_wrapper5000 = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper5009 = function(arg0, arg1, arg2) {
const ret = makeClosure(arg0, arg1, 1041, __wbg_adapter_51); const ret = makeClosure(arg0, arg1, 1044, __wbg_adapter_51);
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_closure_wrapper5658 = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper5669 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1290, __wbg_adapter_54); const ret = makeMutClosure(arg0, arg1, 1294, __wbg_adapter_54);
return addHeapObject(ret); return addHeapObject(ret);
}; };

View file

@ -237,6 +237,7 @@ impl ViewsApp {
let current_user_uat = uat.clone(); let current_user_uat = uat.clone();
let ui_hint_experimental = uat.ui_hints.contains(&UiHint::ExperimentalFeatures); let ui_hint_experimental = uat.ui_hints.contains(&UiHint::ExperimentalFeatures);
let credential_update = uat.ui_hints.contains(&UiHint::CredentialUpdate);
// WARN set dash-body against body here? // WARN set dash-body against body here?
html! { html! {
@ -269,12 +270,14 @@ impl ViewsApp {
</li> </li>
} }
if credential_update {
<li class="mb-1"> <li class="mb-1">
<Link<ViewRoute> classes="nav-link" to={ViewRoute::Security}> <Link<ViewRoute> classes="nav-link" to={ViewRoute::Security}>
<span data-feather="file"></span> <span data-feather="file"></span>
{ "Security" } { "Security" }
</Link<ViewRoute>> </Link<ViewRoute>>
</li> </li>
}
if ui_hint_experimental { if ui_hint_experimental {
<li class="mb-1"> <li class="mb-1">
@ -292,10 +295,10 @@ impl ViewsApp {
>{"Sign out"}</a> >{"Sign out"}</a>
</li> </li>
</ul> </ul>
<form class="d-flex"> // <form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" /> // <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
<button class="btn btn-outline-light" type="submit">{"Search"}</button> // <button class="btn btn-outline-light" type="submit">{"Search"}</button>
</form> // </form>
</div> </div>
</div> </div>
</nav> </nav>