Menú desplegable configurable

1. DESCRIPCIÓN GENERAL

El administrador puede crear elementos de interfaz de usuario del tipo «menú desplegable» con un comportamiento personalizado y añadirlos a las vistas. La personalización consiste en que el Administrador puede definir, en forma de solicitud v2 API, la regla por la cual el menú desplegable genera la lista de valores que muestra cuando el Usuario hace clic en él.

El caso de uso típico del menú desplegable configurable es tener un «selector dependiente». Esto significa tener un menú desplegable que muestre una lista limitada de los valores del campo respectivo, dependiendo de los valores establecidos para otros campos de la misma entidad. Esto evita que el usuario tenga que desplazarse por una larga lista de todos los valores posibles.

Ejemplo 1: Cuando el usuario vincula una característica a un incremento de programa (PI), desea que el menú desplegable «Incremento de programa» solo muestre los PI del tren de lanzamiento ágil (ART) concreto asignado a esta característica. El usuario no quiere desplazarse por todos los PI de ART y adivinar cuál es el suyo.

Ejemplo 2: Cuando el usuario vincula un elemento de trabajo a un resultado clave, desea que el menú desplegable «Resultado clave» solo muestre los resultados clave del objetivo al que está vinculado este elemento de trabajo. El usuario no quiere desplazarse por todos los resultados clave del sistema.

2. CÓMO CONFIGURAR Y AÑADIR MENÚS DESPLEGABLES

2.1. ¿Qué es una configuración?

Un caso concreto de personalización del comportamiento del menú desplegable se denomina «configuración» del menú desplegable. El menú desplegable configurable es compatible actualmente con, y su configuración se puede utilizar en:

  1. Vistas detalladas, como elemento de control desplegable,
  2. Vistas de lista y listas internas, como una unidad.

Cada configuración puede asociarse únicamente a un campo de un tipo de entidad (tipos). Este campo puede ser un enlace a una entidad predeterminada (dominio nativo), un enlace a una entidad de dominio ampliable o un campo personalizado de tipo «Entidad de proceso de destino».

Una configuración es, de hecho, un fragmento de código, una solicitud a la API de controles configurables que contiene un conjunto de atributos. Los atributos se explican en la sección Atributos de configuración.

2.2. Creación de una configuración desplegable

Se puede crear una configuración con una combinación.

Creemos una configuración de ejemplo para resolver el problema del ejemplo 1 anterior.

Con el modelo de datos SAFe, nuestra cuenta tiene, entre otras cosas, los siguientes tipos de entidades:

  1. Agile Release Train, o ART. Básicamente, se trata de un «equipo de equipos». Se implementa como un tipo de entidad de dominio extensible y es padre del tipo de entidad Equipo.
  2. Incremento del programa, o PI. Se trata básicamente de una iteración del trabajo de un ART, es decir, un periodo de tiempo vinculado a un ART. Es una versión renombrada, que es un tipo de entidad predeterminado.

De forma predeterminada, el menú desplegable «Incremento del programa» muestra una lista de los PI de todos los ART presentes en la cuenta, incluso si se ha asignado un ART concreto a la entidad en cuestión. Puede resultar difícil para el usuario examinar todas las PI, la mayoría de las cuales son irrelevantes. Esta captura de pantalla ilustra el problema:

El menú desplegable muestra una lista de los PI de todos los ART presentes en la cuenta Los PI de todos los ART están disponibles en el menú desplegable Incremento del programa (vista de lista)

Ahora añadamos un mashup con una configuración que alivie el problema; véase el código siguiente. Esta configuración hace que el menú desplegable del campo «Incremento del programa» solo muestre los incrementos del programa del ART asignado a esta entidad concreta (por ejemplo, una función). En otras palabras, evita que el usuario tenga que seleccionar entre los PI de todas las ART de la cuenta.

Esta configuración también ordena la lista de PI en el menú desplegable por nombre en orden descendente. Dadas las convenciones de nomenclatura de esta cuenta demo en particular, esto significa que los PI más recientes aparecerán en la parte superior de la lista desplegable.

Código de ejemplo:

