feat: distinguish same-name GPU service resources across users

Resource names are unique per owning principal, so different users
can legally create same-name GPU instances, templates, SSH public
keys, storage volumes and storage types — but the admin's
cross-tenant lists and the instance-create template picker rendered
them indistinguishably.

- Group the template picker by owning scope: Your Templates, Global
  Templates, then — admin cross-tenant view only — one group per
  owner. A single group renders flat without headers. A plugin can
  take over grouping via hooks.useTemplateOwnerGroups when its
  principal model scopes templates beyond USER owners; a plugin
  without the hook keeps the flat list.
- Add an admin-only Creator column to the Instances, SSH Public
  Keys, Storage and Storage Types tables, sitting right before
  Created (mirroring the API Keys page convention). Resolves
  creator_id to a username via the user directory, falling back to
  owner_principal_id for legacy rows — a personal-scope row's
  creator IS its owner.
- Tag template cards with their owner scope (Global / username) for
  admins.

The Creator column and the card tag defer to a plugin that registers
the page's list columns / the OwnerScopeTag slot. Requires the
gpustack server change that records creator_id on templates, SSH
public keys and storage types.
This commit is contained in:
gitlawr
2026-06-12 20:22:56 +08:00
committed by Lawrence Li
parent 778ea36a9d
commit 7a76bda484
20 changed files with 395 additions and 54 deletions
+5 -1
View File
@@ -174,5 +174,9 @@ export default {
'Please enter the temporary storage capacity',
'gpuservice.form.rule.name':
"Lowercase letters, numbers, and '-'. Start and end with a letter or number, no consecutive '-', max 63 characters.",
'gpuservice.form.storage.select': 'Select Storage'
'gpuservice.form.storage.select': 'Select Storage',
'gpuservice.creator': 'Creator',
'gpuservice.owner.global': 'Global',
'gpuservice.template.group.yours': 'Your Templates',
'gpuservice.template.group.global': 'Global Templates'
};
+5 -1
View File
@@ -174,5 +174,9 @@ export default {
'Data is cleared when the instance stops.',
'gpuservice.storage.persistentVolume.tips':
'Data persists across instance restarts. Persistent volumes remain intact after instance termination and can be shared by multiple instances.',
'gpuservice.form.storage.select': 'ストレージを選択'
'gpuservice.form.storage.select': 'ストレージを選択',
'gpuservice.creator': '作成者',
'gpuservice.owner.global': 'グローバル',
'gpuservice.template.group.yours': '自分のテンプレート',
'gpuservice.template.group.global': 'グローバルテンプレート'
};
+5 -1
View File
@@ -171,5 +171,9 @@ export default {
'Data is cleared when the instance stops.',
'gpuservice.storage.persistentVolume.tips':
'Data persists across instance restarts. Persistent volumes remain intact after instance termination and can be shared by multiple instances.',
'gpuservice.form.storage.select': 'Выберите хранилище'
'gpuservice.form.storage.select': 'Выберите хранилище',
'gpuservice.creator': 'Создатель',
'gpuservice.owner.global': 'Глобальный',
'gpuservice.template.group.yours': 'Ваши шаблоны',
'gpuservice.template.group.global': 'Глобальные шаблоны'
};
+5 -1
View File
@@ -169,5 +169,9 @@ export default {
'Data is cleared when the instance stops.',
'gpuservice.storage.persistentVolume.tips':
'Data persists across instance restarts. Persistent volumes remain intact after instance termination and can be shared by multiple instances.',
'gpuservice.form.storage.select': 'Depolamayı Seç'
'gpuservice.form.storage.select': 'Depolamayı Seç',
'gpuservice.creator': 'Oluşturan',
'gpuservice.owner.global': 'Genel',
'gpuservice.template.group.yours': 'Şablonlarınız',
'gpuservice.template.group.global': 'Genel Şablonlar'
};
+5 -1
View File
@@ -158,5 +158,9 @@ export default {
'gpuservice.storage.tempCapacity.required': '请输入临时存储容量',
'gpuservice.form.rule.name':
'由小写字母、数字和 "-" 组成,以字母或数字开头和结尾,不能包含连续的 "-",最多 63 个字符。',
'gpuservice.form.storage.select': '选择存储'
'gpuservice.form.storage.select': '选择存储',
'gpuservice.creator': '创建者',
'gpuservice.owner.global': '全局',
'gpuservice.template.group.yours': '我的模板',
'gpuservice.template.group.global': '全局模板'
};