Skip to content

Commit 5167b4c

Browse files
committed
1 parent 4264bed commit 5167b4c

File tree

20 files changed

+170
-34
lines changed

20 files changed

+170
-34
lines changed

services/client/controllers/api/routes/picklist.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ router.get('/:idOrName', async (req, res) => {
2727
throw r.error;
2828
}
2929
logger.info('Picklist get successful', {corkTraceId: req.corkTraceId, picklistId: r.res.picklist_id});
30+
if ( !req.query.include_items ) {
31+
delete r.res.items;
32+
}
3033
res.status(200).json(r.res);
3134
} catch (e) {
3235
return handleError(res, req, e);

services/client/controllers/api/utils/handleError.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import logger from '../../../../lib/logger.js';
1+
import logger from '#lib/logger.js';
22
// import { MissingResourceError } from '../../../../lib/errors.js';
33

44
function handleError(res, req, error, details) {

services/client/controllers/api/utils/validation/schemas/picklist.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as z from "zod";
22
import { requiredString, urlFriendlyString, pageParam, perPageParam, booleanParam, toString } from "./utils.js";
3-
import models from '../../../../../../lib/models/index.js';
3+
import models from '#models';
44

55
const picklistBaseSchema = z.object({
66
description: toString.pipe(z.string().max(300)).optional(),
@@ -12,7 +12,9 @@ const picklistItemSchema = z.object({
1212
label: requiredString().pipe(z.string().max(250)),
1313
value: requiredString().pipe(z.string().max(250)),
1414
is_archived: z.boolean().optional(),
15-
sort_order: z.coerce.number().int().nonnegative().optional()
15+
sort_order: z.coerce.number().int().nonnegative().optional(),
16+
include_segment: z.array(z.string().max(250)).optional(),
17+
exclude_segment: z.array(z.string().max(250)).optional()
1618
});
1719

1820
const picklistCreateSchema = picklistBaseSchema.extend({
@@ -68,14 +70,6 @@ const picklistIdOrNameSchema = z.object({
6870
const picklistQuerySchema = z.object({
6971
page: pageParam,
7072
per_page: perPageParam(15),
71-
active: z.preprocess(
72-
v => {
73-
if (v === 'true') return true;
74-
if (v === 'false') return false;
75-
return v;
76-
},
77-
z.union([z.literal(true), z.literal(false)]).optional()
78-
),
7973
archived_only: booleanParam,
8074
active_only: booleanParam
8175
});

services/client/controllers/static.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { fileURLToPath } from 'url';
44
import spaMiddleware from '@ucd-lib/spa-router-middleware';
55

66
import loaderHtml from '../html/loader.html.js';
7-
import logger from '../../lib/logger.js';
8-
import config from '../../lib/config.js';
7+
import logger from '#lib/logger.js';
8+
import config from '#lib/config.js';
99
import preloadedIcons from './icons.js';
1010

1111
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -14,7 +14,7 @@ export default (app) => {
1414
let assetsDir = path.join(__dirname, '../public');
1515
logger.info(`Serving static assets from ${assetsDir}`);
1616

17-
const routes = ['picklist'];
17+
const routes = ['picklist', 'field'];
1818
const appTitle = 'Reference Statistics';
1919

2020
spaMiddleware({

services/client/dev/css/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ const styles = `
7373
line-height: 1.3rem;
7474
font-weight: 400;
7575
}
76+
.ucd-link-list-item .ucd-link-list-item--badge {
77+
display: inline-block;
78+
background-color: var(--ucd-blue-50, #cce0f3);
79+
color: var(--ucd-blue, #022851);
80+
padding: 0 0.25rem;
81+
font-size: .875rem;
82+
font-weight: 700;
83+
84+
}
7685
7786
${sharedStyles}
7887
${brandCssProps}

services/client/dev/elements/components/forms/ref-stats-picklist-form.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default class RefStatsPicklistForm extends Mixin(LitElement)
6767
this.payload = {};
6868
if ( !this.picklistIdOrName ) return;
6969

70-
const res = await this.PicklistModel.get(this.picklistIdOrName);
70+
const res = await this.PicklistModel.get(this.picklistIdOrName, {include_items: true});
7171
if ( res?.state === 'loaded' ) {
7272
this.payload = {...res.payload};
7373
}
@@ -85,7 +85,7 @@ export default class RefStatsPicklistForm extends Mixin(LitElement)
8585
_onDeleteRequest(){
8686
this.AppStateModel.showDialogModal({
8787
title: 'Delete Picklist',
88-
content: () => `Are you sure you want to delete this picklist? All data associated with this picklist will be lost. This action cannot be undone.`,
88+
content: () => `Are you sure you want to delete this picklist? All data associated with this picklist will be lost. This action cannot be undone. To retain data, archive the picklist instead.`,
8989
actions: [
9090
{text: 'Close', value: 'dismiss', invert: true, color: 'secondary'},
9191
{ text: 'Delete', color: 'double-decker', value: 'picklist-delete' }

services/client/dev/elements/components/forms/ref-stats-picklist-items-form.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@ export default class RefStatsPicklistItemsForm extends Mixin(LitElement)
3434

3535
willUpdate(props){
3636
if ( props.has('items') ) {
37-
this._items = this.items.map((item, i) => {
38-
return {edited: false, expanded: false, item: {...item, sort_order: i}}
37+
this._items = this.items.map((item, i) => {
38+
return {
39+
edited: false,
40+
expanded: false,
41+
include_segment_string: item.include_segment?.join(', ') || '',
42+
exclude_segment_string: item.exclude_segment?.join(', ') || '',
43+
item: {...item, sort_order: i}}
3944
});
4045
if ( this._items.length === 0 ) {
4146
this.addItem();
@@ -76,6 +81,12 @@ export default class RefStatsPicklistItemsForm extends Mixin(LitElement)
7681
this.requestUpdate();
7782
}
7883

84+
_onSegmentInput(item, include, value) {
85+
item[include ? 'include_segment_string' : 'exclude_segment_string'] = value;
86+
const segments = value.split(',').map( s => s.trim() ).filter( s => s );
87+
this._onItemInput(item, include ? 'include_segment' : 'exclude_segment', segments);
88+
}
89+
7990
setSortOrder(){
8091
this._items.forEach( (item, i) => {
8192
if ( item.item.sort_order !== i ) {

services/client/dev/elements/components/forms/ref-stats-picklist-items-form.tpl.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,34 @@ export function render() {
6868
required
6969
@input=${e => this._onItemInput(item, 'value', e.target.value)}>
7070
</cork-field-container>
71+
<cork-field-container schema='picklist' path='items.${item.editedOrder}.is_archived' class='field-container checkbox'>
72+
<input
73+
type="checkbox"
74+
id=${this.ctl.idGen.get('is_archived--' + i)}
75+
.checked=${item.item.is_archived || false}
76+
@input=${() => this._onItemInput(item, 'is_archived', !item.item.is_archived)}>
77+
<label for=${this.ctl.idGen.get('is_archived--' + i)}>Archived</label>
78+
</cork-field-container>
79+
<cork-field-container schema='picklist' path='items.${item.editedOrder}.include_segment' class='field-container'>
80+
<label for=${this.ctl.idGen.get('include-segment--' + i)}>Include Segments</label>
81+
<input
82+
type="text"
83+
id=${this.ctl.idGen.get('include-segment--' + i)}
84+
.value=${item.include_segment_string || ''}
85+
placeholder="e.g. segment1, segment2"
86+
@input=${e => this._onSegmentInput(item, true, e.target.value)}>
87+
<div class='field-description'>Comma-separated list of segments to include. Will only show this item for users in these segments.</div>
88+
</cork-field-container>
89+
<cork-field-container schema='picklist' path='items.${item.editedOrder}.exclude_segment' class='field-container'>
90+
<label for=${this.ctl.idGen.get('exclude-segment--' + i)}>Exclude Segments</label>
91+
<input
92+
type="text"
93+
id=${this.ctl.idGen.get('exclude-segment--' + i)}
94+
.value=${item.exclude_segment_string || ''}
95+
placeholder="e.g. segment1, segment2"
96+
@input=${e => this._onSegmentInput(item, false, e.target.value)}>
97+
<div class='field-description'>Comma-separated list of segments to exclude. Will hide this item for users in these segments.</div>
98+
</cork-field-container>
7199
</div>
72100
</div>
73101
`)}

services/client/dev/elements/components/ref-stats-picklists.tpl.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ return html`
1919
<div class='ucd-link-list-item'>
2020
<cork-icon icon='fas.circle-chevron-right' class='ucd-link-list-item--icon'></cork-icon>
2121
<div>
22-
<a href='/picklist/${picklist.name}' class='ucd-link-list-item--title'>${picklist.label} <span ?hidden=${!picklist.is_archived}>(Archived)</span></a>
22+
<a href='/picklist/${picklist.name}' class='ucd-link-list-item--title'>${picklist.label}</a>
23+
<div class='ucd-link-list-item--badge' ?hidden=${!picklist.is_archived}>Archived</div>
2324
<div class='ucd-link-list-item--excerpt'>
2425
<span>${picklist.name}</span>
2526
<span ?hidden=${!picklist.description}> | </span>

services/client/dev/elements/pages/admin/ref-stats-page-picklist.tpl.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function render() {
2222
<div class="l-container">
2323
<div class="l-basic--flipped">
2424
<div class="l-content">
25+
<p>Picklists are lists of predefined options that can be used in select, radio, and checkbox questions throughout the application. They help standardize responses and ensure data consistency.</p>
2526
<ref-stats-picklists></ref-stats-picklists>
2627
</div>
2728
<div class="l-sidebar-second">

0 commit comments

Comments
 (0)