tau.mashups
    .addDependency('tau/api/configurable-controls/controls/v1')
    .addMashup(( controlsApiV1 ) => {
        controlsApiV1.addConfiguration('dropdown', {
          id: 'dd_conf_01',
		  name: 'Program Increments of the assigned ART',
          label: 'Program Increment',
          supportedEntityTypes: ['feature'],
          requiredEntityFields: ['id', 'name', 'release'],
          sampleData: {
            release: { name: 'Program Increment' }
          },
          entityClickBehavior: 'openEntity',
          field: 'release',
          dropdownItemsSource: {
            type: 'interpolatedQuery',
            query: "release?where=(agileReleaseTrain.id==${{agileReleaseTrain.id}}$)&orderBy=name desc"
          }
        })
    })
Al configurar la combinación, en el campo «Marcador(es) de posición» puede utilizar cualquier marcador de posición global, por ejemplo:

footerPlaceholder

. Una vez añadido el mashup, puede utilizar esta configuración del menú desplegable en las vistas. Tenga en cuenta que puede añadir cualquier número de configuraciones en una sola combinación. (Para obtener más información sobre cómo funciona esta combinación, consulte la sección Atributos de configuración )

2.3. Añadir una configuración desplegable a las vistas detalladas

En la página del editor de diseño de vista detallada, encontrará un fragmento de la configuración necesaria para utilizar en su diseño: En la página del editor de diseño de vista detallada, encontrará un fragmento de la configuración necesaria para utilizar en su diseño. El fragmento debe añadirse como un nuevo componente de propiedad o colocarse en lugar de un componente de propiedad existente, en el diseño de vista detallada del tipo de entidad de destino: Sustitución de un componente de propiedad predeterminado por una configuración desplegable personalizada en vistas detalladas. Ahora, en las vistas detalladas, nuestro ejemplo de menú desplegable Incremento del programa solo muestra los PI del ART asignados a la entidad: El menú desplegable Incremento del programa solo muestra los PI del ART asignado a la entidad

2.4. Añadir una configuración desplegable a una vista de lista

En las vistas de lista, la configuración del menú desplegable se refleja en una unidad personalizada para el campo de destino. Añada esta unidad personalizada a la configuración de la vista en la pestaña «Personalizar tarjetas» (probablemente querrá sustituir la unidad predeterminada): Cambiar la unidad predeterminada «Incremento del programa» por una configurada en una vista de lista. Ahora, en esta vista de lista, el menú desplegable «Incremento del programa» solo muestra los PI del ART asignado a esta entidad en particular: Solo los PI del ART seleccionado están disponibles en el menú desplegable (vista de lista)

2.5. Añadir una configuración desplegable a la adición rápida

Para añadir campos desplegables configurables en Quick Add, el primer paso es crear una configuración. Asegúrate de que "allowedLocations" contiene "quickAdd" (consulta los atributos de configuración más abajo) o no está configurado en absoluto.
tau.mashups
    .addDependency('tau/api/configurable-controls/controls/v1')
    .addMashup(( controlsApiV1 ) => {
        controlsApiV1.addConfiguration('dropdown', {
          id: 'dd_conf_01',
          name: 'Program Increments of the assigned ART',
          label: 'Program Increment',
          supportedEntityTypes: ['feature'],
          requiredEntityFields: ['id', 'name', 'release'],
          allowReset:false,
          sampleData: {
            release: { name: 'Program Increment' }
          },
          entityClickBehavior: 'openEntity',
          field: 'release',
          dropdownItemsSource: {
            type: 'custom',
            getItems: async ({entity}) => {
                const artId = entity.agilereleasetrain || (entity.agileReleaseTrain && entity.agileReleaseTrain.id) || null
                const response = await fetch(___PROTECTED_5___);
                const {items} = await response.json();
                return items;
              }
            //type: 'interpolatedQuery',
            //query: "release?where=(agileReleaseTrain.id==${{agileReleaseTrain.id}}$)&orderBy=name desc"
            }
        })
    })
