违心°

文章 评论 浏览 33

违心° 2025-02-20 18:53:20

增加 angular.json 的极限将停止警告,但对于生产构建,始终包括CSS文件的缩小版本,这将减少大小的大小。

increasing the limit in angular.json will stop the warning but for production builds always include the minified version of the CSS file which will reduce significant the size.

enter image description here

在角度项目原因中延长了一点点的引导程序“预算”超过CI/CD时间

违心° 2025-02-20 17:59:30

抱歉,我能够自己弄清楚这一点。最终是OKHTTP而不是Vespa的问题。

我正在使用响应。message,但是我需要实际使用响应。Body()。string()查看完整的错误输出。

为混乱表示歉意。

Sorry, I was able to figure this out on my own. It ended up being an issue with OkHttp rather than Vespa.

I was using Response.message, but I needed to actually use Response.body().string() to see the full error output.

Apologies for the confusion.

如何查看错误消息的详细信息“不良请求”用于查询API

违心° 2025-02-20 06:10:16

它是关于由值分组

分组的反转键值对

如果您想如注释中所说的那样倒置映射,则需要在源地图的条目上创建流,而不是在值:

Map<Integer, List<Integer>> personByAge = m.entrySet()
    .stream()
    .collect(Collectors.groupingBy(
        Map.Entry::getValue,
        Collectors.mapping(Map.Entry::getKey,
            Collectors.toList())));
        
personByAge.forEach((k, v) -> System.out.println(k + " -> " + v));

output 上创建流。 :

1 -> [1, 2, 3]
2 -> [4, 5, 6, 7]

it is about the inverting key values pair grouped by values

If you want to invert the Map as you've said in the comments, you need to create a stream over the entries of the source map, not over the values:

Map<Integer, List<Integer>> personByAge = m.entrySet()
    .stream()
    .collect(Collectors.groupingBy(
        Map.Entry::getValue,
        Collectors.mapping(Map.Entry::getKey,
            Collectors.toList())));
        
personByAge.forEach((k, v) -> System.out.println(k + " -> " + v));

Output:

1 -> [1, 2, 3]
2 -> [4, 5, 6, 7]

反转地图&lt; integer,Integer&gt;进入地图&lt;键,列表&lt; integer&gt;&gt;使用流

违心° 2025-02-19 12:54:12

只需使用以下方式:

this.Invoke((MethodInvoker)delegate
            {
                YourControl.Property= value; // runs thread safe
            });

Simply use this:

this.Invoke((MethodInvoker)delegate
            {
                YourControl.Property= value; // runs thread safe
            });

跨线程操作无效:从其在其上创建的线程以外的线程访问的控件

违心° 2025-02-19 03:17:54

不按下来并更改您的pubspect.yaml文件中的资产部分可以修复它。

  assets:
    - images/

Uncomment and change the asset section in your pubspect.yaml file can fix it.

  assets:
    - images/

在颤音中加载图像|内容root的路径不起作用,但绝对路径起作用

违心° 2025-02-19 02:35:29

我猜第一种形式更好,更直观地知道做什么。

帖子 - 客户/地址 - token-这为用户创建地址

I guess the first form is better and more intuitive to know what are do.

POST - customer/address-token - this creates a address for a user

使用动词或名词的休息端点

违心° 2025-02-18 23:22:45

您是说您想从JWT阅读索赔,并以下面的方式了解cookie身份验证的新票:

var jwtsecuritytoken = new JwtSecurityTokenHandler().ReadToken(token) as JwtSecurityToken;
                    var username = jwtsecuritytoken.Claims.FirstOrDefault(m => m.Type == ClaimTypes.Name).Value;
                     .......
                     //add other logic
                    .........
                        var claims = new Claim[]
                        {
                        new Claim(ClaimTypes.Name, username),
                         ..........
                         };
                        var claimsIdentity = new ClaimsIdentity(claims);
                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
                    }

Do you mean you want read claims from jwt and ceate a new ticket for cookie authentication as below:

var jwtsecuritytoken = new JwtSecurityTokenHandler().ReadToken(token) as JwtSecurityToken;
                    var username = jwtsecuritytoken.Claims.FirstOrDefault(m => m.Type == ClaimTypes.Name).Value;
                     .......
                     //add other logic
                    .........
                        var claims = new Claim[]
                        {
                        new Claim(ClaimTypes.Name, username),
                         ..........
                         };
                        var claimsIdentity = new ClaimsIdentity(claims);
                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
                    }

