135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
import type { Clarizen, JsonValue } from "@arco/clarizen-lib";
|
|
import { isCancel, select, spinner, text } from "@clack/prompts";
|
|
import { formatFieldHint } from "../metadata/field-hints.js";
|
|
import {
|
|
fetchPickListOptions,
|
|
formatPickListOptionLabel,
|
|
getPickListEntityType,
|
|
type FieldWithRefs,
|
|
} from "../metadata/picklist.js";
|
|
import { pickFromFiltered } from "../metadata/picker.js";
|
|
import { parseFieldValue, ValueParseError } from "./value.js";
|
|
|
|
export interface FieldValueSelection {
|
|
value: JsonValue;
|
|
displayLabel?: string;
|
|
}
|
|
|
|
async function pickPickListOption(
|
|
field: FieldWithRefs,
|
|
options: Array<{ value: string; label: string }>,
|
|
): Promise<string | symbol> {
|
|
const fieldLabel = field.label ?? field.name ?? "valor";
|
|
return pickFromFiltered(
|
|
`Escolha o valor para ${fieldLabel}`,
|
|
options,
|
|
"Como deseja buscar na lista?",
|
|
);
|
|
}
|
|
|
|
async function promptPickListSelection(
|
|
clarizen: Clarizen,
|
|
field: FieldWithRefs,
|
|
pickListTypeName: string,
|
|
): Promise<FieldValueSelection | symbol> {
|
|
const loadSpinner = spinner();
|
|
loadSpinner.start(`Carregando opções de ${pickListTypeName}...`);
|
|
|
|
const pickListOptions = await fetchPickListOptions(
|
|
clarizen,
|
|
pickListTypeName,
|
|
(count) => {
|
|
loadSpinner.message(
|
|
`Carregando opções de ${pickListTypeName}... (${count})`,
|
|
);
|
|
},
|
|
);
|
|
|
|
loadSpinner.stop(`${pickListOptions.length} opção(ões) carregada(s).`);
|
|
|
|
if (pickListOptions.length === 0) {
|
|
console.log(
|
|
`\nNenhuma opção encontrada para ${pickListTypeName}. Informe o ID manualmente.\n`,
|
|
);
|
|
return promptManualEntityValue(field);
|
|
}
|
|
|
|
const selectOptions = pickListOptions.map((o) => ({
|
|
value: o.id,
|
|
label: formatPickListOptionLabel(o),
|
|
}));
|
|
|
|
const selectedId = await pickPickListOption(field, selectOptions);
|
|
if (isCancel(selectedId)) return selectedId;
|
|
|
|
const match = pickListOptions.find((o) => o.id === selectedId);
|
|
return {
|
|
value: { id: selectedId },
|
|
displayLabel: match
|
|
? `${match.label} (${match.id})`
|
|
: String(selectedId),
|
|
};
|
|
}
|
|
|
|
async function promptManualEntityValue(
|
|
field: FieldWithRefs,
|
|
): Promise<FieldValueSelection | symbol> {
|
|
while (true) {
|
|
const raw = await text({
|
|
message: "Informe o ID da entidade (ex: /Tipo/guid)",
|
|
validate: (value) => (!value?.trim() ? "Valor obrigatório." : undefined),
|
|
});
|
|
if (isCancel(raw)) return raw;
|
|
|
|
try {
|
|
const value = parseFieldValue(raw, field);
|
|
return { value, displayLabel: formatEntityDisplayLabel(value) };
|
|
} catch (err) {
|
|
if (err instanceof ValueParseError) {
|
|
console.error(`\n Erro: ${err.message}\n`);
|
|
continue;
|
|
}
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
|
|
function formatEntityDisplayLabel(value: JsonValue): string | undefined {
|
|
if (value && typeof value === "object" && "id" in value) {
|
|
const id = (value as { id?: unknown }).id;
|
|
if (typeof id === "string") return id;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export async function promptPickListValue(
|
|
clarizen: Clarizen,
|
|
field: FieldWithRefs,
|
|
): Promise<FieldValueSelection | symbol> {
|
|
console.log("\n" + formatFieldHint(field) + "\n");
|
|
|
|
if (field.nullable) {
|
|
const action = await select({
|
|
message: "O que deseja fazer com este campo?",
|
|
options: [
|
|
{ value: "set", label: "Definir um valor" },
|
|
{ value: "clear", label: "Limpar campo (null)" },
|
|
],
|
|
});
|
|
if (isCancel(action)) return action;
|
|
if (action === "clear") {
|
|
return { value: null, displayLabel: "(vazio / null)" };
|
|
}
|
|
}
|
|
|
|
const pickListTypeName = getPickListEntityType(field);
|
|
if (!pickListTypeName) {
|
|
console.log(
|
|
"\nPicklist sem tipo de referência na metadata. Informe o ID manualmente.\n",
|
|
);
|
|
return promptManualEntityValue(field);
|
|
}
|
|
|
|
return promptPickListSelection(clarizen, field, pickListTypeName);
|
|
}
|