Ahora ve a «Configuración», selecciona «Añadir rápidamente» en la parte izquierda y elige la entidad que desees. Esta imagen muestra la configuración, y luego selecciona «Añadir rápidamente» en el lado izquierdo y selecciona la entidad deseada. Seleccione «Añadir campo» y elija el campo configurado previamente. Todos los campos desplegables configurables serán visibles en la parte inferior. Esta imagen muestra la función de búsqueda rápida de características Después de seleccionar un campo, se añadirá a la lista de campos configurados. El indicador «Required» se controla mediante "allowReset" el indicador en la configuración. Si no está establecido \"allowReset\" o es «true», el campo no será obligatorio. Ahora abre la ventana emergente «Añadir rápidamente» haciendo clic en el botón de la esquina superior derecha y selecciona la entidad que hayas configurado. Deberías ver un campo desplegable configurable en la lista de campos de entidad. Esta imagen muestra cómo abrir la ventana emergente de adición rápida haciendo clic en el botón de la esquina superior derecha y seleccionando la entidad configurada.

3. ATRIBUTOS DE CONFIGURACIÓN

A continuación se enumeran y explican todos los atributos posibles de una configuración de un menú desplegable.

3.1. <b>id</b>

¿Obligatorio? Sí. Identificador de texto especificado por el creador de la aplicación combinada. Debe ser único entre los controles del mismo tipo (es decir, «desplegable»). Se recomienda utilizar letras minúsculas para el parámetro ID.

3.2. <b>nombre</b>

¿Obligatorio? Núm. Nombre de texto amistoso. Utiliza esto para ayudar a las personas a comprender qué hace esta configuración.

3.3. <b>etiqueta</b>

¿Obligatorio? Sí. Texto que aparece como etiqueta del menú desplegable en las vistas detalladas y como encabezado de columna en las listas.

3.4. <b>supportedEntityTypes</b>

¿Obligatorio? Núm. Nombres de tipos de entidad de Targetprocess (en minúsculas) que admiten la representación de este control concreto. Si no se proporciona ninguno, se considera que el control es universal. Fragmento de ejemplo: supportedEntityTypes: ['userstory', 'bug']

3.5. <b>allowedLocations</b>

¿Obligatorio? Núm. Permite utilizar esta configuración desplegable solo en tipos de vista específicos, por ejemplo, solo en vistas detalladas, pero no en listas. Fragmento de ejemplo:
allowedLocations: {
  listUnit: false,
  detailedView: true,
  quickAdd: true,
}
De forma predeterminada, una configuración se puede utilizar en todos los tipos de vista compatibles actualmente con el menú desplegable configurable.

3.6. <b>requiredEntityFields</b>

