Show auto-collected contacts in a table (4.9.1-ops.16).

Align nickname, phone, source, and grant actions like the other access lists.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-05 18:14:13 +08:00
parent a10d900a7b
commit e4cdb6f60a
6 changed files with 220 additions and 153 deletions

View file

@ -571,7 +571,7 @@ var React24 = __toESM(require("react"), 1);
// package.json // package.json
var package_default = { var package_default = {
name: "dsh-im-ops", name: "dsh-im-ops",
version: "4.9.1-ops.15", version: "4.9.1-ops.16",
description: "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.", description: "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.",
keywords: [ keywords: [
"deepseek-harness", "deepseek-harness",
@ -852,6 +852,8 @@ var EN = Object.freeze({
"\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs", "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs",
"\u6295\u9012\u8BBE\u7F6E": "Delivery settings", "\u6295\u9012\u8BBE\u7F6E": "Delivery settings",
"\u8BBF\u95EE\u8BBE\u7F6E": "Access settings", "\u8BBF\u95EE\u8BBE\u7F6E": "Access settings",
"\u2014": "\u2014",
"\u6765\u6E90": "Source",
"\u6682\u65E0\u7BA1\u7406\u5458\uFF0C\u53EF\u70B9\u4E0B\u65B9\u65B0\u589E\u3002": "No admins yet. Add one below.", "\u6682\u65E0\u7BA1\u7406\u5458\uFF0C\u53EF\u70B9\u4E0B\u65B9\u65B0\u589E\u3002": "No admins yet. Add one below.",
"\u6682\u65E0\u7528\u6237\uFF0C\u53EF\u70B9\u4E0B\u65B9\u65B0\u589E\u3002": "No users yet. Add one below.", "\u6682\u65E0\u7528\u6237\uFF0C\u53EF\u70B9\u4E0B\u65B9\u65B0\u589E\u3002": "No users yet. Add one below.",
"\u4E0D\u53EF\u5220\u9664": "Locked", "\u4E0D\u53EF\u5220\u9664": "Locked",
@ -13254,90 +13256,123 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved
h2("legend", null, "\u6700\u8FD1\u8054\u7CFB\u4EBA\uFF08\u81EA\u52A8\u6C89\u6DC0\uFF09"), h2("legend", null, "\u6700\u8FD1\u8054\u7CFB\u4EBA\uFF08\u81EA\u52A8\u6C89\u6DC0\uFF09"),
h2( h2(
"p", "p",
{ className: "dim-accessUsersEmpty" }, { className: "dim-accessHint" },
"\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u5DF2\u6709\u5BF9\u5E94\u6743\u9650\u7684\u4EBA\u4F1A\u81EA\u52A8\u9690\u85CF\uFF1B\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002" "\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u5DF2\u6709\u5BF9\u5E94\u6743\u9650\u7684\u4EBA\u4F1A\u81EA\u52A8\u9690\u85CF\uFF1B\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002"
), ),
actionableContacts.length === 0 ? h2( actionableContacts.length === 0 ? h2(
"div", "div",
{ className: "dim-accessUsersEmpty" }, { className: "dim-accessUsersEmpty" },
contacts.length === 0 ? "\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002" : "\u5F53\u524D\u8054\u7CFB\u4EBA\u5747\u5DF2\u5177\u5907\u5BF9\u5E94\u6743\u9650\uFF0C\u65E0\u9700\u518D\u6388\u6743\u3002" contacts.length === 0 ? "\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002" : "\u5F53\u524D\u8054\u7CFB\u4EBA\u5747\u5DF2\u5177\u5907\u5BF9\u5E94\u6743\u9650\uFF0C\u65E0\u9700\u518D\u6388\u6743\u3002"
) : h2("ul", { className: "dim-accessUserList" }, actionableContacts.slice(0, 30).map((contact) => { ) : h2(
const phone = contact.phone || ""; "div",
const alreadyDirect = Boolean(phone) && ((draft.directMembers ?? []).some((m) => m.phone === phone) || (draft.globalAdmins ?? []).includes(phone)); { className: "dim-accessTableWrap" },
const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)).filter((groupJid) => { h2(
if (!phone) return true; "table",
const group = draft.groups[groupJid] ?? { admins: [], members: [] }; { className: "dim-accessTable", "data-kind": "contact" },
return !(group.admins ?? []).includes(phone) && !(group.members ?? []).some((m) => m.phone === phone);
});
return h2(
"li",
{
key: `${contact.phone ?? ""}-${(contact.lids ?? []).join(",")}`,
className: "dim-accessUserRow"
},
h2( h2(
"div", "thead",
{ className: "dim-accessField" }, null,
h2("strong", null, contactLabel(contact)), h2(
h2("span", null, (contact.scenes ?? []).join(" / ")), "tr",
phone ? null : h2("span", null, "\u5F85\u8865\u7535\u8BDD") null,
h2("th", { scope: "col" }, "\u6635\u79F0"),
h2("th", { scope: "col" }, "\u7535\u8BDD"),
h2("th", { scope: "col" }, "\u6765\u6E90"),
h2("th", { scope: "col", className: "dim-accessTableActions" }, "\u64CD\u4F5C")
)
), ),
phone && !alreadyDirect ? h2("button", { h2("tbody", null, actionableContacts.slice(0, 30).map((contact) => {
type: "button", const phone = contact.phone || "";
className: "dim-deliveryButton", const nickname = typeof contact.pushName === "string" && contact.pushName.trim() ? contact.pushName.trim() : "\u6682\u65E0\u6635\u79F0";
"data-kind": "primary", const alreadyDirect = Boolean(phone) && ((draft.directMembers ?? []).some((m) => m.phone === phone) || (draft.globalAdmins ?? []).includes(phone));
disabled: saving, const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)).filter((groupJid) => {
onClick: () => { if (!phone) return true;
setDraft((current) => { const group = draft.groups[groupJid] ?? { admins: [], members: [] };
if (current.directMembers.some((m) => m.phone === phone)) return current; return !(group.admins ?? []).includes(phone) && !(group.members ?? []).some((m) => m.phone === phone);
return { });
...current, return h2(
directMembers: [ "tr",
...current.directMembers, {
{ phone, canExecuteCommands: true } key: `${contact.phone ?? ""}-${(contact.lids ?? []).join(",")}`
] },
}; h2(
}); "td",
setFeedback({ tone: "success", message: "\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002" }); { className: "dim-accessTableNick" },
} h2("span", {
}, "\u52A0\u79C1\u804A") : null, className: nickname === "\u6682\u65E0\u6635\u79F0" ? "dim-accessNickname dim-accessNicknameEmpty" : "dim-accessNickname"
...groupTargets.map((groupJid) => { }, nickname)
const group = draft.groups[groupJid] ?? { admins: [], members: [] }; ),
const name2 = groupDisplayName(groupJid, draft.groups); h2(
return h2("button", { "td",
key: `add-${groupJid}`, { className: "dim-accessTablePhone" },
type: "button", phone || h2("span", { className: "dim-accessNicknameEmpty" }, "\u5F85\u8865\u7535\u8BDD")
className: "dim-deliveryButton", ),
disabled: saving || !phone, h2(
onClick: () => { "td",
setDraft((current) => { { className: "dim-accessTableSource" },
const existing = current.groups[groupJid] ?? { title: "", admins: [], members: [] }; (contact.scenes ?? []).join(" / ") || "\u2014"
if (existing.admins.includes(phone) || existing.members.some((m) => m.phone === phone)) { ),
return current; h2(
} "td",
return { { className: "dim-accessTableActions dim-accessContactActions" },
...current, phone && !alreadyDirect ? h2("button", {
groups: { type: "button",
...current.groups, className: "dim-deliveryButton",
[groupJid]: { "data-kind": "primary",
...existing, disabled: saving,
members: [ onClick: () => {
...existing.members, setDraft((current) => {
if (current.directMembers.some((m) => m.phone === phone)) return current;
return {
...current,
directMembers: [
...current.directMembers,
{ phone, canExecuteCommands: true } { phone, canExecuteCommands: true }
] ]
} };
});
setFeedback({ tone: "success", message: "\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002" });
}
}, "\u52A0\u79C1\u804A") : null,
...groupTargets.map((groupJid) => {
const name2 = groupDisplayName(groupJid, draft.groups);
return h2("button", {
key: `add-${groupJid}`,
type: "button",
className: "dim-deliveryButton",
disabled: saving || !phone,
onClick: () => {
setDraft((current) => {
const existing = current.groups[groupJid] ?? { title: "", admins: [], members: [] };
if (existing.admins.includes(phone) || existing.members.some((m) => m.phone === phone)) {
return current;
}
return {
...current,
groups: {
...current.groups,
[groupJid]: {
...existing,
members: [
...existing.members,
{ phone, canExecuteCommands: true }
]
}
}
};
});
setFeedback({
tone: "success",
message: ["\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A", name2, "\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002"].join("")
});
} }
}; }, ["\u52A0\u5165\u7FA4\uFF1A", name2].join(""));
}); })
setFeedback({ )
tone: "success", );
message: ["\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A", name2, "\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002"].join("") }))
}); )
} )
}, ["\u52A0\u5165\u7FA4\uFF1A", name2].join(""));
})
);
}))
), ),
h2( h2(
"fieldset", "fieldset",
@ -14764,6 +14799,13 @@ body[data-ds-dark-theme] .dim-page select option, body[data-ds-dark-theme] .dim-
.dim-accessTable[data-kind="member"] th:nth-child(2), .dim-accessTable[data-kind="member"] td:nth-child(2) { width: 36%; } .dim-accessTable[data-kind="member"] th:nth-child(2), .dim-accessTable[data-kind="member"] td:nth-child(2) { width: 36%; }
.dim-accessTable[data-kind="member"] th:nth-child(3), .dim-accessTable[data-kind="member"] td:nth-child(3) { width: 28%; } .dim-accessTable[data-kind="member"] th:nth-child(3), .dim-accessTable[data-kind="member"] td:nth-child(3) { width: 28%; }
.dim-accessTable[data-kind="member"] th:nth-child(4), .dim-accessTable[data-kind="member"] td:nth-child(4) { width: 16%; } .dim-accessTable[data-kind="member"] th:nth-child(4), .dim-accessTable[data-kind="member"] td:nth-child(4) { width: 16%; }
.dim-accessTable[data-kind="contact"] th:nth-child(1), .dim-accessTable[data-kind="contact"] td:nth-child(1) { width: 18%; }
.dim-accessTable[data-kind="contact"] th:nth-child(2), .dim-accessTable[data-kind="contact"] td:nth-child(2) { width: 26%; }
.dim-accessTable[data-kind="contact"] th:nth-child(3), .dim-accessTable[data-kind="contact"] td:nth-child(3) { width: 18%; }
.dim-accessTable[data-kind="contact"] th:nth-child(4), .dim-accessTable[data-kind="contact"] td:nth-child(4) { width: 38%; }
.dim-accessTableSource { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dim-accessContactActions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.dim-accessContactActions .dim-deliveryButton { min-height: 30px; padding-inline: 10px; }
.dim-accessTableNick { min-width: 0; } .dim-accessTableNick { min-width: 0; }
.dim-accessTableNick .dim-accessNickname { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .dim-accessTableNick .dim-accessNickname { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dim-accessTablePhone { min-width: 0; position: relative; z-index: 0; } .dim-accessTablePhone { min-width: 0; position: relative; z-index: 0; }

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{ {
"name": "dsh-im-ops", "name": "dsh-im-ops",
"version": "4.9.1-ops.15", "version": "4.9.1-ops.16",
"description": "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 — access/session policies owned here.", "description": "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 — access/session policies owned here.",
"keywords": [ "keywords": [
"deepseek-harness", "deepseek-harness",

View file

@ -679,90 +679,106 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved })
}, '添加群'))), }, '添加群'))),
h('fieldset', { className: 'dim-accessScene', disabled: saving }, h('fieldset', { className: 'dim-accessScene', disabled: saving },
h('legend', null, '最近联系人(自动沉淀)'), h('legend', null, '最近联系人(自动沉淀)'),
h('p', { className: 'dim-accessUsersEmpty' }, h('p', { className: 'dim-accessHint' },
'仅记录私聊机器人,或在群里 @ 机器人的人。已有对应权限的人会自动隐藏;电话是唯一授权键,可一键加入私聊/本群授权。'), '仅记录私聊机器人,或在群里 @ 机器人的人。已有对应权限的人会自动隐藏;电话是唯一授权键,可一键加入私聊/本群授权。'),
actionableContacts.length === 0 actionableContacts.length === 0
? h('div', { className: 'dim-accessUsersEmpty' }, ? h('div', { className: 'dim-accessUsersEmpty' },
contacts.length === 0 contacts.length === 0
? '暂无联系人。有人私聊或 @ 机器人后会出现在此。' ? '暂无联系人。有人私聊或 @ 机器人后会出现在此。'
: '当前联系人均已具备对应权限,无需再授权。') : '当前联系人均已具备对应权限,无需再授权。')
: h('ul', { className: 'dim-accessUserList' }, actionableContacts.slice(0, 30).map((contact) => { : h('div', { className: 'dim-accessTableWrap' },
const phone = contact.phone || ''; h('table', { className: 'dim-accessTable', 'data-kind': 'contact' },
const alreadyDirect = Boolean(phone) h('thead', null,
&& ((draft.directMembers ?? []).some((m) => m.phone === phone) h('tr', null,
|| (draft.globalAdmins ?? []).includes(phone)); h('th', { scope: 'col' }, '昵称'),
const groupTargets = (contact.groupJids ?? []) h('th', { scope: 'col' }, '电话'),
.filter((jid) => knownGroupJids.includes(jid)) h('th', { scope: 'col' }, '来源'),
.filter((groupJid) => { h('th', { scope: 'col', className: 'dim-accessTableActions' }, '操作'))),
if (!phone) return true; h('tbody', null, actionableContacts.slice(0, 30).map((contact) => {
const group = draft.groups[groupJid] ?? { admins: [], members: [] }; const phone = contact.phone || '';
return !(group.admins ?? []).includes(phone) const nickname = (typeof contact.pushName === 'string' && contact.pushName.trim())
&& !(group.members ?? []).some((m) => m.phone === phone); ? contact.pushName.trim()
}); : '暂无昵称';
return h('li', { const alreadyDirect = Boolean(phone)
key: `${contact.phone ?? ''}-${(contact.lids ?? []).join(',')}`, && ((draft.directMembers ?? []).some((m) => m.phone === phone)
className: 'dim-accessUserRow', || (draft.globalAdmins ?? []).includes(phone));
}, const groupTargets = (contact.groupJids ?? [])
h('div', { className: 'dim-accessField' }, .filter((jid) => knownGroupJids.includes(jid))
h('strong', null, contactLabel(contact)), .filter((groupJid) => {
h('span', null, (contact.scenes ?? []).join(' / ')), if (!phone) return true;
phone ? null : h('span', null, '待补电话')), const group = draft.groups[groupJid] ?? { admins: [], members: [] };
phone && !alreadyDirect ? h('button', { return !(group.admins ?? []).includes(phone)
type: 'button', && !(group.members ?? []).some((m) => m.phone === phone);
className: 'dim-deliveryButton',
'data-kind': 'primary',
disabled: saving,
onClick: () => {
setDraft((current) => {
if (current.directMembers.some((m) => m.phone === phone)) return current;
return {
...current,
directMembers: [
...current.directMembers,
{ phone, canExecuteCommands: true },
],
};
});
setFeedback({ tone: 'success', message: '已加入私聊授权,记得点保存。' });
},
}, '加私聊') : null,
...groupTargets.map((groupJid) => {
const group = draft.groups[groupJid] ?? { admins: [], members: [] };
const name = groupDisplayName(groupJid, draft.groups);
return h('button', {
key: `add-${groupJid}`,
type: 'button',
className: 'dim-deliveryButton',
disabled: saving || !phone,
onClick: () => {
setDraft((current) => {
const existing = current.groups[groupJid] ?? { title: '', admins: [], members: [] };
if (existing.admins.includes(phone)
|| existing.members.some((m) => m.phone === phone)) {
return current;
}
return {
...current,
groups: {
...current.groups,
[groupJid]: {
...existing,
members: [
...existing.members,
{ phone, canExecuteCommands: true },
],
},
},
};
});
setFeedback({
tone: 'success',
message: ['已加入群授权:', name, '。记得点保存。'].join(''),
}); });
return h('tr', {
key: `${contact.phone ?? ''}-${(contact.lids ?? []).join(',')}`,
}, },
}, ['加入群:', name].join('')); h('td', { className: 'dim-accessTableNick' },
})); h('span', {
}))), className: nickname === '暂无昵称'
? 'dim-accessNickname dim-accessNicknameEmpty'
: 'dim-accessNickname',
}, nickname)),
h('td', { className: 'dim-accessTablePhone' },
phone || h('span', { className: 'dim-accessNicknameEmpty' }, '待补电话')),
h('td', { className: 'dim-accessTableSource' },
(contact.scenes ?? []).join(' / ') || '—'),
h('td', { className: 'dim-accessTableActions dim-accessContactActions' },
phone && !alreadyDirect ? h('button', {
type: 'button',
className: 'dim-deliveryButton',
'data-kind': 'primary',
disabled: saving,
onClick: () => {
setDraft((current) => {
if (current.directMembers.some((m) => m.phone === phone)) return current;
return {
...current,
directMembers: [
...current.directMembers,
{ phone, canExecuteCommands: true },
],
};
});
setFeedback({ tone: 'success', message: '已加入私聊授权,记得点保存。' });
},
}, '加私聊') : null,
...groupTargets.map((groupJid) => {
const name = groupDisplayName(groupJid, draft.groups);
return h('button', {
key: `add-${groupJid}`,
type: 'button',
className: 'dim-deliveryButton',
disabled: saving || !phone,
onClick: () => {
setDraft((current) => {
const existing = current.groups[groupJid] ?? { title: '', admins: [], members: [] };
if (existing.admins.includes(phone)
|| existing.members.some((m) => m.phone === phone)) {
return current;
}
return {
...current,
groups: {
...current.groups,
[groupJid]: {
...existing,
members: [
...existing.members,
{ phone, canExecuteCommands: true },
],
},
},
};
});
setFeedback({
tone: 'success',
message: ['已加入群授权:', name, '。记得点保存。'].join(''),
});
},
}, ['加入群:', name].join(''));
})));
}))))),
h('fieldset', { className: 'dim-accessScene', disabled: saving }, h('fieldset', { className: 'dim-accessScene', disabled: saving },
h('legend', null, '群会话策略'), h('legend', null, '群会话策略'),
h('label', { className: 'dim-accessField' }, h('label', { className: 'dim-accessField' },

View file

@ -11,6 +11,8 @@ const EN = Object.freeze({
'机器人设置页签': 'Bot settings tabs', '机器人设置页签': 'Bot settings tabs',
'投递设置': 'Delivery settings', '投递设置': 'Delivery settings',
'访问设置': 'Access settings', '访问设置': 'Access settings',
"—": "—",
"来源": "Source",
"暂无管理员,可点下方新增。": "No admins yet. Add one below.", "暂无管理员,可点下方新增。": "No admins yet. Add one below.",
"暂无用户,可点下方新增。": "No users yet. Add one below.", "暂无用户,可点下方新增。": "No users yet. Add one below.",
"不可删除": "Locked", "不可删除": "Locked",

View file

@ -484,6 +484,13 @@ body[data-ds-dark-theme] .dim-page select option, body[data-ds-dark-theme] .dim-
.dim-accessTable[data-kind="member"] th:nth-child(2), .dim-accessTable[data-kind="member"] td:nth-child(2) { width: 36%; } .dim-accessTable[data-kind="member"] th:nth-child(2), .dim-accessTable[data-kind="member"] td:nth-child(2) { width: 36%; }
.dim-accessTable[data-kind="member"] th:nth-child(3), .dim-accessTable[data-kind="member"] td:nth-child(3) { width: 28%; } .dim-accessTable[data-kind="member"] th:nth-child(3), .dim-accessTable[data-kind="member"] td:nth-child(3) { width: 28%; }
.dim-accessTable[data-kind="member"] th:nth-child(4), .dim-accessTable[data-kind="member"] td:nth-child(4) { width: 16%; } .dim-accessTable[data-kind="member"] th:nth-child(4), .dim-accessTable[data-kind="member"] td:nth-child(4) { width: 16%; }
.dim-accessTable[data-kind="contact"] th:nth-child(1), .dim-accessTable[data-kind="contact"] td:nth-child(1) { width: 18%; }
.dim-accessTable[data-kind="contact"] th:nth-child(2), .dim-accessTable[data-kind="contact"] td:nth-child(2) { width: 26%; }
.dim-accessTable[data-kind="contact"] th:nth-child(3), .dim-accessTable[data-kind="contact"] td:nth-child(3) { width: 18%; }
.dim-accessTable[data-kind="contact"] th:nth-child(4), .dim-accessTable[data-kind="contact"] td:nth-child(4) { width: 38%; }
.dim-accessTableSource { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dim-accessContactActions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.dim-accessContactActions .dim-deliveryButton { min-height: 30px; padding-inline: 10px; }
.dim-accessTableNick { min-width: 0; } .dim-accessTableNick { min-width: 0; }
.dim-accessTableNick .dim-accessNickname { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .dim-accessTableNick .dim-accessNickname { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dim-accessTablePhone { min-width: 0; position: relative; z-index: 0; } .dim-accessTablePhone { min-width: 0; position: relative; z-index: 0; }