feat(datasources): enforce policy-aware data visibility
Module Package Release / publish-packages (push) Successful in 11s
Module Package Release / publish-packages (push) Successful in 11s
This commit is contained in:
@@ -73,6 +73,7 @@ import {
|
||||
import {
|
||||
DATASOURCE_FIELDS_DOCUMENTATION,
|
||||
DATASOURCE_GOVERNANCE_DOCUMENTATION,
|
||||
DATASOURCE_VISIBILITY_DOCUMENTATION,
|
||||
DATASOURCES_DOCUMENTATION,
|
||||
DATASOURCES_I18N
|
||||
} from "./interfacePatterns";
|
||||
@@ -898,6 +899,7 @@ function GovernanceDialog({
|
||||
const [draft, setDraft] = useState<DatasourceGovernance | null>(null);
|
||||
const [freshness, setFreshness] = useState("{}");
|
||||
const [quality, setQuality] = useState("{}");
|
||||
const [visibility, setVisibility] = useState("{}");
|
||||
const [baselineKey, setBaselineKey] = useState("");
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
@@ -908,14 +910,16 @@ function GovernanceDialog({
|
||||
const nextDraft = structuredClone(datasource.governance);
|
||||
const nextFreshness = JSON.stringify(datasource.governance.freshness_policy, null, 2);
|
||||
const nextQuality = JSON.stringify(datasource.governance.quality_policy, null, 2);
|
||||
const nextVisibility = JSON.stringify(datasource.governance.visibility_policy ?? {}, null, 2);
|
||||
setDraft(nextDraft);
|
||||
setFreshness(nextFreshness);
|
||||
setQuality(nextQuality);
|
||||
setBaselineKey(JSON.stringify({ draft: nextDraft, freshness: nextFreshness, quality: nextQuality }));
|
||||
setVisibility(nextVisibility);
|
||||
setBaselineKey(JSON.stringify({ draft: nextDraft, freshness: nextFreshness, quality: nextQuality, visibility: nextVisibility }));
|
||||
setError("");
|
||||
}, [datasource, open]);
|
||||
|
||||
const dirty = Boolean(open && draft && JSON.stringify({ draft, freshness, quality }) !== baselineKey);
|
||||
const dirty = Boolean(open && draft && JSON.stringify({ draft, freshness, quality, visibility }) !== baselineKey);
|
||||
|
||||
const save = async (): Promise<boolean> => {
|
||||
if (!datasource || !draft) return false;
|
||||
@@ -925,7 +929,8 @@ function GovernanceDialog({
|
||||
const updated = await updateDatasourceGovernance(settings, datasource.ref, {
|
||||
...draft,
|
||||
freshness_policy: parseObject(freshness, "Freshness policy"),
|
||||
quality_policy: parseObject(quality, "Quality policy")
|
||||
quality_policy: parseObject(quality, "Quality policy"),
|
||||
visibility_policy: parseObject(visibility, "Visibility policy")
|
||||
});
|
||||
await onSaved(updated);
|
||||
return true;
|
||||
@@ -1020,6 +1025,9 @@ function GovernanceDialog({
|
||||
<FormField label="Retention policy" interfaceId="datasources.field.retention-policy" helpContextId="datasources.field.retention-policy" helpModuleId="datasources" documentation={DATASOURCE_GOVERNANCE_DOCUMENTATION}>
|
||||
<input value={draft.retention_policy_ref ?? ""} onChange={(event) => setValue("retention_policy_ref", event.target.value || null)} />
|
||||
</FormField>
|
||||
<FormField label="Access policy reference" interfaceId="datasources.field.access-policy" helpContextId="datasources.field.access-policy" helpModuleId="datasources" documentation={DATASOURCE_VISIBILITY_DOCUMENTATION}>
|
||||
<input value={draft.access_policy_ref ?? ""} onChange={(event) => setValue("access_policy_ref", event.target.value || null)} placeholder="Optional Policy module target" />
|
||||
</FormField>
|
||||
<FormField label="Transfer agreement" interfaceId="datasources.field.transfer-agreement" helpContextId="datasources.field.transfer-agreement" helpModuleId="datasources" documentation={DATASOURCE_GOVERNANCE_DOCUMENTATION}>
|
||||
<input value={draft.transfer_agreement_ref ?? ""} onChange={(event) => setValue("transfer_agreement_ref", event.target.value || null)} />
|
||||
</FormField>
|
||||
@@ -1040,6 +1048,10 @@ function GovernanceDialog({
|
||||
<GovernanceListField label="Known limits" values={draft.known_limits} onChange={(values) => setValue("known_limits", values)} />
|
||||
</FormGrid>
|
||||
<FormGrid columns={2} gap="small" collapseAt="narrow">
|
||||
<FormField label="Visibility policy (JSON)" interfaceId="datasources.field.visibility-policy" helpContextId="datasources.field.visibility-policy" helpModuleId="datasources" documentation={DATASOURCE_VISIBILITY_DOCUMENTATION}>
|
||||
<textarea value={visibility} onChange={(event) => setVisibility(event.target.value)} spellCheck={false} />
|
||||
<small>Configure source and materialization ACLs, field redaction or omission, and principal-bound row filters.</small>
|
||||
</FormField>
|
||||
<FormField label="Freshness policy (JSON)" documentation={DATASOURCE_GOVERNANCE_DOCUMENTATION}>
|
||||
<textarea value={freshness} onChange={(event) => setFreshness(event.target.value)} spellCheck={false} />
|
||||
</FormField>
|
||||
@@ -1463,17 +1475,18 @@ function SchemaTable({ fields }: { fields: Datasource["schema"] }) {
|
||||
<div className="datasources-table-scroll">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Field</th><th>Type</th><th>Nullable</th></tr>
|
||||
<tr><th>Field</th><th>Type</th><th>Classification</th><th>Nullable</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{fields.map((field) => (
|
||||
<tr key={field.name}>
|
||||
<td>{field.name}</td>
|
||||
<td>{field.data_type}</td>
|
||||
<td>{readableToken(field.classification)}</td>
|
||||
<td>{field.nullable ? "Yes" : "No"}</td>
|
||||
</tr>
|
||||
))}
|
||||
{!fields.length ? <tr><td colSpan={3}>Schema not available</td></tr> : null}
|
||||
{!fields.length ? <tr><td colSpan={4}>Schema not available</td></tr> : null}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user