Skip to content

Commit

Permalink
something like feature flags
Browse files Browse the repository at this point in the history
  • Loading branch information
freddieptf committed Nov 19, 2024
1 parent 786acef commit 9ea6f96
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 43 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ To use the User Management Tool with your CHT project, you'll need to create a n
`contact_types.contact_properties` | Array<ConfigProperty> | Defines the attributes which are collected and set on the user's primary contact doc. See [ConfigProperty](#ConfigProperty).
`contact_types.deactivate_users_on_replace` | boolean | Controls what should happen to the defunct contact and user documents when a user is replaced. When `false`, the contact and user account will be deleted. When `true`, the contact will be unaltered and the user account will be assigned the role `deactivated`. This allows for account restoration.
`contact_types.hint` | string | Provide a brief hint or description to clarify the expected input for the property.
`contact_types.feature_flags` | Array | A list of features to enable for this contact type. Acceptable values are `create`, `replace-contact` and `move`. All features are enabled by default
`logoBase64` | Image in base64 | Logo image for your project

#### ConfigProperty
Expand Down
36 changes: 35 additions & 1 deletion src/config/chis-ke/config.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ export type ContactType = {
contact_type: string;
contact_friendly?: string;
user_role: string[];
username_from_place: boolean;
username_from_place?: boolean;
hierarchy: HierarchyConstraint[];
replacement_property: ContactProperty;
place_properties: ContactProperty[];
contact_properties: ContactProperty[];
deactivate_users_on_replace: boolean;
deactivate_users_on_replace?: boolean;
hint?: string;
feature_flags?: string[];
};