¿Obligatorio? No (Sí, para el campo personalizado Entidad). Una lista de campos que deben estar disponibles en “ConfigurableControlInfo” (véase más abajo) y que deben solicitarse para que este control se pueda renderizar. Los campos pueden pertenecer a la propia entidad con la que se utilizará esta configuración desplegable (la entidad «destino»), así como a entidades vinculadas a ella. Los campos se agregan en un único selector de v2 API, por lo que es posible utilizar nombres de campo (por ejemplo, «esfuerzo») o selectores v2 de API con alias (por ejemplo, "userStoryId:userStory «.id», un ID de una historia de usuario vinculada a la entidad de destino). Los nombres de los campos deben escribirse en mayúsculas y minúsculas. E.g. userStory. Fragmento de ejemplo:
requiredEntityFields: [
    'id', 
    'name', 
    'feature:{id:feature.id,name:feature.name,projectId:feature.project.id}', 
    'tasks:tasks.select({id,name})',
    'customFieldName: {id:CustomValues.Entity("Custom Field Name").id, name:CustomValues.Entity("Custom Field Name").name, resourceType:"entityTypeName"}'
]

3.7. <b>sampleData</b>

¿Obligatorio? Núm. Una lista de valores ficticios para todos los campos que son obligatorios según el atributo «Campos de entidad obligatorios». Estos valores ficticios se utilizarán para representar el control en todos los editores (como Personalizar tarjetas) en los que no se dispone de datos de entidad, con el fin de mostrar una vista previa significativa. Fragmento de ejemplo:
sampleData: {
  id: 5,
  name: 'Some name',
  feature: {id: 10, name: 'Some feature name', projectId: 50},
  tasks: [
    {id: 18, name: 'Task 1'},
    {id: 19, name: 'Task 2'}
  ]
}

3.8. <b>isEnabled</b>

¿Obligatorio? Núm. Una devolución de llamada que consiste en una comprobación específica para determinar si el control debe habilitarse o deshabilitarse (es decir, solo lectura). Plantilla:
isEnabled?: {
    callback: (info: ConfigurableControlInfo) => boolean | PromiseLike<boolean>;
    rerunOnRequiredFieldsChanged: string[];
  }
Fragmento de ejemplo 1: el control solo se habilita si el nombre de la entidad de destino comienza con una «S» o «s»:
isEnabled: {
    callback: info => info.entity.name.toLowerCase().startsWith('s'),
    rerunOnRequiredFieldsChanged: ['name']
}
Fragmento de código 2: el control siempre está desactivado (solo lectura):
isEnabled: { 
    callback: () => false, 
    rerunOnRequiredFieldsChanged: [] 
}
La devolución de llamada se ejecuta a) antes de la inicialización del control, y b) cuando se actualiza uno de los "rerunOnRequiredFieldsChanged" campos de la entidad enumerados en. En la representación inicial, si la devolución de llamada devuelve un valor similar a una promesa, el control se desactivará y permanecerá desactivado hasta que el valor similar a una promesa se resuelva con un valor verdadero; si se rechaza o se resuelve con un valor falso, el control permanecerá desactivado. Al volver a renderizar el menú desplegable, la "rerunOnRequiredFieldsChanged" colección se comparará con los campos que están presentes en requiredEntityFields y se han actualizado. Si alguno de ellos ha sido modificado, se ejecuta la devolución de llamada. Si la devolución de llamada devuelve una promesa, por motivos de experiencia de usuario, el control conserva visualmente (pero no funcionalmente) su estado anterior de «desactivación» hasta que se resuelva la promesa, para evitar destellos con cada modificación. TENGA EN CUENTA que al registrar el control como una unidad (es decir, en Listas), esta devolución de llamada se ejecutará para cada tarjeta visible. Por lo tanto, si la devolución de llamada realiza un trabajo pesado y/o asíncrono para verificar la visibilidad (como una solicitud de red), esto puede afectar negativamente al rendimiento cuando se utiliza como unidad. Si no "rerunOnRequiredFieldsChanged" se proporciona o está vacío, la devolución de llamada solo se ejecutará para el renderizado inicial. Si no isEnabled se proporciona, el control siempre estará habilitado.

3.9. <b>entityClickBehavior</b>

¿Obligatorio? Sí. Determina qué sucede cuando el menú desplegable no está abierto y el usuario hace clic en el nombre de la entidad seleccionada para este campo. "openDropdown" ignora el enlace de la entidad y abre el menú desplegable; "openEntity" abre la vista detallada de la entidad. Fragmento de ejemplo: entityClickBehavior: 'openEntity'

3.10. <b>campo</b>

¿Obligatorio? Sí. El nombre del campo de la entidad para el que se utilizará el menú desplegable. Para los campos personalizados, se especifica el nombre del campo personalizado. Para los campos no personalizados, se especifica uno de los requiredEntityFields campos presentes en. El comportamiento en el campo debe cumplir las siguientes condiciones:
  1. Es null cuando no se establece ningún valor.
  2. Tiene los parámetros idname y (ambos obligatorios), y un parámetro resourceType opcional que se utiliza para producir el color correcto de la etiqueta de la entidad.

El campo se utilizará tanto para mostrar el valor como para actualizarlo cuando se seleccione una nueva opción del menú desplegable.

El nombre del campo debe escribirse en mayúsculas y minúsculas. E.g. userStory.

3.11. <b>allowReset</b>

¿Obligatorio? Núm. Atributo booleano que determina si el menú desplegable admite un valor vacío. Es «verdadero» por defecto.