ASP.NET核心签名与JWT

违心° 2025-02-18 23:21:02

考虑使用基准测试工具(例如LDBC(链接数据基准委员会))进行图形数据库引擎的标准化性能评估。 LDBC基准提供了现实的工作负载和查询,与手动设置相比节省了时间。

Consider using benchmarking tools like LDBC (Linked Data Benchmark Council) for standardized performance evaluation of graph database engines. LDBC benchmarks provide realistic workloads and queries, saving time compared to manual setup.

分布式图DB:性能度量

违心° 2025-02-18 22:18:41

日期功能在系统设置上很大程度上依赖于您的本地日期和时间。如果您在美国碰巧是一个月/日/年。

您只需要解构它即可获得所需的东西。以下代码将按照您要寻找的顺序获取(并说明一个月为0索引):

const time = new Date()

const time2 = '' + time.getFullYear() + (time.getMonth() + 1) + time.getDate().toString().padStart(2,'0')

https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/global_objects/date

The date functions rely a lot on system settings to get your local date and time. If you're in the U.S. that happens to be month/day/year.

You simply need to deconstruct it to get what you're looking for. The below code will get it in the order you're looking for (and account for the month being 0-indexed):

const time = new Date()

const time2 = '' + time.getFullYear() + (time.getMonth() + 1) + time.getDate().toString().padStart(2,'0')

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

如何在node.js中获取本地时间日期?

违心° 2025-02-18 21:10:24

尝试从功能调用中删除 inplace = true 。根据fileInput 文档

“如果关键字参数inplace = true将传递给fileInput.input()
或到文件输入构造函数,将文件移至备份文件
和标准输出针对输入文件(如果是
与备份文件已经存在的名称相同,将被替换
默默)。这使得编写一个重写其过滤器
输入文件到位“

因此打印将不起作用,因为所有内容都被管道输入到您的输入文件。

此外,根据您的用例,FileInput可能不是最合适的模块。同样,请参考FileInput文档:

此模块实现了一个助手类,并函数快速编写一个
循环在标准输入或文件列表上。如果您只想阅读
或写一个文件,请参见Open()。

Try to remove the inplace=True from your function call. According to the fileinput documentation

"if the keyword argument inplace=True is passed to fileinput.input()
or to the FileInput constructor, the file is moved to a backup file
and standard output is directed to the input file (if a file of the
same name as the backup file already exists, it will be replaced
silently). This makes it possible to write a filter that rewrites its
input file in place"

So printing will not work, as everything is being piped to your input file.

Also depending on your use case, fileinput may not be the most appropriate module to use. Again, referring to the fileinput documentation:

This module implements a helper class and functions to quickly write a
loop over standard input or a list of files. If you just want to read
or write one file see open().

Python:从文本文件中删除数字和小数

违心° 2025-02-18 19:02:46

出现错误是因为我在Cupy之前进口了Pytorch。

解决方案是在火炬之前进口杯子。

The error was showing up because I was importing PyTorch before CuPy.

Solution was to import cupy before torch.

jupyter笔记本:导入错误:dll负载失败(但在.py上起作用)没有anaconda

违心° 2025-02-18 01:55:46

我必须自己处理这个问题。我目前可以使用视图来解决它,但宁愿将来选择RLS策略,触发器或特权功能(截至目前未经测试)。我在下面分享了我研究的注释。


列级安全性(“ CLS”)是指根据某些条件选择性地禁止列值更新,插入甚至选择。有几种替代解决方案(摘要),每种都有优势和缺点。下面对它们进行了详细讨论。

选项1:RLS策略

(到目前为止我最喜欢的选项,但我尚未在实践中使用它

。 RLS)策略检索旧行,并比较您受保护的列的字段值是否会从旧行变为新行。解决方案的候选者已发布为堆栈溢出答案,但这仍然必须使其成为通用功能。

乍一看,这似乎比触发因素更好:它具有其优势,此外,Supabase无论如何都会促进使用RLS策略来访问控制,并且对RLS的UI支持要比对触发器的支持更好。因此,它将通过降低复杂性来提高数据库的一致性和可维护性。

