Reintroduce the nullable api_tokens.dataset_id column (dropped in 2e9819ca5b28)
so dataset API keys can opt into per-knowledge-base scoping:
- NULL dataset_id keeps today's workspace-wide behavior, so every existing key
and the existing /datasets/api-keys create route are unchanged.
- validate_dataset_token rejects a bound key for any other dataset, and for
endpoints that carry no dataset id (e.g. list-all), with 403.
- CachedApiToken carries dataset_id with a None default so cache entries
written before deploy keep deserializing.
- The per-dataset console routes in apikey.py (previously dead code that 500ed
on a missing ApiToken.dataset_id) now create bound keys; their list returns
bound keys plus workspace keys so the dataset page shows the full access
picture.
- Frontend: the knowledge base API access popover gains an API keys entry; the
secret key modal accepts datasetId, shows a scope column, and offers a
workspace / this-knowledge-base scope choice on create. New strings are
localized for all 23 locales.