3.12. <b>dropdownItemsSource</b>

¿Obligatorio? Sí. Un subconjunto de atributos que determina la procedencia de los elementos de la lista desplegable. Los elementos pueden proporcionarse mediante una consulta interpolada o una función personalizada. Plantilla:
dropdownItemsSource:
    | {
        type: 'interpolatedQuery';
        query: string;
      }
    | {
        type: 'custom';
        getItems: (info: ConfigurableControlInfo) => PromiseLike<{id: any; name: string}[]>;
      };
Una consulta interpolada es una solicitud con plantilla a la API v2. Puede hacer referencia a los campos de la entidad de destino con la sintaxis de plantilla: ${{}}$ (signo de dólar, doble llave abierta, expresión, doble llave cerrada, signo de dólar), por ejemplo: "feature?where=(epic.id=='${{epic.id}}$)" Lo que significa «mostrar las características que están vinculadas a la misma épica a la que está vinculada esta entidad de destino». En el caso de, type: 'custom' opciónlos elementos de la lista son proporcionados por una función personalizada que toma la información sobre el estado del menú desplegable (incluidos los requiredEntityFields valores) como entrada y devuelve de forma asíncrona una matriz de objetos con los campos «id» y «name». En principio, esta función personalizada puede realizar solicitudes a cualquier destino o incluso devolver algunos datos codificados. Ejemplo:
getItems: async info => {
  const response = await fetch(___PROTECTED_17___);
  const items = await response.json();
  return items;
}
Esta función personalizada realiza una solicitud a un servicio concreto para obtener una matriz de entidades que satisfacen una condición determinada y, a continuación, devuelve la matriz.

3.13. <b>showSearch</b>

¿Obligatorio? Núm. Un atributo booleano que determina si el menú desplegable está siempre buscando. Es «falso» por defecto. Si no se configura, el menú desplegable permite buscar más de 10 elementos.

4. BIBLIOTECA DE CONFIGURACIONES

Esta sección es una recopilación de ejemplos útiles de configuración de menús desplegables procedentes de cuentas reales de clientes. Puede tomar estos ejemplos y modificarlos para crear sus nuevas configuraciones. A medida que haya nuevos ejemplos útiles disponibles, se irán añadiendo aquí.

4.1. Mostrar flujos de valor relevantes para los ART asignados

Con esta configuración, el menú desplegable «Value Stream» solo mostrará los flujos de valor relevantes para los ART asignados a la entidad de destino. Si no se asignan ART, el menú desplegable muestra todos los flujos de valor de la cuenta.
tau.mashups
    .addDependency('tau/api/configurable-controls/controls/v1')
    .addMashup(controlsApiV1 => {
        controlsApiV1.addConfiguration('dropdown', {
            id: 'feature_valuestream_filtered_by_assigned_art',
            name: 'Value Stream filtered by ART',
            label: 'Value Stream',
            supportedEntityTypes: ['feature'],
            requiredEntityFields: ['valueStream'],
            sampleData: {
                valueStream: { resourceType: 'valuestream', name: 'Value Stream' }
            },
            entityClickBehavior: 'openDropdown',
            field: 'valueStream',
            dropdownItemsSource: {
                type: 'interpolatedQuery',
                query: "valuestream?where=(valueStreamAgileReleaseTrains.count(${{agileReleaseTrain.id}}$ == null or agileReleaseTrain.id == ${{agileReleaseTrain.id}}$) > 0)&take=999"
            }
        })
    })

4.2. Mostrar incrementos del programa con sus proyectos correspondientes