export type HierarchyConstraint = {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/remote-place-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { RemotePlace, ChtApi } from './cht-api';
import { Config, ContactType, HierarchyConstraint } from '../config';
import { Validation } from './validation';
import RemotePlaceCache from './remote-place-cache';
import assert from 'assert';

type RemotePlaceMap = { [key: string]: RemotePlace };

Expand Down Expand Up @@ -111,6 +112,7 @@ export default class RemotePlaceResolver {

function getFuzzFunction(place: Place, hierarchyLevel: HierarchyConstraint, contactType: ContactType) {
const fuzzingProperty = hierarchyLevel.level === 0 ? contactType.replacement_property : hierarchyLevel;
assert(fuzzingProperty);
if (fuzzingProperty.type === 'generated') {
throw Error(`Invalid configuration: hierarchy properties cannot be of type "generated".`);
}
Expand Down
24 changes: 17 additions & 7 deletions src/liquid/app/nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@
</a>
<div class="navbar-dropdown">
{% for placeType in contactTypes %}
<div class="navbar-item">
<b>{{placeType.friendly}}</b>
</div>
<a class="navbar-item" href="/add-place?type={{ placeType.name }}&op=new">Create New</a>
<a class="navbar-item" href="/add-place?type={{ placeType.name }}&op=replace">Replace Existing</a>
<a class="navbar-item" href="/add-place?type={{ placeType.name }}&op=bulk">Upload from CSV</a>
{% if placeType.feature_flags == undefined or placeType.feature_flags contains "create" or placeType.feature_flags contains "replace-contact" %}
<div class="navbar-item">
<b>{{placeType.friendly}}</b>
</div>
{%endif%}
{% if placeType.feature_flags == undefined or placeType.feature_flags contains "create" %}
<a class="navbar-item" href="/add-place?type={{ placeType.name }}&op=new">Create New</a>
{%endif%}
{% if placeType.feature_flags == undefined or placeType.feature_flags contains "replace-contact" %}
<a class="navbar-item" href="/add-place?type={{ placeType.name }}&op=replace">Replace Existing</a>
{%endif%}
{% if placeType.feature_flags == undefined or placeType.feature_flags contains "create" %}
<a class="navbar-item" href="/add-place?type={{ placeType.name }}&op=bulk">Upload from CSV</a>
{%endif%}
{% endfor%}
</div>
</div>
Expand All @@ -35,7 +43,9 @@
</a>
<div class="navbar-dropdown">
{% for placeType in contactTypes %}
<a class="navbar-item" href="/move/{{ placeType.name }}">Move {{placeType.friendly}}</a>
{% if placeType.feature_flags == undefined or placeType.feature_flags contains "move" %}
<a class="navbar-item" href="/move/{{ placeType.name }}">Move {{placeType.friendly}}</a>
{%endif%}
{% endfor%}
</div>
</div>
Expand Down
16 changes: 12 additions & 4 deletions src/liquid/place/directive_1_get_started.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@
<span class="material-symbols-outlined">add</span> Add {{contactType.friendly}}
</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="/add-place?type={{ contactType.name }}&op=new">Create New</a>
<a class="navbar-item" href="/add-place?type={{ contactType.name }}&op=replace">Replace Existing</a>
<a class="navbar-item" href="/add-place?type={{ contactType.name }}&op=bulk">Upload from CSV</a>
<a class="navbar-item" href="/move/{{ contactType.name }}">Move</a>
{% if contactType.feature_flags == undefined or contactType.feature_flags contains "create" %}
<a class="navbar-item" href="/add-place?type={{ contactType.name }}&op=new">Create New</a>
{%endif%}
{% if contactType.feature_flags == undefined or contactType.feature_flags contains "replace-contact" %}
<a class="navbar-item" href="/add-place?type={{ contactType.name }}&op=replace">Replace Existing</a>
{%endif%}
{% if contactType.feature_flags == undefined or contactType.feature_flags contains "create" %}
<a class="navbar-item" href="/add-place?type={{ contactType.name }}&op=bulk">Upload from CSV</a>
{%endif%}
{% if contactType.feature_flags == undefined or contactType.feature_flags contains "move" %}
<a class="navbar-item" href="/move/{{ contactType.name }}">Move</a>
{%endif%}
</div>
</div>
</div>
Expand Down
40 changes: 21 additions & 19 deletions src/liquid/place/list.html
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
<div id="place_list">
{% for contactType in contactTypes %}
<div id="{{contactType.name}}" class="mb-6">
<h2 class="title is-4">{{contactType.friendly}}</h2>
{% if contactType.places.length > 0 %}
<table
id="table_places"
class="table is-fullwidth is-striped is-hoverable"
>
{% include "components/table_header.html" contactType=contactType %}
<tbody>
{% for place in contactType.places %}
{% include "components/place_item.html" %}
{% endfor%}
</tbody>
</table>
{% else %}
<div class="notification is-white">
<i>No Results</i>
</div>
{% endif %}
{% if contactType.feature_flags == undefined or contactType.feature_flags contains "create" or contactType.feature_flags contains "replace-contact" %}
<div id="{{contactType.name}}" class="mb-6">
<h2 class="title is-4">{{contactType.friendly}}</h2>
{% if contactType.places.length > 0 %}
<table
id="table_places"
class="table is-fullwidth is-striped is-hoverable"
>
{% include "components/table_header.html" contactType=contactType %}
<tbody>
{% for place in contactType.places %}
{% include "components/place_item.html" %}
{% endfor%}
</tbody>
</table>
{% else %}
<div class="notification is-white">
<i>No Results</i>
</div>
{% endif %}
{%endif%}
{% endfor %}
</div>
22 changes: 12 additions & 10 deletions src/liquid/place/list_lazy.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<div id="place_list" hx-trigger="load" hx-get="/app/list" hx-target="this" hx-swap="outerHTML">
{% for contactType in contactTypes %}
<div id="{{contactType.name}}" class="mb-6">
<h2 class="title is-4">{{contactType.friendly}}</h2>
<div>
<table id="table_places" class="table is-fullwidth is-striped is-hoverable">
{% include "components/table_header.html" contactType=contactType %}
</table>
<div class="container p-6 is-flex is-justify-content-center is-align-content-center">
<img src="/public/spinner.gif" alt="Loading data" />
</div>
</div>
{% if contactType.feature_flags == undefined or contactType.feature_flags contains "create" or contactType.feature_flags contains "replace-contact" %}
<div id="{{contactType.name}}" class="mb-6">
<h2 class="title is-4">{{contactType.friendly}}</h2>
<div>
<table id="table_places" class="table is-fullwidth is-striped is-hoverable">
{% include "components/table_header.html" contactType=contactType %}
</table>
<div class="container p-6 is-flex is-justify-content-center is-align-content-center">
<img src="/public/spinner.gif" alt="Loading data" />
</div>
</div>
{%endif%}
{% endfor %}
</div>
</div>
7 changes: 7 additions & 0 deletions src/routes/add-place.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export default async function addPlace(fastify: FastifyInstance) {
? Config.getContactType(queryParams.type)
: contactTypes[contactTypes.length - 1];
const op = queryParams.op || 'new';
if (contactType.feature_flags) {
if ((op === 'new' && !contactType.feature_flags.includes('create')) ||
(op === 'replace' && !contactType.feature_flags.includes('replace-contact'))) {
resp.status(404);
return;
}
}
const tmplData = {
view: 'add',
logo: Config.getLogoBase64(),
Expand Down
4 changes: 4 additions & 0 deletions src/routes/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export default async function sessionCache(fastify: FastifyInstance) {
const contactTypes = Config.contactTypes();

const contactType = Config.getContactType(placeType);
if (contactType.feature_flags && !contactType.feature_flags.includes('move')) {
resp.code(404).type("text/html").send("Not Found");
return;
}
const tmplData = {
view: 'move',
op: 'move',
Expand Down

0 comments on commit 9ea6f96

Please sign in to comment.