但是,supabase RLS编辑器不能用于复杂的RLS策略(“ noreferrer”>问题报告由于解决方法,应将所有RLS代码包装到一个或嵌套的函数调用中,或者至少不超过一行代码。更好的是,在Supabase之外的版本控制下,将SQL源代码维护,并在要更改RLS策略,表格,功能等时,将其复制到Supabase SQL编辑器中。

选项2:触发器

请参见在这里,我的原始说明 a href =“ https://github.com/orgs/supabase/discussions/656#discussioncomment-5594653” rel =“ noreferrer”>改进的说明 github用户Christophemarois。

优点:

  • 不添加另一个表或视图,因此数据库结构由数据确定,而不是通过许可系统怪癖来确定。

  • 不需要更改默认的supabase权限或表格到示意分配。

  • 结合了RLS策略和列级权限的功能。

缺点:

  • 触发器在supabase UI中尚未得到很好的支持:只能更改触发器状态,但只能在UI中显示或编辑,只能在postgresql控制台中显示或编辑。实际上,这并不是什么问题,因为无论如何,您都必须直接与PostgreSQL数据库一起工作。

  • 它需要了解PGSQL或其他编程语言……对于某些人来说,编程是我们想要使用Supabase避免的。但是,该解决方案使用一个接收到白名单列的抽象函数(“允许更改”),因此无需进行实际编程,只需部署一些可重复使用的代码即可。

选项3:特权功能

“您可以用安全定义器隐藏函数后面的表。该表本身将无法提供更新访问权限,而是用户只能通过函数更新表。” ( source

,在该功能中,您可以按照自己喜欢的任何方式确定列级访问权限。模式中的任何此类功能 public 将通过API自动获得:

“写postgresql sql functions […],并通过 supabase.rpc('function_name',{param1:'value'}); 呼叫。 ( source )。

但是,问题在于,API不再具有“所有内容都在表中可用”的统一结构。

选项4:特定于用户的视图

请参阅指令。更多说明:

“您可以创建一个视图以仅显示所需的列,请确保使用语句忽略语句,因为它忽略了RLS(通常是),然后使用RLS阻止原始表。 “ ( source> source

/Github.com/supabase/supabase/discussions/8663#discussioncomment-3484271“ rel =“ noreferrer”>由supabase维护者推荐。总的来说,RLS政策和触发器似乎是可取的。

要使此解决方案安全,您必须使用选项 security_barrier = on 详细信息),这会严重影响视图性能。解决的唯一方法是不使用 where 子句,而是通过 security_invoker = on 重新使用基础表的RLS策略。这需要将基础表移至API不暴露的自定义数据库方案(见下文)。

优点:

  • 简单。视图就像桌子一样,每个人都知道PostgreSQL表 - 与触发器或(复杂的)RLS策略相比。

  • 您会看到您编辑的内容。用户(或他们的应用程序)可以在表中看到记录,不必担心由于RLS策略是否可以编辑。无论用户可以看到什么,他们都可以编辑。

  • ❓可根据需要扩展。 (仍然不确定。) 仅在视图中提供某个某些用户的编辑列。要找到正确的列,有时需要更多上下文。没问题:在API访问时间时,请再次根据需要加入底层基础表的视图和列。只有替代主键列 id 才需要始终包含在视图中。这不是一个问题:如果用户试图编辑它,则只有在使用新值时才能成功,在这种情况下,有效地创建了新的记录,无论如何都可能允许用户执行此操作。 (待确认,仍然可以使用适当的访问保护更新。)

(可以确认,

  • API将以适当的数据库设计中的形式公开数据。通过暴露其他视图,API变得不必要地复杂。

  • 无法真正重复使用底层表的RLS策略。在创建视图时使用 security_invoker = on 在创建视图时(详细信息)。但是,在执行此操作时,可以通过视图更新记录的相同用户也可以在基础表中更新该记录,从而规避使用该视图的列访问限制。唯一的方法是将基础表移至API未暴露的自定义数据库方案。这是可能的,但增加了结构上的复杂性。

  • 需要更改默认视图权限。由于这些简单视图,因此它们在PostgreSQL中是“可更新”视图。加上supabase schema public中默认的表级 /视图级权限,这意味着所有用户,甚至匿名的用户都可以从这些视图中删除记录,从而导致填充表中的记录删除。< / p>。< / p>

    要解决此问题,必须从视图中删除插入物并删除特权。这是对默认的supabase权限的更改,理想情况下是不需要的。

    有一个替代解决方案,但这不是很实际:您可以使用 security_invoker = on 创建视图来重复使用底层表的RLS策略。然后使用这些RLS策略来防止记录删除。但是,他们必须允许选择和更新;因此,除非将底层表移至API未曝光的模式,否则它将允许用户规避创建视图的列级安全性。

  • 没有限制某些 的好方法。这是因为视图不能具有自己的RLS政策。有几种解决此问题的方法:

    • 可能最佳的工作方式是构建表,以便允许对列的写入访问权限的用户使用该列中的每个值。例如,代替列角色(用户,admin)和状态(应用,批准,不赞成),将有可无效的布尔列 user_application admin_application user_status admin_status

    • 对于复杂情况,另一个选项是将基础表移至不访问API的自定义模式(同时仍授予所有Supabase角色的使用和权限;

    • 对于复杂情况,另一个选项是在视图或底层表上使用触发器。



选项5:列级访问权限

“您只能提供对表的列的一个子集:Grant Update(COL1,COL2)。 >)“( source

据报道,维护所有这些访问权利是一种麻烦。在supabase中,不可能向不同的身份验证的用户提供不同的权限,因为所有这些用户都使用相同的角色 autheratiencatienated 访问数据库。但是,在最高级别上工作时,您可以在这里有不同的选择。

选项6:与视图相比,表分裂

,这将主表分为多个部分。使用RLS策略,定义了谁可以用每个部分表来做什么;而且,与您只能在某个子句中部分模拟RLS策略的视图不同,RLS策略也可以用于限制用户可以用于列的值。要将它们一起使用,必须将它们加入请求。

将桌子分成两个时还可以。但是有时分裂几乎是“每列的一个表”,例如,对于每列角色一个列的许可管理表。这很糟糕,因为它“原子化”了数据,而不是以适当的正常形式保持数据,这意味着数据甚至无法以舒适的方式访问。可以通过将分开表再次组合并提供对这些底层表的写入访问的视图来解决。但是,还有很多表格。这是“丑陋的”。

I had to deal with this issue myself. I currently solve it with views, but would rather choose RLS policies, triggers or privileged functions in the future (untested, as of right now). I share the notes from my research into this issue below.


Column-level security ("CLS") means to selectively prohibit column value UPDATEs, INSERTs or even SELECTs based on certain conditions. There are several alternative solutions for this (summary), each with advantages and disadvantages. They are discussed in detail below.

Option 1: RLS policies

(My favourite option so far, but I have not yet used it in practice.)

Here, for a CLS policy to protect against UPDATEs, you would use a row-level security (RLS) policy that retrieves the old row and compares if your protected column's field value would change from the old to the new row. A solution candidate for this has been posted as a Stack Overflow answer, but this still has to be made into a generic function.

At first glance, this seems better than a trigger: it shares its advantages and in addition, Supabase promotes the use of RLS policies for access control anyway, and has much better UI support for RLS than for triggers. So it would improve consistency and maintainability of the database by reducing complexity.

However, the Supabase RLS editor cannot be used for complex RLS policies (issue report), so as a workaround one should wrap all RLS code into a single or nested function call, or at least something no longer than one line of code. Even better is to maintain the SQL source code under version control outside of Supabase, and to copy-and-paste it into the Supabase SQL Editor whenever you want to change a RLS policy, table, function and so on.

Option 2: Triggers

See here for my original instructions, and then the improved instructions by Github user christophemarois.

Advantages:

  • Does not add another table or view, so that the database structure is determined by the data, as it should be, and not by permission system quirks.

  • Does not require changes to the default Supabase permissions or table-to-schema assignments.

  • Combined the powers of RLS policies and column-level permissions.

Disadvantages:

  • Triggers are not yet supported well in the Supabase UI: only the trigger status can be changed, but it cannot be shown or edited in the UI, only in the PostgreSQL console. In practice, this is not much of an issue, as for any real-life project you will have to work with the PostgreSQL database directly, anyway.

  • It requires knowledge of PGSQL or another programming language … and for some, programming is what we want to avoid with Supabase. However, the solution uses one abstract function that receives columns to whitelist ("changes allowed"), so no real programming is necessary, just deploying some re-usable code.

Option 3: Privileged Functions

"You can hide the table behind a FUNCTION with SECURITY DEFINER. The table itself would not provide UPDATE access, instead users can only update the table through the FUNCTION." (source)

And in that function, you can determine column-level access permissions in any way you like. Any such function in schema public is automatically available through the API:

"write PostgreSQL SQL functions […] and call them via supabase.rpc('function_name', {param1: 'value'});." (source).

The issue is, however, that the API then no longer has a unified structure of "everything is available in tables".

Option 4: User-specific views

See the instructions. More instructions:

"You can create a view to only show the columns you want, make sure you secure with a WHERE statement as it ignores RLS (normally), and then use RLS to block the original table." (source)

This solution has been recommended by a Supabase maintainer. In total, RLS policies and triggers seem preferable, though.

To make this solution secure, you have to use option security_barrier = on (details), which can severely impact view performance. The only way around that is to not use a WHERE clause and instead to re-use RLS policies of the base table via security_invoker = on. That requires moving the base table to a custom database scheme that is not exposed by API (see below).

Advantages:

  • Simple. Views are just like tables, and everyone knows PostgreSQL tables – in contrast to triggers or (complex) RLS policies.

  • You see what you edit. Users (or their applications) who can see records in the table do not have to worry if they are editable due to RLS policies. Whatever a user can see, they can edit.

  • ❓ Extendable as needed. (Still unsure about this.) Only the columns a certain user is allowed to edit can be provided in the view. To find the right column, sometimes more context is needed. Not a problem: join the view and columns from the underlaying base table again as needed, at API access time. Only the surrogate primary key column id needs to be always included into the view; this is not an issue: if a user tries to edit it, it can only succeed when using new values, in which case effectively a new record is created, which the user is probably allowed to do anyway. (To be confirmed that updates with proper access protection are then still possible.)

Disadvantages:

  • Cluttering the table space. Ideally, the API would expose the data in the form they have in a proper database design. By exposing additional views, the API becomes unnecessarily complex.

  • Can not really reuse RLS policies of underlaying table. To be done by using security_invoker = on when creating the view (details). However, when doing this, the same user that can, say, update a record through the view can then also update that record in the base table, circumventing the column access restrictions for which the view is used. The only way around that would be to move the base table to a custom database scheme that is not exposed by API. That is possible, but adds yet more structural complexity.

  • Needs changes to the default view permissions. Since these are simple views, they are "updateable" views in PostgreSQL. Together with the default table-level / view-level permissions in Supabase schema public this means that all users, even anonymous ones, can delete records from these views, leading to the deletion of records in the underlaying tables.

    To fix this, one has to remove the INSERT and DELETE privileges from the view. This is a change to the default Supabase permissions that would ideally not be necessary.

    There is an alternative solution, but it is not very practical: you can create the views with security_invoker = on to reuse the RLS policies of the underlaying table. Then use these RLS policies to prevent record deletion. However, they have to allow SELECT and UPDATE; so unless you move the underlaying table to a schema not exposed by API, it would allow users to circumvent the column-level security for which the views were created.

  • No good way to restrict the use of certain values in a column to certain users. This is because views cannot have their own RLS policies. There are several ways to work around this:

    • Probably the best way to work around that is to structure tables so that a user with write access to a column is allowed to use every value in that column. For example, instead of columns role (user, admin) and status (applied, approved, disapproved), there would be nullable boolean columns user_application, admin_application, user_status, admin_status.

    • Another option, for complex cases, is to move the underlying table to a custom schema that is not API accessible (while still granting USAGE and permissions to all Supabase roles; see), to create RLS policies on that underlying table, and to re-use them in the views via security_invoker = on.

    • Another option, also for complex cases, is to use triggers on the view or the underlaying table.

Option 5: Column-level access rights

"You can provide UPDATE access to only a subset of columns of the table: GRANT UPDATE(col1, col2). (details)" (source)

Reportedly, it is a hassle to maintain all these access rights. And in Supabase, it would not be possible to give different permissions to different authenticated users, as all of them access the database using the same role authenticated. When working on the PostgREST level, you could have different options here, though.

Option 6: Table Splitting

Compared to views, this splits the main table into multiple parts. Using RLS policies, it is defined who can do what with each partial table; and, different from views where you can only partially emulate RLS policies in a WHERE clause, a RLS policy can also be used to limit which values a user can use for a column. To use them together, they have to be joined in requests.

Quite ok when splitting a table in two. But sometimes the splitting is almost "one table per column", for example for permission management tables with one column per role. This is bad because it "atomizes" the data rather than keeping it in a proper normal form, meaning that the data is not even accessible to admins in a comfortable way. That can be solved with views that combine the split-off tables again and provide write access to these underlaying tables. But still, a lot of tables to deal with. It's "ugly".

supabase:用于列级安全的解决方案

违心° 2025-02-17 07:58:36

我可以为您提供我使用的假设解决方案,但您必须自己实施其余的解决方案。

在我的模板中,我有一个下拉列表,我的工作是添加了一个on Change操作。这将我从下拉列表中选择的任何内容添加到隐藏的输入字段。添加完成后,我将在文本字段中发送数据。

    <select class="exempt" onchange="addProgrammingLanguages(this, 'dropId', 'langtxt');">
      <option value="Select">Select languages *</option>
      <option value="Java">Java</option>
      <option value="Javascript">Javascript</option>
      <option value="Python">Python</option>
      <option value="C">C</option>
      <option value="C#">C#</option>
    </select>
    <div class="exempt" id="dropId" style="max-width:80%; border:none; height:auto; display:flex; flex-direction:row; gap:5px; flex-wrap:wrap;">

    </div>
    <input id="langtxt" type="hidden" th:field="*{language}">
function addProgrammingLanguages(menu, ident, txtfield)
{
    var selected = menu.value;

    button.onclick = function() {
        removeMenu(this.id, ident);
        document.getElementById(txtfield).value = document.getElementById(txtfield).value.replace(this.id.split("_")[0]+"_",'');
     };


    document.getElementById(txtfield).value += selected+'_';
    menu.selectedIndex=0;
}

在我的代码中,我向所有输入添加了一个_在我的Java中,我将使用string.split()方法分析。您不必添加一个_,但是就我而言,我有一个单一字符的选择,如果您添加特殊字符,我也可以更轻松地拆分。

希望这会有所帮助。

I can give you a hypothetical solution that im using but you will have to implement the rest yourself.

In my templating, I have a dropdown and what I did is added an onchange action. This adds whatever I selected from the dropdown to a hidden input field. Once i'm done adding, I send the data in the text field.

    <select class="exempt" onchange="addProgrammingLanguages(this, 'dropId', 'langtxt');">
      <option value="Select">Select languages *</option>
      <option value="Java">Java</option>
      <option value="Javascript">Javascript</option>
      <option value="Python">Python</option>
      <option value="C">C</option>
      <option value="C#">C#</option>
    </select>
    <div class="exempt" id="dropId" style="max-width:80%; border:none; height:auto; display:flex; flex-direction:row; gap:5px; flex-wrap:wrap;">

    </div>
    <input id="langtxt" type="hidden" th:field="*{language}">
function addProgrammingLanguages(menu, ident, txtfield)
{
    var selected = menu.value;

    button.onclick = function() {
        removeMenu(this.id, ident);
        document.getElementById(txtfield).value = document.getElementById(txtfield).value.replace(this.id.split("_")[0]+"_",'');
     };


    document.getElementById(txtfield).value += selected+'_';
    menu.selectedIndex=0;
}

In my code i added a _ to all the inputs to in my java I would parse with string.split() method. You dont have to add a _ but in my case I had options that were singular characters and also I makes it easier to split if you add a special character.

Hope this helps.

如何通过多个下拉列表&#x27;价值回到控制器?

违心° 2025-02-17 04:04:10

文档摘录:

官方文档 )返回

二维值

始终返回a 两个尺寸值阵列

一维数组是

[1,2,3]

二维数组的数组中

[[1,2,3]]
//or
[[1], [2], [3]]

有/是数组中的数组。

由行索引,然后是列。

首先,它由行索引:IE,外部阵列的行作为内数阵列。然后每个内部阵列都有列元素。考虑以下简单电子表格:

A B C
1&GT; 1 2 3
2&gt; 2 3 4
3&gt; 3 4 5

a1:a3 包含3行,每行包含1列元素。这表示为 [[1],[2],[3]] 。同样,以下范围代表以下数组。尝试根据a1表示法猜测数组结构:

a1
列表
编号
列的行
array数组
结构
阵列数组
.length
Array [0]
.length
A1 :a3 3 1 [[1],[2],[3],[3] 3 1
a1:c1 1 3 [[1,2,3]] 1 3
A1 :b2 2 2 [[1,2],[2,3]] 2 2
b1:c3 3 2 [[2,3],[3,4],[4,[4,[4,] 5]] 3 2
a2:c3 2 3 [[2,3,4],[3,4,5]] 2 3 3

请注意二维如何提供方向。
请参阅下面的实时可视化:

/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
const test = {
  'A1:A3': [[1], [2], [3]],
  'A1:C1': [[1, 2, 3]],
  'A1:B2': [
    [1, 2],
    [2, 3],
  ],
  'B1:C3': [
    [2, 3],
    [3, 4],
    [4, 5],
  ],
  'A2:C3': [
    [2, 3, 4],
    [3, 4, 5],
  ],
};

Object.entries(test).forEach(([key, value]) => {
  console.log(`The range is ${key}`);
  console.table(value);
  console.info(`The above table's JavaScript array notation is ${JSON.stringify(value)}`)
  console.log(`=================================`);
});
<!-- https://meta.stackoverflow.com/a/375985/ -->    <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

根据单元格的值。

在上面的示例中,我们具有转换为JavaScript号码类型的电子表格编号类型元素。您可以使用 type(type() )。对应的JavaScript类型参考是在这里

空单元用数组中的一个空字符串表示。

检查使用

console.log(values[0][0]==="")//logs true if A1 is empty    

请记住,范围索引从1、1开始,而JavaScript数组则从[0] [0]。

索引。

给定二维数组结构,要访问一个值,需要两个格式 array [row] [column] 的索引。在上表中,如果检索 a2:c3 ,则访问 c3 ,请使用 values [1] [2] [1] 是范围A2:C3的第二行。请注意,范围本身从第二行开始。因此,在中,第二行给定范围是行 3 [2] 是第三列 c

注意:

  • 警告:

从一个范围内检索的值始终二维,无论范围高或宽度如何(即使仅1)。 getRange(“ a1”)。getValues()将表示 [[1]

  • setValues()将接受与对应于该阵列相对应的相同数组结构范围设置。如果尝试使用一维数组,则错误

参数(number []/string [])不匹配电子表格Appapp.range.setValues的方法签名。

被扔了。

  • 如果数组不完全对应于所设置的范围,即,如果内部数组的长度中的每个阵列都不对应于范围内的列数或外部阵列的长度与该范围内的行数不符被设置为类似以下错误的错误:

数据中的列数与范围内的列数不匹配。数据有5个,但范围为6。

参考:

Documentation excerpts:

From The official documentation, getValues() returns

a two-dimensional array of values,

It ALWAYS returns a two dimensional array of values.

One dimensional array is

[1,2,3]

Two dimensional array is

[[1,2,3]]
//or
[[1], [2], [3]]

There is/are array(s) inside a array.

indexed by row, then by column.

It is indexed by row first: i.e., The outer array has rows as inner array. Then each inner array has column elements. Consider the following simple spreadsheet:

A B C
1> 1 2 3
2> 2 3 4
3> 3 4 5

A1:A3 contains 3 rows and each row contains 1 column element. This is represented as [[1],[2],[3]]. Similarly, The following ranges represent the following arrays. Try to guess the array structure based on the A1 notation:

A1
Notation
Number
of Rows
Number
of columns
Array
Structure
array
.length
array[0]
.length
A1:A3 3 1 [[1],[2],[3]] 3 1
A1:C1 1 3 [[1,2,3]] 1 3
A1:B2 2 2 [[1,2],[2,3]] 2 2
B1:C3 3 2 [[2,3],[3,4],[4,5]] 3 2
A2:C3 2 3 [[2,3,4],[3,4,5]] 2 3

Note how the two dimension provides direction.
See live visualization below:

/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
const test = {
  'A1:A3': [[1], [2], [3]],
  'A1:C1': [[1, 2, 3]],
  'A1:B2': [
    [1, 2],
    [2, 3],
  ],
  'B1:C3': [
    [2, 3],
    [3, 4],
    [4, 5],
  ],
  'A2:C3': [
    [2, 3, 4],
    [3, 4, 5],
  ],
};

Object.entries(test).forEach(([key, value]) => {
  console.log(`The range is ${key}`);
  console.table(value);
  console.info(`The above table's JavaScript array notation is ${JSON.stringify(value)}`)
  console.log(`=================================`);
});
<!-- https://meta.stackoverflow.com/a/375985/ -->    <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

The values may be of type Number, Boolean, Date, or String, depending on the value of the cell.

In the above example, We have Spreadsheet Number type elements converted to JavaScript number type. You can check spreadsheet type using =TYPE(). Corresponding JavaScript type reference is here

Empty cells are represented by an empty string in the array.

Check using

console.log(values[0][0]==="")//logs true if A1 is empty    

Remember that while a range index starts at 1, 1, the JavaScript array is indexed from [0][0].

Given the two dimensional array structure, to access a value, two indexes of format array[row][column] is needed. In the above table, if A2:C3 is retrieved, To access C3, Use values[1][2]. [1] is second row in range A2:C3. Note that the range itself starts on second row. So, second row in the given range is row3 [2]is third column C.

Notes:

  • Warning:

Retrieved values from a range is always two dimensional regardless of the range height or width(even if it is just 1). getRange("A1").getValues() will represent [[1]]

  • setValues() will accept the same array structure corresponding to the range to set. If a 1D array is attempted, the error

The parameters (number[]/string[]) don't match the method signature for SpreadsheetApp.Range.setValues.

is thrown.

  • If the array does NOT exactly correspond to the range being set,i.e.,if each of the the inner array's length does not correspond to the number of columns in the range or the outer array's length does not correspond to the number of rows in the range being set, The error similar to the following is thrown:

The number of columns in the data does not match the number of columns in the range. The data has 5 but the range has 6.

  • Related answers to the above error:

  • indexOf/includes uses strict type checking. They won't work when you compare primitives against array objects. You can use Array.flat to flatten the 2D array to a 1D one. Alternatively, Use a plain old for-loop to check something.

    const values = [[1,2,3]].flat();//flattened
    console.log(values.indexOf(2));//expected 1
    console.log(values.includes(1));//expected true

References:

范围方法getValues()返回和setValues()接受什么?

违心° 2025-02-16 18:15:30

通过共享网络驱动器加载加载项,但是根据Microsoft文档,这不是生产部署的选项。

如果没有生产选项,所有其他可能的方法都很好。

我的问题是,如果可以通过VSTO包装器以某种方式传递基于Web的加载项?

要交付清单还不够,因此您需要通过将清单文件添加到Office应用程序中来进行加载项。将URL提供给网络共享的URL是否更好地占有用户?在这种情况下,VSTO是毫无用处的。 Officejs (不是Excel)不提供任何以编程加载Web加载的API。

另外,可以以某种方式为每个用户提供本地驱动器上的清单?

无需将清单保留在本地驱动器上。如果没有集中式部署(通过Office365 Admin Center),则可以提供清单的URL来侧载加载项。

部署和发布添加办公室添加办公室添加办公室添加-ins 文章。

Loading the add-in via a shared network drive works, but according to the microsoft docs this is not an option for a production deployment.

When production options are not available, all other possible ways are good.

my question is, if it's somehow possible to deliver the web-based add-in via a VSTO wrapper?

To deliver the manifest is not enough, so you need to sideload the add-in by adding the manifest file to the Office application. Isn't better to provide URL to the network share where manifest resides to users? VSTO is useless in that scenario. OfficeJS (not Excel) doesn't provide any API for loading web add-ins programmatically.

Would it alternatively be possible to provide the manifest on the the local drive for each user somehow?

There is no need to keep the manifest on the local drive. You can provide URL of the manifest to sideload the add-in if the centralized deployment is not available (via the Office365 admin center).

Read more about possible routes in the Deploy and publish Office Add-ins article.

交付包裹在VSTO ADDIN中的Officejs Web addin

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文