Con esta configuración, el menú desplegable Incremento del programa (o Versión) mostrará su lista de valores posibles, cada uno de ellos combinado con el nombre de su entidad de proyecto correspondiente. Esto se implementa con una fuente de elementos personalizada, ya que una consulta interpolada no funcionaría. Tenga en cuenta que la lista solo contendrá los incrementos de programa que se están ejecutando actualmente (mediante la &where=(IsCurrent == True) condición). Esta imagen muestra las listas desplegables con los nombres de los proyectos correspondientes.
tau.mashups
    .addDependency('tau/api/configurable-controls/controls/v1')
    .addDependency('tau/configurator')
    .addMashup(( controlsApiV1, configurator ) => {
        const store2 = configurator.getStore2();
        controlsApiV1.addConfiguration('dropdown', {
          id: 'dd_conf_03',
          name: 'PI with Project',
          label: 'PI w/ Project',
          supportedEntityTypes: ['teamiteration'],
          requiredEntityFields: ['release'],
          sampleData: {
            release: {name: 'Program Increment', resourceType: 'release'}
          },
          entityClickBehavior: 'openEntity',
          field: 'release',
          dropdownItemsSource: {
            type: 'custom',
            getItems: async () => {
                const releasesWithProjects = await store2.findAll('release?select={id,name,projectName:project.name}&where=(IsCurrent == True)&orderBy=name desc');
                return releasesWithProjects.map(release => ({
                    id: release.id,
                    name: ___PROTECTED_19___
                }));
            }
          }
        });
    })

4.3. Mostrar solo los usuarios adecuados y disponibles para una asignación de trabajo

Esta configuración limita la lista desplegable de usuarios conectados en una entidad de asignación de trabajo solo a aquellos usuarios que:
  1. Tener al menos una de las habilidades requeridas en esta asignación de trabajo
  2. Tener disponibilidad en todos los periodos en los que esta asignación de trabajo tiene demanda, y que dicha disponibilidad tenga una capacidad igual o superior al FTE requerido por esta asignación de trabajo.

En otras palabras, el menú desplegable solo mostrará los usuarios que tengan la habilidad necesaria y suficiente capacidad no asignada en los periodos necesarios.

tau.mashups
    .addDependency('tau/api/configurable-controls/controls/v1')
    .addMashup(( controlsApiV1 ) => {
        controlsApiV1.addConfiguration('dropdown', {
          id: 'dd_conf_04',
          name: 'Connected User',
          label: 'Connected User',
          supportedEntityTypes: ['WorkAllocation'],
          requiredEntityFields: ['connectedUser:connectedUser==null?null:{id:connectedUser.id,name:connectedUser.fullName,resourceType:connectedUser.resourceType}'],
          sampleData: {
            ConnectedUser: { name: 'John Smith' }
          },
          entityClickBehavior: 'openEntity',
          field: 'connectedUser',
          dropdownItemsSource: {
            type: 'interpolatedQuery',
            query: "user?select={id, fullname as name}&where=(Skills.Where(name==\"${{Skill.Name}}$\").Count()>0 and Availabilities.Where(Timeframe.Id in [${{Demands.Select(Timeframe.Id)}}$]).Count()==${{Demands.Count()}}$ and Availabilities.Where(Timeframe.Id in [${{Demands.Select(Timeframe.Id)}}$]).Where((AvailableCapacity/100)<${{CustomValues.Get(\"FTE\").Value}}$).Count()==0)"
          }
        })
    })
Para el requiredEntityFields atributo en este ejemplo concreto, no es posible utilizar una connectedUser referencia de la forma estándar (connectedUser: {id: connectedUser.id, name: connectedUser.name, resourceType: connectedUser.resourceType}). El selector debe modificarse porque hace referencia a la entidad Usuario, que no tiene un name campo. Por esta razón, lo alias fullName como name: {id: connectedUser.id, name: connectedUser.fullName, resourceType: connectedUser.resourceType}. Sin embargo, ahora no basta con utilizar solo este selector, ya que connectedUser being null producirá un objeto vacío (connectedUser: {}) en lugar de null. Para evitar esto, añadimos una comprobación adicional utilizando el operador ternario para evaluar siempre null que la entidad connectedUser también tenga un null valor. Para obtener más información sobre la sintaxis de los selectores v2 de API, consulte la Descripción general v2 de la API REST y los documentos relacionados. TENGA EN CUENTA que las asignaciones de trabajo, las habilidades, las disponibilidades, los plazos y las demandas son entidades de dominio ampliables que pueden no estar presentes en su cuenta de Targetprocess en particular.