Enhance vendor management with extended data fields

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-04-10 17:19:35 -07:00
parent 25ca9e5d3b
commit 9fa33726e7
21 changed files with 2013 additions and 288 deletions

View File

@@ -4,10 +4,24 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
### Added
- Added vendors.json data file under Creative Commons Attribution-ShareAlike 4.0 license`
- New vendor data management system with comprehensive vendor information
- Pre-populated vendor database with 12 common SaaS vendors and their certifications
- Vendor details page with extended fields for improved vendor management:
- Legal name and headquarters address
- Website URL
- Certification tracking with tag-based interface
- Links to important vendor documents (SLA, DPA, security pages)
- Support for multiple compliance certifications per vendor
### Fixed
- Fix cannot create vendor when the name is too similar to suggested one
- Fix UI show double button to close evidence preview modal.
- Fix UI showing double button to close evidence preview modal
- Fix cannot delete vendor with compliance reports (added cascade delete constraint)
## [0.5.0] - 2025-04-10

173
LICENSE
View File

@@ -1,21 +1,160 @@
Copyright 2025 Probo Inc
Creative Commons Attribution-ShareAlike 4.0 International Public License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
“Software”), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Section 1 Definitions.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights under this Public License.
k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
A. reproduce and Share the Licensed Material, in whole or in part; and
B. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
3. Term. The term of this Public License is specified in Section 6(a).
4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
5. Downstream recipients.
A. Offer from the Licensor Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
B. Additional offer from the Licensor Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter's License You apply.
C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this Public License.
3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.
Section 3 License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified form), You must:
A. retain the following if it is supplied by the Licensor with the Licensed Material:
i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of warranties;
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply.
Section 4 Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;
b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 Disclaimer of Warranties and Limitation of Liability.
a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
Section 6 Term and Termination.
a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 Interpretation.
a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the "Licensor." The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
Creative Commons may be contacted at creativecommons.org.

View File

@@ -0,0 +1,24 @@
# Vendors Data
The `[vendors.json](vendors.json)` file contains data about various vendors and their security certifications. This data is licensed under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.
## License Requirements
When using this data, you must:
1. **Give appropriate credit** - Provide attribution to Probo Inc. and include a link to this license
2. **Indicate if changes were made** - If you modify the data, you must indicate that changes were made
3. **Share under the same license** - If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original
## Attribution Example
When using this data, please include the following attribution:
```
Data sourced from Probo Inc. (https://getprobo.com) under CC BY-SA 4.0 license
```
## More Information
For more information about the CC BY-SA 4.0 license, please visit:
https://creativecommons.org/licenses/by-sa/4.0/

View File

@@ -0,0 +1,309 @@
[
{
"name": "Slack",
"headquarterAddress": "San Francisco, 50 Fremont Street, United States",
"legalName": "Slack Technologies, Inc.",
"websiteUrl": "https://slack.com",
"privacyPolicyUrl": "https://slack.com/intl/en-gb/trust/privacy/privacy-policy",
"serviceLevelAgreementUrl": "https://slack.com/intl/en-gb/terms/service-level-agreement",
"description": "Slack is a team communication platform that allows users to send messages, files, and images to each other.",
"statusPageUrl": "https://slack-status.com/",
"termsOfServiceUrl": "https://slack.com/intl/en-gb/main-services-agreement",
"category": "Communication",
"certifications": [
"ISO/IEC 27001:2022",
"ISO/IEC 27017:2015",
"ISO/IEC 27018:2019",
"SOC2 Type 2",
"C5",
"GDPR"
],
"securityPageUrl": "https://slack.com/intl/en-gb/trust/security"
},
{
"name": "Zoom",
"headquarterAddress": "950 Page Mill Rd, Palo Alto, CA 94306",
"legalName": "Zoom Video Communications, Inc.",
"websiteUrl": "https://zoom.us",
"privacyPolicyUrl": "https://zoom.us/privacy",
"serviceLevelAgreementUrl": "https://explore.zoom.us/en/premier-support-terms/",
"description": "Zoom is a video communication platform that allows users to send messages, files, and images to each other.",
"category": "Communication",
"certifications": [
"ISO/IEC 27001:2022",
"ISO/IEC 27017:2015",
"ISO/IEC 27018:2019",
"ISO/IEC 27701:2019",
"SOC2 Type 2",
"SOC2 HITRUST",
"CSTAR LEVEL 2",
"FedRAMP",
"StateRAMP",
"CJIS",
"UK Cyber Essentials Plus",
"iRAP",
"ENS",
"BSI C5",
"gpaNRW",
"ISMAP",
"ETDA",
"PCI DSS",
"GDPR"
],
"securityPageUrl": "https://zoom.us/trust/security",
"statusPageUrl": "https://status.zoom.us/"
},
{
"name": "Github",
"headquarterAddress": "88 Colin P Kelly Jr St, San Francisco, CA 94103",
"legalName": "GitHub, Inc.",
"websiteUrl": "https://github.com",
"privacyPolicyUrl": "https://github.com/site/privacy",
"serviceLevelAgreementUrl": "https://github.com/site/terms",
"subprocessorsListUrl": "https://docs.github.com/en/site-policy/privacy-policies/github-subprocessors",
"description": "Github is a code hosting platform for version control and collaboration.",
"category": "Code Hosting",
"certifications": [
"SOC 1 Type 2",
"SOC 2 Type 2",
"CSA CAIQ Level 1",
"ISO/IEC 27001:2013",
"CSA STAR Level 2",
"GDPR"
],
"securityPageUrl": "https://docs.github.com/en/code-security/security-overview/about-security-overview",
"statusPageUrl": "https://www.githubstatus.com/"
},
{
"name": "Stripe",
"headquarterAddress": "101 Townsend St, San Francisco, CA 94103",
"legalName": "Stripe, Inc.",
"websiteUrl": "https://stripe.com",
"privacyPolicyUrl": "https://stripe.com/privacy",
"serviceLevelAgreementUrl": "https://stripe.com/legal/ssa",
"dataProcessingAgreementUrl": "https://stripe.com/legal/dpa",
"description": "Online payment processing platform that enables businesses to accept and manage digital payments, supporting various payment methods and currencies with integrated fraud protection and compliance features",
"category": "Payment Processing",
"certifications": [
"PCI DSS v4.0",
"SOC 2 Type 2",
"SOC 1 Type 2",
"SOC 3",
"EMVCo Level 1",
"EMVCo Level 2",
"CBPR",
"PRP",
"EU-U.S. DPF",
"EU-U.S. DPF",
"GDPR"
],
"securityPageUrl": "https://stripe.com/security",
"statusPageUrl": "https://status.stripe.com/"
},
{
"name": "Cloudflare",
"headquarterAddress": "101 Townsend St, San Francisco, CA 94103",
"legalName": "Cloudflare, Inc.",
"websiteUrl": "https://cloudflare.com",
"privacyPolicyUrl": "https://cloudflare.com/privacy",
"serviceLevelAgreementUrl": "https://www.cloudflare.com/en-gb/business-sla",
"description": "Cloudflare is a cloud computing company that provides a range of services, including web hosting, domain name registration, and cloud storage.",
"category": "Web Hosting",
"certifications": [
"ISO/IEC 27001:2013",
"ISO/IEC 27701:2019",
"ISO/IEC 27018:2019",
"FedRAMP",
"SOC 2 Type 2",
"PCI DSS 4.0",
"Global CBPR",
"Global PRP",
"EU Cloud Code of Conduct",
"Cyber Essentials",
"C5:2020",
"ENS",
"BSI Qualification",
"WCAG 2.1 AA and Section 508",
"APPI",
"LGPD",
"DPDP",
"GDPR",
"PDPA",
"PIPA",
"DORA",
"CCPA",
"CPRA"
],
"securityPageUrl": "https://www.cloudflare.com/en-gb/security",
"statusPageUrl": "https://www.cloudflarestatus.com/"
},
{
"name": "Sentry",
"headquarterAddress": "1 Market St, San Francisco, CA 94105",
"legalName": "Sentry, Inc.",
"websiteUrl": "https://sentry.io",
"privacyPolicyUrl": "https://sentry.io/privacy",
"serviceLevelAgreementUrl": "",
"description": "Sentry is a cloud-based platform for monitoring and analyzing application performance and user behavior.",
"category": "Monitoring",
"certifications": ["ISO/IEC 27001:2013", "SOC2 Type 2"],
"securityPageUrl": "https://sentry.io/security",
"statusPageUrl": "https://status.sentry.io/"
},
{
"name": "Datadog",
"headquarterAddress": "1 Market St, San Francisco, CA 94105",
"legalName": "Datadog, Inc.",
"websiteUrl": "https://datadog.com",
"privacyPolicyUrl": "https://datadog.com/privacy",
"serviceLevelAgreementUrl": "https://datadog.com/terms",
"description": "Datadog is a cloud-based platform for monitoring and analyzing application performance and user behavior.",
"category": "Monitoring",
"certifications": [
"CCPA",
"CSA STAR",
"DORA",
"EU-US DPF",
"FedRAMP",
"GDPR",
"HIPAA",
"ISO/IEC 27001:2022",
"ISO/IEC 27017:2015",
"GDPR"
],
"securityPageUrl": "https://datadog.com/security",
"trustPageUrl": "https://datadog.com/trust",
"statusPageUrl": "https://status.datadoghq.com/"
},
{
"name": "Vercel",
"headquarterAddress": "1 Market St, San Francisco, CA 94105",
"legalName": "Vercel, Inc.",
"websiteUrl": "https://vercel.com",
"privacyPolicyUrl": "https://vercel.com/legal/privacy-policy",
"serviceLevelAgreementUrl": "https://vercel.com/legal/sla",
"dataProcessingAgreementUrl": "https://vercel.com/legal/dpa",
"description": "Vercel is a cloud-based platform for monitoring and analyzing application performance and user behavior.",
"category": "Web Hosting",
"certifications": [
"ISO/IEC 27001:2013",
"SOC2 Type 2",
"GDPR",
"PCI DSS",
"HIPAA",
"DPF",
"CCPA",
"PIPEDA"
],
"securityPageUrl": "https://vercel.com/security",
"trustPageUrl": "https://security.vercel.com/",
"statusPageUrl": "https://status.vercel.com/"
},
{
"name": "Sendgrid",
"headquarterAddress": "1801 California Street, Suite 500, Denver, CO 80202",
"legalName": "SendGrid, Inc.",
"websiteUrl": "https://sendgrid.com",
"privacyPolicyUrl": "https://www.twilio.com/en-us/legal/privacy",
"serviceLevelAgreementUrl": "https://sendgrid.com/terms",
"dataProcessingAgreementUrl": "https://sendgrid.com/dpa",
"description": "Cloud-based email delivery platform that provides transactional and marketing email services, offering reliable message delivery, analytics, and automation features for business communications.",
"category": "Email Marketing",
"certifications": [
"CCPA",
"CPRA",
"GDPR",
"HIPAA",
"ISO/IEC 27001:2013",
"ISO/IEC 27017:2015",
"ISO/IEC 27018:2019",
"SOC2 Type 2",
"PCI DSS"
],
"securityPageUrl": "https://sendgrid.com/en-us/policies/security",
"trustPageUrl": "https://security.twilio.com/",
"statusPageUrl": "https://status.sendgrid.com/"
},
{
"name": "Figma",
"headquarterAddress": "760 Market St Floor 10, San Francisco, CA 94102",
"legalName": "Figma, Inc.",
"websiteUrl": "https://figma.com",
"privacyPolicyUrl": "https://www.figma.com/legal/privacy/",
"serviceSoftwareAgreementUrl": "https://www.figma.com/ssa/",
"description": "Cloud-based design and prototyping platform that enables collaborative interface design, wireframing, and mockup creation with real-time editing capabilities for teams.",
"category": "Design",
"certifications": [
"SOC 2 Type 2",
"ISO/IEC 27001:2013",
"ISO/IEC 27001:2022",
"GDPR",
"ISO/IEC 27017:2015",
"ISO/IEC 27018:2019",
"SOC3",
"CCPA",
"CSA",
"SIG",
"EU Cloud Code of Conduct",
"TISAX",
"VPAT"
],
"securityPageUrl": "https://www.figma.com/security",
"trustPageUrl": "https://compliance.figma.com/",
"statusPageUrl": "https://status.figma.com/"
},
{
"name": "Notion",
"headquarterAddress": "2300 Harrison St, San Francisco, CA 94110",
"legalName": "Notion Labs, Inc.",
"websiteUrl": "https://notion.so",
"privacyPolicyUrl": "https://www.notion.so/notion/Privacy-Policy-3468d120cf614d4c9014c09f6adc9091",
"serviceLevelAgreementUrl": "https://www.notion.so/notion/Service-Level-Terms-6f805fa1d4ca4463b805e2832ae8ff0d",
"subprocessorsListUrl": "https://www.notion.so/notion/Notion-s-List-of-Subprocessors-268fa5bcfa0f46b6bc29436b21676734",
"businessAssociateAgreementUrl": "https://www.notion.so/notion/Business-Associate-Agreement-909d9f4ccca041b1a23d0fe6e56fa111",
"description": "Cloud-based workspace and collaboration platform that offers document management, project management, and team communication features, allowing users to create, edit, and share content in a centralized environment.",
"category": "Project Management",
"certifications": [
"SOC 2 Type 2",
"ISO/IEC 27001:2022",
"ISO/IEC 27701:2019",
"ISO/IEC 27017:2015",
"ISO/IEC 27018:2019",
"HIPAA",
"BSI C5",
"GDPR",
"CCPA"
],
"statusPageUrl": "https://status.notion.so"
},
{
"name": "Mintlify",
"headquarterAddress": "108 Ferris Place, Ithaca, NY 14850",
"legalName": "Mintlify, Inc.",
"websiteUrl": "https://mintlify.com",
"privacyPolicyUrl": "https://app.termly.io/policy-viewer/policy.html?policyUUID=95d79e73-9d6f-4e0a-8abd-2a608e8f5242",
"termsOfServiceUrl": "https://mintlify.com/legal/terms",
"description": "Mintlify is a cloud-based documentation platform that enables teams to create, manage, and share documentation for their projects.",
"category": "Documentation",
"certifications": ["SOC 2 Type 1"],
"subprocessorsListUrl": "https://security.mintlify.com",
"trustPageUrl": "https://security.mintlify.com/",
"statusPageUrl": "https://status.mintlify.com/"
},
{
"name": "Supabase",
"headquarterAddress": "3500 S Dupont Hwy, United States",
"legalName": "Supabase, Inc.",
"websiteUrl": "https://supabase.com",
"privacyPolicyUrl": "https://supabase.com/privacy",
"termsOfServiceUrl": "https://supabase.com/terms",
"description": "Open-source Firebase alternative providing a backend-as-a-service platform with PostgreSQL database, authentication, storage, and API functionality for application development.",
"category": "Database",
"certifications": ["SOC2 Type 2", "HIPAA", "GDPR"],
"securityPageUrl": "https://supabase.com/security",
"serviceLevelAgreementUrl": "https://supabase.com/sla",
"trustPageUrl": "https://security.supabase.com/",
"dataProcessingAgreementUrl": "https://supabase.com/legal/dpa",
"statusPageUrl": "https://status.supabase.com/"
}
]

View File

@@ -24,6 +24,24 @@ import { VendorListViewDeleteVendorMutation } from "./__generated__/VendorListVi
import { VendorListViewPaginationQuery } from "./__generated__/VendorListViewPaginationQuery.graphql";
import { VendorListView_vendors$key } from "./__generated__/VendorListView_vendors.graphql";
interface VendorData {
name: string;
headquarterAddress: string;
legalName: string;
websiteUrl: string;
privacyPolicyUrl: string;
serviceLevelAgreementUrl?: string;
category: string;
dataProcessingAgreementUrl?: string;
description: string;
categories: string[];
certifications: string[];
securityPageUrl?: string;
trustPageUrl?: string;
statusPageUrl?: string;
termsOfServiceUrl?: string;
}
const ITEMS_PER_PAGE = 25;
const vendorListViewQuery = graphql`
@@ -111,38 +129,6 @@ const deleteVendorMutation = graphql`
}
`;
// Define a proper type for the vendor items
interface VendorItem {
id: string;
name: string;
createdAt: string;
}
// TODO: Remove this once we have a real list of vendors
const vendorsList: VendorItem[] = [
{ id: "1", name: "Amazon Web Services", createdAt: new Date().toISOString() },
{
id: "2",
name: "Google Cloud Platform",
createdAt: new Date().toISOString(),
},
{ id: "3", name: "Microsoft Azure", createdAt: new Date().toISOString() },
{ id: "4", name: "Salesforce", createdAt: new Date().toISOString() },
{ id: "5", name: "Slack", createdAt: new Date().toISOString() },
{ id: "6", name: "Zoom", createdAt: new Date().toISOString() },
{ id: "7", name: "Dropbox", createdAt: new Date().toISOString() },
{ id: "8", name: "Trello", createdAt: new Date().toISOString() },
{ id: "9", name: "Asana", createdAt: new Date().toISOString() },
{ id: "10", name: "Notion", createdAt: new Date().toISOString() },
{ id: "11", name: "GitHub", createdAt: new Date().toISOString() },
{ id: "12", name: "GitLab", createdAt: new Date().toISOString() },
{ id: "13", name: "Bitbucket", createdAt: new Date().toISOString() },
{ id: "14", name: "Docker", createdAt: new Date().toISOString() },
{ id: "15", name: "Kubernetes", createdAt: new Date().toISOString() },
{ id: "16", name: "Jenkins", createdAt: new Date().toISOString() },
{ id: "17", name: "CircleCI", createdAt: new Date().toISOString() },
];
function LoadAboveButton({
isLoading,
hasMore,
@@ -210,13 +196,40 @@ function VendorListContent({
const [, setSearchParams] = useSearchParams();
const [, startTransition] = useTransition();
const [searchTerm, setSearchTerm] = useState("");
const [filteredVendors, setFilteredVendors] = useState<VendorItem[]>([]);
const [filteredVendors, setFilteredVendors] = useState<VendorData[]>([]);
const [vendorsData, setVendorsData] = useState<VendorData[]>([]);
const [isLoadingVendors, setIsLoadingVendors] = useState(false);
const [createVendor] =
useMutation<VendorListViewCreateVendorMutation>(createVendorMutation);
const [deleteVendor] =
useMutation<VendorListViewDeleteVendorMutation>(deleteVendorMutation);
const { organizationId } = useParams();
useEffect(() => {
const loadVendorsData = async () => {
try {
setIsLoadingVendors(true);
const response = await fetch("/data/vendors/vendors.json");
if (!response.ok) {
throw new Error("Failed to load vendors data");
}
const data = await response.json();
setVendorsData(data);
} catch (error) {
console.error("Error loading vendors data:", error);
toast({
title: "Error",
description: "Failed to load vendors data",
variant: "destructive",
});
} finally {
setIsLoadingVendors(false);
}
};
loadVendorsData();
}, [toast]);
const {
data: vendorsConnection,
loadNext,
@@ -234,7 +247,7 @@ function VendorListContent({
vendorsConnection.vendors.edges.map((edge) => edge.node) ?? [];
const pageInfo = vendorsConnection.vendors.pageInfo;
const fuse = new Fuse(vendorsList, {
const fuse = new Fuse<VendorData>(vendorsData, {
keys: ["name"],
threshold: 0.3,
});
@@ -269,16 +282,22 @@ function VendorListContent({
setFilteredVendors(results);
}
}}
disabled={isLoadingVendors}
/>
{isLoadingVendors && (
<div className="absolute inset-0 flex items-center justify-center bg-background/50">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
</div>
)}
{searchTerm.trim() !== "" && (
<div
style={{ borderRadius: "0.3rem" }}
className="absolute top-full left-0 mt-1 w-[calc(100%-100px)] max-h-48 overflow-y-auto border bg-invert-bg shadow-md z-10"
>
{filteredVendors.map((vendor: VendorItem) => (
{filteredVendors.map((vendor) => (
<button
key={vendor.id}
key={vendor.name}
className="w-full px-3 py-2 text-left bg-invert-bg hover:bg-h-subtle-bg"
onClick={() => {
createVendor({
@@ -287,7 +306,21 @@ function VendorListContent({
input: {
organizationId: data.organization.id,
name: vendor.name,
description: "",
description: vendor.description,
headquarterAddress: vendor.headquarterAddress,
legalName: vendor.legalName,
websiteUrl: vendor.websiteUrl,
category: vendor.category,
privacyPolicyUrl: vendor.privacyPolicyUrl,
serviceLevelAgreementUrl:
vendor.serviceLevelAgreementUrl,
dataProcessingAgreementUrl:
vendor.dataProcessingAgreementUrl,
certifications: vendor.certifications,
securityPageUrl: vendor.securityPageUrl,
trustPageUrl: vendor.trustPageUrl,
statusPageUrl: vendor.statusPageUrl,
termsOfServiceUrl: vendor.termsOfServiceUrl,
serviceStartAt: new Date().toISOString(),
serviceCriticality: "LOW",
riskTier: "GENERAL",

View File

@@ -5,7 +5,7 @@ import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { useToast } from "@/hooks/use-toast";
import { HelpCircle } from "lucide-react";
import { HelpCircle, X } from "lucide-react";
import {
graphql,
PreloadedQuery,
@@ -18,6 +18,7 @@ import { Suspense, useEffect, useState, useCallback, useRef } from "react";
import type { VendorViewQuery as VendorViewQueryType } from "./__generated__/VendorViewQuery.graphql";
import type { VendorViewDeleteComplianceReportMutation as DeleteComplianceReportMutationType } from "./__generated__/VendorViewDeleteComplianceReportMutation.graphql";
import type { VendorViewUploadComplianceReportMutation as UploadComplianceReportMutationType } from "./__generated__/VendorViewUploadComplianceReportMutation.graphql";
import type { VendorViewUpdateVendorMutation } from "./__generated__/VendorViewUpdateVendorMutation.graphql";
import { useParams } from "react-router";
import { cn } from "@/lib/utils";
import { PageTemplate } from "@/components/PageTemplate";
@@ -37,6 +38,14 @@ const vendorViewQuery = graphql`
statusPageUrl
termsOfServiceUrl
privacyPolicyUrl
serviceLevelAgreementUrl
dataProcessingAgreementUrl
securityPageUrl
trustPageUrl
certifications
headquarterAddress
legalName
websiteUrl
createdAt
updatedAt
complianceReports(first: 100)
@@ -72,6 +81,14 @@ const updateVendorMutation = graphql`
statusPageUrl
termsOfServiceUrl
privacyPolicyUrl
serviceLevelAgreementUrl
dataProcessingAgreementUrl
securityPageUrl
trustPageUrl
certifications
headquarterAddress
legalName
websiteUrl
updatedAt
}
}
@@ -277,6 +294,55 @@ function ComplianceReportsTable({
);
}
function TagList({
tags,
onAdd,
onRemove,
}: {
tags: readonly string[];
onAdd: (tag: string) => void;
onRemove: (tag: string) => void;
}) {
const [newTag, setNewTag] = useState("");
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && newTag.trim()) {
e.preventDefault();
onAdd(newTag.trim());
setNewTag("");
}
};
return (
<div className="space-y-2">
<div className="flex flex-wrap gap-2">
{tags.map((tag) => (
<div
key={tag}
className="flex items-center gap-1 rounded-full bg-primary/10 px-3 py-1 text-sm"
>
<span>{tag}</span>
<button
onClick={() => onRemove(tag)}
className="text-primary hover:text-primary/80"
>
<X className="h-3 w-3" />
</button>
</div>
))}
</div>
<Input
type="text"
value={newTag}
onChange={(e) => setNewTag(e.target.value)}
onKeyDown={handleAddTag}
placeholder="Type and press Enter to add a certification"
className="mt-2"
/>
</div>
);
}
function VendorViewContent({
queryRef,
}: {
@@ -294,8 +360,17 @@ function VendorViewContent({
statusPageUrl: data.node.statusPageUrl || "",
termsOfServiceUrl: data.node.termsOfServiceUrl || "",
privacyPolicyUrl: data.node.privacyPolicyUrl || "",
serviceLevelAgreementUrl: data.node.serviceLevelAgreementUrl || "",
dataProcessingAgreementUrl: data.node.dataProcessingAgreementUrl || "",
securityPageUrl: data.node.securityPageUrl || "",
trustPageUrl: data.node.trustPageUrl || "",
certifications: data.node.certifications || [],
headquarterAddress: data.node.headquarterAddress || "",
legalName: data.node.legalName || "",
websiteUrl: data.node.websiteUrl || "",
});
const [updateVendor] = useMutation(updateVendorMutation);
const [updateVendor] =
useMutation<VendorViewUpdateVendorMutation>(updateVendorMutation);
const [deleteVendorComplianceReport] =
useMutation<DeleteComplianceReportMutationType>(
deleteComplianceReportMutation
@@ -321,7 +396,7 @@ function VendorViewContent({
updateVendor({
variables: {
input: {
id: data.node.id,
id: data.node.id!,
...formattedData,
},
},
@@ -362,7 +437,6 @@ function VendorViewContent({
setEditedFields((prev) => new Set(prev).add(field));
};
// Update the cancel handler to also format dates
const handleCancel = () => {
setFormData({
name: data.node.name || "",
@@ -374,6 +448,14 @@ function VendorViewContent({
statusPageUrl: data.node.statusPageUrl || "",
termsOfServiceUrl: data.node.termsOfServiceUrl || "",
privacyPolicyUrl: data.node.privacyPolicyUrl || "",
serviceLevelAgreementUrl: data.node.serviceLevelAgreementUrl || "",
dataProcessingAgreementUrl: data.node.dataProcessingAgreementUrl || "",
securityPageUrl: data.node.securityPageUrl || "",
trustPageUrl: data.node.trustPageUrl || "",
certifications: data.node.certifications || [],
headquarterAddress: data.node.headquarterAddress || "",
legalName: data.node.legalName || "",
websiteUrl: data.node.websiteUrl || "",
});
setEditedFields(new Set());
};
@@ -497,6 +579,24 @@ function VendorViewContent({
onChange={(value) => handleFieldChange("description", value)}
/>
<EditableField
label="Legal Name"
value={formData.legalName}
onChange={(value) => handleFieldChange("legalName", value)}
/>
<EditableField
label="Headquarter Address"
value={formData.headquarterAddress}
onChange={(value) => handleFieldChange("headquarterAddress", value)}
/>
<EditableField
label="Website URL"
value={formData.websiteUrl}
onChange={(value) => handleFieldChange("websiteUrl", value)}
/>
<Card className="p-6">
<div className="space-y-4">
<div className="space-y-2">
@@ -628,16 +728,29 @@ function VendorViewContent({
"General vendor with minimal risk"}
</p>
</div>
</div>
</div>
</Card>
<Card className="p-6">
<div className="space-y-4">
<div className="space-y-2">
<h2 className="text-lg font-medium">URLs</h2>
<p className="text-sm text-secondary">
Important URLs related to the vendor
</p>
</div>
<div className="space-y-4">
<EditableField
label="Status Page URL"
value={formData.statusPageUrl || ""}
value={formData.statusPageUrl}
onChange={(value) => handleFieldChange("statusPageUrl", value)}
/>
<EditableField
label="Terms of Service URL"
value={formData.termsOfServiceUrl || ""}
value={formData.termsOfServiceUrl}
onChange={(value) =>
handleFieldChange("termsOfServiceUrl", value)
}
@@ -645,11 +758,76 @@ function VendorViewContent({
<EditableField
label="Privacy Policy URL"
value={formData.privacyPolicyUrl || ""}
value={formData.privacyPolicyUrl}
onChange={(value) =>
handleFieldChange("privacyPolicyUrl", value)
}
/>
<EditableField
label="Service Level Agreement URL"
value={formData.serviceLevelAgreementUrl}
onChange={(value) =>
handleFieldChange("serviceLevelAgreementUrl", value)
}
/>
<EditableField
label="Data Processing Agreement URL"
value={formData.dataProcessingAgreementUrl}
onChange={(value) =>
handleFieldChange("dataProcessingAgreementUrl", value)
}
/>
<EditableField
label="Security Page URL"
value={formData.securityPageUrl}
onChange={(value) =>
handleFieldChange("securityPageUrl", value)
}
/>
<EditableField
label="Trust Page URL"
value={formData.trustPageUrl}
onChange={(value) => handleFieldChange("trustPageUrl", value)}
/>
</div>
</div>
</Card>
<Card className="p-6">
<div className="space-y-4">
<div className="space-y-2">
<h2 className="text-lg font-medium">Certifications</h2>
<p className="text-sm text-secondary">
List of certifications held by the vendor
</p>
</div>
<div className="space-y-4">
<div className="space-y-2">
<div className="flex items-center gap-2">
<HelpCircle className="h-4 w-4 text-tertiary" />
<Label className="text-sm">Certifications</Label>
</div>
<TagList
tags={[...formData.certifications]}
onAdd={(tag) =>
handleFieldChange("certifications", [
...formData.certifications,
tag,
])
}
onRemove={(tag) =>
handleFieldChange(
"certifications",
formData.certifications.filter((t) => t !== tag)
)
}
/>
</div>
</div>
</div>
</Card>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<38a771b621d1e813bc7dbdd6d5bcf323>>
* @generated SignedSource<<d8ebd7f4de7a9e2e314f93e5e6b61e25>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -12,16 +12,25 @@ import { ConcreteRequest } from 'relay-runtime';
export type RiskTier = "CRITICAL" | "GENERAL" | "SIGNIFICANT";
export type ServiceCriticality = "HIGH" | "LOW" | "MEDIUM";
export type CreateVendorInput = {
description: string;
category?: string | null | undefined;
certifications?: ReadonlyArray<string> | null | undefined;
dataProcessingAgreementUrl?: string | null | undefined;
description?: string | null | undefined;
headquarterAddress?: string | null | undefined;
legalName?: string | null | undefined;
name: string;
organizationId: string;
privacyPolicyUrl?: string | null | undefined;
riskTier: RiskTier;
securityPageUrl?: string | null | undefined;
serviceCriticality: ServiceCriticality;
serviceLevelAgreementUrl?: string | null | undefined;
serviceStartAt: string;
serviceTerminationAt?: string | null | undefined;
statusPageUrl?: string | null | undefined;
termsOfServiceUrl?: string | null | undefined;
trustPageUrl?: string | null | undefined;
websiteUrl?: string | null | undefined;
};
export type VendorListViewCreateVendorMutation$variables = {
connections: ReadonlyArray<string>;
@@ -32,7 +41,7 @@ export type VendorListViewCreateVendorMutation$data = {
readonly vendorEdge: {
readonly node: {
readonly createdAt: string;
readonly description: string;
readonly description: string | null | undefined;
readonly id: string;
readonly name: string;
readonly riskTier: RiskTier;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7b424e7690762d554e28421c32fdee78>>
* @generated SignedSource<<dce76b1271e95cbf0d70b18be492a389>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -18,7 +18,7 @@ export type VendorListView_vendors$data = {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
readonly description: string;
readonly description: string | null | undefined;
readonly id: string;
readonly name: string;
readonly riskTier: RiskTier;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e84da0f625c9ae5495a0cb0c99c88c81>>
* @generated SignedSource<<f69485d1f583f57e60850e2bc6428763>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -16,6 +16,7 @@ export type VendorViewQuery$variables = {
};
export type VendorViewQuery$data = {
readonly node: {
readonly certifications?: ReadonlyArray<string>;
readonly complianceReports?: {
readonly edges: ReadonlyArray<{
readonly node: {
@@ -30,17 +31,24 @@ export type VendorViewQuery$data = {
}>;
};
readonly createdAt?: string;
readonly description?: string;
readonly dataProcessingAgreementUrl?: string | null | undefined;
readonly description?: string | null | undefined;
readonly headquarterAddress?: string | null | undefined;
readonly id?: string;
readonly legalName?: string | null | undefined;
readonly name?: string;
readonly privacyPolicyUrl?: string | null | undefined;
readonly riskTier?: RiskTier;
readonly securityPageUrl?: string | null | undefined;
readonly serviceCriticality?: ServiceCriticality;
readonly serviceLevelAgreementUrl?: string | null | undefined;
readonly serviceStartAt?: string;
readonly serviceTerminationAt?: string | null | undefined;
readonly statusPageUrl?: string | null | undefined;
readonly termsOfServiceUrl?: string | null | undefined;
readonly trustPageUrl?: string | null | undefined;
readonly updatedAt?: string;
readonly websiteUrl?: string | null | undefined;
};
};
export type VendorViewQuery = {
@@ -137,24 +145,80 @@ v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"name": "serviceLevelAgreementUrl",
"storageKey": null
},
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"name": "dataProcessingAgreementUrl",
"storageKey": null
},
v14 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "securityPageUrl",
"storageKey": null
},
v15 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "trustPageUrl",
"storageKey": null
},
v16 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "certifications",
"storageKey": null
},
v17 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "headquarterAddress",
"storageKey": null
},
v18 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "legalName",
"storageKey": null
},
v19 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "websiteUrl",
"storageKey": null
},
v20 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v21 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
v22 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v15 = [
v23 = [
{
"alias": null,
"args": null,
@@ -207,8 +271,8 @@ v15 = [
"name": "fileSize",
"storageKey": null
},
(v12/*: any*/),
(v14/*: any*/)
(v20/*: any*/),
(v22/*: any*/)
],
"storageKey": null
},
@@ -248,7 +312,7 @@ v15 = [
"storageKey": null
}
],
v16 = [
v24 = [
{
"kind": "Literal",
"name": "first",
@@ -285,6 +349,14 @@ return {
(v11/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
(v19/*: any*/),
(v20/*: any*/),
(v21/*: any*/),
{
"alias": "complianceReports",
"args": null,
@@ -292,7 +364,7 @@ return {
"kind": "LinkedField",
"name": "__VendorView_complianceReports_connection",
"plural": false,
"selections": (v15/*: any*/),
"selections": (v23/*: any*/),
"storageKey": null
}
],
@@ -320,7 +392,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v14/*: any*/),
(v22/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
@@ -336,19 +408,27 @@ return {
(v11/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
(v19/*: any*/),
(v20/*: any*/),
(v21/*: any*/),
{
"alias": null,
"args": (v16/*: any*/),
"args": (v24/*: any*/),
"concreteType": "VendorComplianceReportConnection",
"kind": "LinkedField",
"name": "complianceReports",
"plural": false,
"selections": (v15/*: any*/),
"selections": (v23/*: any*/),
"storageKey": "complianceReports(first:100)"
},
{
"alias": null,
"args": (v16/*: any*/),
"args": (v24/*: any*/),
"filters": null,
"handle": "connection",
"key": "VendorView_complianceReports",
@@ -365,7 +445,7 @@ return {
]
},
"params": {
"cacheID": "9d2e53dfbc545614d651819697eda6e6",
"cacheID": "2bef9911b76d74ced85cf4430410a297",
"id": null,
"metadata": {
"connection": [
@@ -382,11 +462,11 @@ return {
},
"name": "VendorViewQuery",
"operationKind": "query",
"text": "query VendorViewQuery(\n $vendorId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n serviceCriticality\n riskTier\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n"
"text": "query VendorViewQuery(\n $vendorId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n serviceCriticality\n riskTier\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "110583f1567e472ba6b4a6064be056e9";
(node as any).hash = "f3f95bc0c893b61e83940c1cc0c33922";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7568e87d53b6e76d1db4e3029430f118>>
* @generated SignedSource<<0e66de0cfba2c27bbf78dcb8e846ad8d>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -12,16 +12,25 @@ import { ConcreteRequest } from 'relay-runtime';
export type RiskTier = "CRITICAL" | "GENERAL" | "SIGNIFICANT";
export type ServiceCriticality = "HIGH" | "LOW" | "MEDIUM";
export type UpdateVendorInput = {
category?: string | null | undefined;
certifications?: ReadonlyArray<string> | null | undefined;
dataProcessingAgreementUrl?: string | null | undefined;
description?: string | null | undefined;
headquarterAddress?: string | null | undefined;
id: string;
legalName?: string | null | undefined;
name?: string | null | undefined;
privacyPolicyUrl?: string | null | undefined;
riskTier?: RiskTier | null | undefined;
securityPageUrl?: string | null | undefined;
serviceCriticality?: ServiceCriticality | null | undefined;
serviceLevelAgreementUrl?: string | null | undefined;
serviceStartAt?: string | null | undefined;
serviceTerminationAt?: string | null | undefined;
statusPageUrl?: string | null | undefined;
termsOfServiceUrl?: string | null | undefined;
trustPageUrl?: string | null | undefined;
websiteUrl?: string | null | undefined;
};
export type VendorViewUpdateVendorMutation$variables = {
input: UpdateVendorInput;
@@ -29,17 +38,25 @@ export type VendorViewUpdateVendorMutation$variables = {
export type VendorViewUpdateVendorMutation$data = {
readonly updateVendor: {
readonly vendor: {
readonly description: string;
readonly certifications: ReadonlyArray<string>;
readonly dataProcessingAgreementUrl: string | null | undefined;
readonly description: string | null | undefined;
readonly headquarterAddress: string | null | undefined;
readonly id: string;
readonly legalName: string | null | undefined;
readonly name: string;
readonly privacyPolicyUrl: string | null | undefined;
readonly riskTier: RiskTier;
readonly securityPageUrl: string | null | undefined;
readonly serviceCriticality: ServiceCriticality;
readonly serviceLevelAgreementUrl: string | null | undefined;
readonly serviceStartAt: string;
readonly serviceTerminationAt: string | null | undefined;
readonly statusPageUrl: string | null | undefined;
readonly termsOfServiceUrl: string | null | undefined;
readonly trustPageUrl: string | null | undefined;
readonly updatedAt: string;
readonly websiteUrl: string | null | undefined;
};
};
};
@@ -149,6 +166,62 @@ v1 = [
"name": "privacyPolicyUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "serviceLevelAgreementUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "dataProcessingAgreementUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "securityPageUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "trustPageUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "certifications",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "headquarterAddress",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "legalName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "websiteUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -181,16 +254,16 @@ return {
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "1a49efe0fe5e3da519e1b15a8f81cc1e",
"cacheID": "8ed69675626a00cac2cc79aa570f123d",
"id": null,
"metadata": {},
"name": "VendorViewUpdateVendorMutation",
"operationKind": "mutation",
"text": "mutation VendorViewUpdateVendorMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n serviceCriticality\n riskTier\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n updatedAt\n }\n }\n}\n"
"text": "mutation VendorViewUpdateVendorMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n serviceCriticality\n riskTier\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n updatedAt\n }\n }\n}\n"
}
};
})();
(node as any).hash = "15ffa38b13259f9c7c6511aa72d07247";
(node as any).hash = "517efd79b3eb1781ed562368a2ed1ecc";
export default node;

View File

@@ -0,0 +1,12 @@
ALTER TABLE vendors
ADD COLUMN service_level_agreement_url TEXT,
ADD COLUMN data_processing_agreement_url TEXT,
ADD COLUMN security_page_url TEXT,
ADD COLUMN trust_page_url TEXT,
ADD COLUMN headquarter_address TEXT,
ADD COLUMN legal_name TEXT,
ADD COLUMN website_url TEXT,
ADD COLUMN category TEXT,
ADD COLUMN certifications TEXT[];

View File

@@ -0,0 +1 @@
UPDATE vendors SET category = 'Other' WHERE category IS NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE vendors ALTER COLUMN description DROP NOT NULL;

View File

@@ -0,0 +1,6 @@
ALTER TABLE vendor_compliance_reports
DROP CONSTRAINT vendor_compliance_reports_vendor_id_fkey,
ADD CONSTRAINT vendor_compliance_reports_vendor_id_fkey
FOREIGN KEY (vendor_id)
REFERENCES vendors(id)
ON DELETE CASCADE;

View File

@@ -31,19 +31,28 @@ var ErrConcurrentModification = errors.New("concurrent modification")
type (
Vendor struct {
ID gid.GID `db:"id"`
OrganizationID gid.GID `db:"organization_id"`
Name string `db:"name"`
Description string `db:"description"`
ServiceStartAt time.Time `db:"service_start_at"`
ServiceTerminationAt *time.Time `db:"service_termination_at"`
ServiceCriticality ServiceCriticality `db:"service_criticality"`
RiskTier RiskTier `db:"risk_tier"`
StatusPageURL *string `db:"status_page_url"`
TermsOfServiceURL *string `db:"terms_of_service_url"`
PrivacyPolicyURL *string `db:"privacy_policy_url"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID gid.GID `db:"id"`
OrganizationID gid.GID `db:"organization_id"`
Name string `db:"name"`
Description *string `db:"description"`
Category string `db:"category"`
ServiceStartAt time.Time `db:"service_start_at"`
ServiceTerminationAt *time.Time `db:"service_termination_at"`
HeadquarterAddress *string `db:"headquarter_address"`
LegalName *string `db:"legal_name"`
WebsiteURL *string `db:"website_url"`
PrivacyPolicyURL *string `db:"privacy_policy_url"`
ServiceLevelAgreementURL *string `db:"service_level_agreement_url"`
DataProcessingAgreementURL *string `db:"data_processing_agreement_url"`
Certifications []string `db:"certifications"`
ServiceCriticality ServiceCriticality `db:"service_criticality"`
RiskTier RiskTier `db:"risk_tier"`
StatusPageURL *string `db:"status_page_url"`
TermsOfServiceURL *string `db:"terms_of_service_url"`
SecurityPageURL *string `db:"security_page_url"`
TrustPageURL *string `db:"trust_page_url"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
Vendors []*Vendor
@@ -72,13 +81,22 @@ SELECT
organization_id,
name,
description,
category,
headquarter_address,
legal_name,
website_url,
service_start_at,
service_termination_at,
privacy_policy_url,
service_level_agreement_url,
data_processing_agreement_url,
certifications,
service_criticality,
risk_tier,
status_page_url,
terms_of_service_url,
privacy_policy_url,
security_page_url,
trust_page_url,
created_at,
updated_at
FROM
@@ -123,13 +141,22 @@ INSERT INTO
organization_id,
name,
description,
category,
headquarter_address,
legal_name,
website_url,
privacy_policy_url,
service_level_agreement_url,
data_processing_agreement_url,
certifications,
service_start_at,
service_termination_at,
service_criticality,
risk_tier,
status_page_url,
terms_of_service_url,
privacy_policy_url,
security_page_url,
trust_page_url,
created_at,
updated_at
)
@@ -139,33 +166,51 @@ VALUES (
@organization_id,
@name,
@description,
@category,
@headquarter_address,
@legal_name,
@website_url,
@privacy_policy_url,
@service_level_agreement_url,
@data_processing_agreement_url,
@certifications,
@service_start_at,
@service_termination_at,
@service_criticality,
@risk_tier,
@status_page_url,
@terms_of_service_url,
@privacy_policy_url,
@security_page_url,
@trust_page_url,
@created_at,
@updated_at
)
`
args := pgx.StrictNamedArgs{
"tenant_id": scope.GetTenantID(),
"vendor_id": v.ID,
"organization_id": v.OrganizationID,
"name": v.Name,
"description": v.Description,
"service_start_at": v.ServiceStartAt,
"service_termination_at": v.ServiceTerminationAt,
"service_criticality": v.ServiceCriticality,
"risk_tier": v.RiskTier,
"status_page_url": v.StatusPageURL,
"terms_of_service_url": v.TermsOfServiceURL,
"privacy_policy_url": v.PrivacyPolicyURL,
"created_at": v.CreatedAt,
"updated_at": v.UpdatedAt,
"tenant_id": scope.GetTenantID(),
"vendor_id": v.ID,
"organization_id": v.OrganizationID,
"name": v.Name,
"description": v.Description,
"category": v.Category,
"headquarter_address": v.HeadquarterAddress,
"legal_name": v.LegalName,
"website_url": v.WebsiteURL,
"privacy_policy_url": v.PrivacyPolicyURL,
"service_level_agreement_url": v.ServiceLevelAgreementURL,
"data_processing_agreement_url": v.DataProcessingAgreementURL,
"certifications": v.Certifications,
"service_start_at": v.ServiceStartAt,
"service_termination_at": v.ServiceTerminationAt,
"service_criticality": v.ServiceCriticality,
"risk_tier": v.RiskTier,
"status_page_url": v.StatusPageURL,
"terms_of_service_url": v.TermsOfServiceURL,
"security_page_url": v.SecurityPageURL,
"trust_page_url": v.TrustPageURL,
"created_at": v.CreatedAt,
"updated_at": v.UpdatedAt,
}
_, err := conn.Exec(ctx, q, args)
return err
@@ -202,13 +247,22 @@ SELECT
organization_id,
name,
description,
category,
headquarter_address,
legal_name,
website_url,
privacy_policy_url,
service_level_agreement_url,
data_processing_agreement_url,
certifications,
service_start_at,
service_termination_at,
service_criticality,
risk_tier,
status_page_url,
terms_of_service_url,
privacy_policy_url,
security_page_url,
trust_page_url,
created_at,
updated_at
FROM
@@ -253,9 +307,18 @@ SET
service_termination_at = @service_termination_at,
service_criticality = @service_criticality,
risk_tier = @risk_tier,
category = @category,
headquarter_address = @headquarter_address,
legal_name = @legal_name,
website_url = @website_url,
privacy_policy_url = @privacy_policy_url,
service_level_agreement_url = @service_level_agreement_url,
data_processing_agreement_url = @data_processing_agreement_url,
certifications = @certifications,
status_page_url = @status_page_url,
terms_of_service_url = @terms_of_service_url,
privacy_policy_url = @privacy_policy_url,
security_page_url = @security_page_url,
trust_page_url = @trust_page_url,
updated_at = @updated_at
WHERE %s
AND id = @vendor_id
@@ -263,17 +326,26 @@ WHERE %s
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"vendor_id": v.ID,
"updated_at": time.Now(),
"name": v.Name,
"description": v.Description,
"service_start_at": v.ServiceStartAt,
"service_termination_at": v.ServiceTerminationAt,
"service_criticality": v.ServiceCriticality,
"risk_tier": v.RiskTier,
"status_page_url": v.StatusPageURL,
"terms_of_service_url": v.TermsOfServiceURL,
"privacy_policy_url": v.PrivacyPolicyURL,
"vendor_id": v.ID,
"updated_at": time.Now(),
"name": v.Name,
"description": v.Description,
"service_start_at": v.ServiceStartAt,
"service_termination_at": v.ServiceTerminationAt,
"service_criticality": v.ServiceCriticality,
"risk_tier": v.RiskTier,
"category": v.Category,
"headquarter_address": v.HeadquarterAddress,
"legal_name": v.LegalName,
"website_url": v.WebsiteURL,
"privacy_policy_url": v.PrivacyPolicyURL,
"service_level_agreement_url": v.ServiceLevelAgreementURL,
"data_processing_agreement_url": v.DataProcessingAgreementURL,
"certifications": v.Certifications,
"status_page_url": v.StatusPageURL,
"terms_of_service_url": v.TermsOfServiceURL,
"security_page_url": v.SecurityPageURL,
"trust_page_url": v.TrustPageURL,
}
maps.Copy(args, scope.SQLArguments())

View File

@@ -31,30 +31,47 @@ type (
}
CreateVendorRequest struct {
OrganizationID gid.GID
Name string
Description string
ServiceStartAt time.Time
ServiceTerminationAt *time.Time
ServiceCriticality coredata.ServiceCriticality
RiskTier coredata.RiskTier
StatusPageURL *string
TermsOfServiceURL *string
PrivacyPolicyURL *string
OrganizationID gid.GID
Name string
Description *string
HeadquarterAddress *string
LegalName *string
WebsiteURL *string
Category *string
PrivacyPolicyURL *string
ServiceLevelAgreementURL *string
DataProcessingAgreementURL *string
Certifications []string
SecurityPageURL *string
TrustPageURL *string
TermsOfServiceURL *string
StatusPageURL *string
ServiceStartAt time.Time
ServiceTerminationAt *time.Time
ServiceCriticality coredata.ServiceCriticality
RiskTier coredata.RiskTier
}
UpdateVendorRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
ServiceStartAt *time.Time
ServiceTerminationAt *time.Time
ServiceCriticality *coredata.ServiceCriticality
RiskTier *coredata.RiskTier
StatusPageURL *string
TermsOfServiceURL *string
PrivacyPolicyURL *string
ID gid.GID
Name *string
Description *string
HeadquarterAddress *string
LegalName *string
WebsiteURL *string
TermsOfServiceURL *string
Category *string
PrivacyPolicyURL *string
ServiceLevelAgreementURL *string
DataProcessingAgreementURL *string
Certifications []string
SecurityPageURL *string
TrustPageURL *string
StatusPageURL *string
ServiceStartAt *time.Time
ServiceTerminationAt *time.Time
ServiceCriticality *coredata.ServiceCriticality
RiskTier *coredata.RiskTier
}
)
@@ -103,7 +120,7 @@ func (s VendorService) Update(
}
if req.Description != nil {
vendor.Description = *req.Description
vendor.Description = req.Description
}
if req.ServiceStartAt != nil {
@@ -134,6 +151,60 @@ func (s VendorService) Update(
vendor.PrivacyPolicyURL = req.PrivacyPolicyURL
}
if req.ServiceLevelAgreementURL != nil {
vendor.ServiceLevelAgreementURL = req.ServiceLevelAgreementURL
}
if req.DataProcessingAgreementURL != nil {
vendor.DataProcessingAgreementURL = req.DataProcessingAgreementURL
}
if req.Category != nil {
vendor.Category = *req.Category
}
if req.SecurityPageURL != nil {
vendor.SecurityPageURL = req.SecurityPageURL
}
if req.TrustPageURL != nil {
vendor.TrustPageURL = req.TrustPageURL
}
if req.HeadquarterAddress != nil {
vendor.HeadquarterAddress = req.HeadquarterAddress
}
if req.LegalName != nil {
vendor.LegalName = req.LegalName
}
if req.WebsiteURL != nil {
vendor.WebsiteURL = req.WebsiteURL
}
if req.TermsOfServiceURL != nil {
vendor.TermsOfServiceURL = req.TermsOfServiceURL
}
if req.Certifications != nil {
vendor.Certifications = req.Certifications
}
if req.StatusPageURL != nil {
vendor.StatusPageURL = req.StatusPageURL
}
if req.SecurityPageURL != nil {
vendor.SecurityPageURL = req.SecurityPageURL
}
if req.TrustPageURL != nil {
vendor.TrustPageURL = req.TrustPageURL
}
vendor.UpdatedAt = time.Now()
if err := vendor.Update(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot update vendor: %w", err)
}
@@ -194,19 +265,33 @@ func (s VendorService) Create(
organization := &coredata.Organization{}
vendor := &coredata.Vendor{
ID: vendorID,
OrganizationID: req.OrganizationID,
Name: req.Name,
CreatedAt: now,
UpdatedAt: now,
Description: req.Description,
ServiceStartAt: req.ServiceStartAt,
ServiceTerminationAt: req.ServiceTerminationAt,
ServiceCriticality: req.ServiceCriticality,
RiskTier: req.RiskTier,
StatusPageURL: req.StatusPageURL,
TermsOfServiceURL: req.TermsOfServiceURL,
PrivacyPolicyURL: req.PrivacyPolicyURL,
ID: vendorID,
OrganizationID: req.OrganizationID,
Name: req.Name,
CreatedAt: now,
UpdatedAt: now,
Description: req.Description,
ServiceStartAt: req.ServiceStartAt,
ServiceTerminationAt: req.ServiceTerminationAt,
HeadquarterAddress: req.HeadquarterAddress,
LegalName: req.LegalName,
WebsiteURL: req.WebsiteURL,
PrivacyPolicyURL: req.PrivacyPolicyURL,
ServiceLevelAgreementURL: req.ServiceLevelAgreementURL,
DataProcessingAgreementURL: req.DataProcessingAgreementURL,
Certifications: req.Certifications,
SecurityPageURL: req.SecurityPageURL,
TrustPageURL: req.TrustPageURL,
StatusPageURL: req.StatusPageURL,
TermsOfServiceURL: req.TermsOfServiceURL,
ServiceCriticality: req.ServiceCriticality,
RiskTier: req.RiskTier,
}
if req.Category != nil {
vendor.Category = *req.Category
} else {
vendor.Category = "Other"
}
err = s.svc.pg.WithTx(

View File

@@ -427,7 +427,7 @@ type People implements Node {
type Vendor implements Node {
id: ID!
name: String!
description: String!
description: String
complianceReports(
first: Int
@@ -444,6 +444,14 @@ type Vendor implements Node {
statusPageUrl: String
termsOfServiceUrl: String
privacyPolicyUrl: String
serviceLevelAgreementUrl: String
dataProcessingAgreementUrl: String
certifications: [String!]!
securityPageUrl: String
trustPageUrl: String
headquarterAddress: String
legalName: String
websiteUrl: String
createdAt: Datetime!
updatedAt: Datetime!
}
@@ -864,14 +872,23 @@ input DeleteOrganizationInput {
input CreateVendorInput {
organizationId: ID!
name: String!
description: String!
description: String
headquarterAddress: String
legalName: String
websiteUrl: String
privacyPolicyUrl: String
category: String
serviceLevelAgreementUrl: String
dataProcessingAgreementUrl: String
certifications: [String!]
securityPageUrl: String
trustPageUrl: String
statusPageUrl: String
termsOfServiceUrl: String
serviceStartAt: Datetime!
serviceTerminationAt: Datetime
serviceCriticality: ServiceCriticality!
riskTier: RiskTier!
statusPageUrl: String
termsOfServiceUrl: String
privacyPolicyUrl: String
}
input UpdateVendorInput {
@@ -885,6 +902,15 @@ input UpdateVendorInput {
statusPageUrl: String
termsOfServiceUrl: String
privacyPolicyUrl: String
serviceLevelAgreementUrl: String
dataProcessingAgreementUrl: String
websiteUrl: String
legalName: String
headquarterAddress: String
category: String
certifications: [String!]
securityPageUrl: String
trustPageUrl: String
}
input DeleteVendorInput {

View File

@@ -508,19 +508,27 @@ type ComplexityRoot struct {
}
Vendor struct {
ComplianceReports func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) int
CreatedAt func(childComplexity int) int
Description func(childComplexity int) int
ID func(childComplexity int) int
Name func(childComplexity int) int
PrivacyPolicyURL func(childComplexity int) int
RiskTier func(childComplexity int) int
ServiceCriticality func(childComplexity int) int
ServiceStartAt func(childComplexity int) int
ServiceTerminationAt func(childComplexity int) int
StatusPageURL func(childComplexity int) int
TermsOfServiceURL func(childComplexity int) int
UpdatedAt func(childComplexity int) int
Certifications func(childComplexity int) int
ComplianceReports func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) int
CreatedAt func(childComplexity int) int
DataProcessingAgreementURL func(childComplexity int) int
Description func(childComplexity int) int
HeadquarterAddress func(childComplexity int) int
ID func(childComplexity int) int
LegalName func(childComplexity int) int
Name func(childComplexity int) int
PrivacyPolicyURL func(childComplexity int) int
RiskTier func(childComplexity int) int
SecurityPageURL func(childComplexity int) int
ServiceCriticality func(childComplexity int) int
ServiceLevelAgreementURL func(childComplexity int) int
ServiceStartAt func(childComplexity int) int
ServiceTerminationAt func(childComplexity int) int
StatusPageURL func(childComplexity int) int
TermsOfServiceURL func(childComplexity int) int
TrustPageURL func(childComplexity int) int
UpdatedAt func(childComplexity int) int
WebsiteURL func(childComplexity int) int
}
VendorComplianceReport struct {
@@ -2498,6 +2506,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.UserEdge.Node(childComplexity), true
case "Vendor.certifications":
if e.complexity.Vendor.Certifications == nil {
break
}
return e.complexity.Vendor.Certifications(childComplexity), true
case "Vendor.complianceReports":
if e.complexity.Vendor.ComplianceReports == nil {
break
@@ -2517,6 +2532,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.CreatedAt(childComplexity), true
case "Vendor.dataProcessingAgreementUrl":
if e.complexity.Vendor.DataProcessingAgreementURL == nil {
break
}
return e.complexity.Vendor.DataProcessingAgreementURL(childComplexity), true
case "Vendor.description":
if e.complexity.Vendor.Description == nil {
break
@@ -2524,6 +2546,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.Description(childComplexity), true
case "Vendor.headquarterAddress":
if e.complexity.Vendor.HeadquarterAddress == nil {
break
}
return e.complexity.Vendor.HeadquarterAddress(childComplexity), true
case "Vendor.id":
if e.complexity.Vendor.ID == nil {
break
@@ -2531,6 +2560,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.ID(childComplexity), true
case "Vendor.legalName":
if e.complexity.Vendor.LegalName == nil {
break
}
return e.complexity.Vendor.LegalName(childComplexity), true
case "Vendor.name":
if e.complexity.Vendor.Name == nil {
break
@@ -2552,6 +2588,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.RiskTier(childComplexity), true
case "Vendor.securityPageUrl":
if e.complexity.Vendor.SecurityPageURL == nil {
break
}
return e.complexity.Vendor.SecurityPageURL(childComplexity), true
case "Vendor.serviceCriticality":
if e.complexity.Vendor.ServiceCriticality == nil {
break
@@ -2559,6 +2602,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.ServiceCriticality(childComplexity), true
case "Vendor.serviceLevelAgreementUrl":
if e.complexity.Vendor.ServiceLevelAgreementURL == nil {
break
}
return e.complexity.Vendor.ServiceLevelAgreementURL(childComplexity), true
case "Vendor.serviceStartAt":
if e.complexity.Vendor.ServiceStartAt == nil {
break
@@ -2587,6 +2637,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.TermsOfServiceURL(childComplexity), true
case "Vendor.trustPageUrl":
if e.complexity.Vendor.TrustPageURL == nil {
break
}
return e.complexity.Vendor.TrustPageURL(childComplexity), true
case "Vendor.updatedAt":
if e.complexity.Vendor.UpdatedAt == nil {
break
@@ -2594,6 +2651,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.UpdatedAt(childComplexity), true
case "Vendor.websiteUrl":
if e.complexity.Vendor.WebsiteURL == nil {
break
}
return e.complexity.Vendor.WebsiteURL(childComplexity), true
case "VendorComplianceReport.createdAt":
if e.complexity.VendorComplianceReport.CreatedAt == nil {
break
@@ -3327,7 +3391,7 @@ type People implements Node {
type Vendor implements Node {
id: ID!
name: String!
description: String!
description: String
complianceReports(
first: Int
@@ -3344,6 +3408,14 @@ type Vendor implements Node {
statusPageUrl: String
termsOfServiceUrl: String
privacyPolicyUrl: String
serviceLevelAgreementUrl: String
dataProcessingAgreementUrl: String
certifications: [String!]!
securityPageUrl: String
trustPageUrl: String
headquarterAddress: String
legalName: String
websiteUrl: String
createdAt: Datetime!
updatedAt: Datetime!
}
@@ -3764,14 +3836,23 @@ input DeleteOrganizationInput {
input CreateVendorInput {
organizationId: ID!
name: String!
description: String!
description: String
headquarterAddress: String
legalName: String
websiteUrl: String
privacyPolicyUrl: String
category: String
serviceLevelAgreementUrl: String
dataProcessingAgreementUrl: String
certifications: [String!]
securityPageUrl: String
trustPageUrl: String
statusPageUrl: String
termsOfServiceUrl: String
serviceStartAt: Datetime!
serviceTerminationAt: Datetime
serviceCriticality: ServiceCriticality!
riskTier: RiskTier!
statusPageUrl: String
termsOfServiceUrl: String
privacyPolicyUrl: String
}
input UpdateVendorInput {
@@ -3785,6 +3866,15 @@ input UpdateVendorInput {
statusPageUrl: String
termsOfServiceUrl: String
privacyPolicyUrl: String
serviceLevelAgreementUrl: String
dataProcessingAgreementUrl: String
websiteUrl: String
legalName: String
headquarterAddress: String
category: String
certifications: [String!]
securityPageUrl: String
trustPageUrl: String
}
input DeleteVendorInput {
@@ -17818,6 +17908,22 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co
return ec.fieldContext_Vendor_termsOfServiceUrl(ctx, field)
case "privacyPolicyUrl":
return ec.fieldContext_Vendor_privacyPolicyUrl(ctx, field)
case "serviceLevelAgreementUrl":
return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field)
case "dataProcessingAgreementUrl":
return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field)
case "certifications":
return ec.fieldContext_Vendor_certifications(ctx, field)
case "securityPageUrl":
return ec.fieldContext_Vendor_securityPageUrl(ctx, field)
case "trustPageUrl":
return ec.fieldContext_Vendor_trustPageUrl(ctx, field)
case "headquarterAddress":
return ec.fieldContext_Vendor_headquarterAddress(ctx, field)
case "legalName":
return ec.fieldContext_Vendor_legalName(ctx, field)
case "websiteUrl":
return ec.fieldContext_Vendor_websiteUrl(ctx, field)
case "createdAt":
return ec.fieldContext_Vendor_createdAt(ctx, field)
case "updatedAt":
@@ -18412,14 +18518,11 @@ func (ec *executionContext) _Vendor_description(ctx context.Context, field graph
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
res := resTmp.(*string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
return ec.marshalOString2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -18792,6 +18895,337 @@ func (ec *executionContext) fieldContext_Vendor_privacyPolicyUrl(_ context.Conte
return fc, nil
}
func (ec *executionContext) _Vendor_serviceLevelAgreementUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.ServiceLevelAgreementURL, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_serviceLevelAgreementUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_dataProcessingAgreementUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.DataProcessingAgreementURL, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_dataProcessingAgreementUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_certifications(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_certifications(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Certifications, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]string)
fc.Result = res
return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_certifications(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_securityPageUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_securityPageUrl(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.SecurityPageURL, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_securityPageUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_trustPageUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_trustPageUrl(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.TrustPageURL, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_trustPageUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_headquarterAddress(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_headquarterAddress(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.HeadquarterAddress, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_headquarterAddress(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_legalName(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_legalName(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.LegalName, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_legalName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_websiteUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_websiteUrl(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.WebsiteURL, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_websiteUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Vendor",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_createdAt(ctx, field)
if err != nil {
@@ -18985,6 +19419,22 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context
return ec.fieldContext_Vendor_termsOfServiceUrl(ctx, field)
case "privacyPolicyUrl":
return ec.fieldContext_Vendor_privacyPolicyUrl(ctx, field)
case "serviceLevelAgreementUrl":
return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field)
case "dataProcessingAgreementUrl":
return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field)
case "certifications":
return ec.fieldContext_Vendor_certifications(ctx, field)
case "securityPageUrl":
return ec.fieldContext_Vendor_securityPageUrl(ctx, field)
case "trustPageUrl":
return ec.fieldContext_Vendor_trustPageUrl(ctx, field)
case "headquarterAddress":
return ec.fieldContext_Vendor_headquarterAddress(ctx, field)
case "legalName":
return ec.fieldContext_Vendor_legalName(ctx, field)
case "websiteUrl":
return ec.fieldContext_Vendor_websiteUrl(ctx, field)
case "createdAt":
return ec.fieldContext_Vendor_createdAt(ctx, field)
case "updatedAt":
@@ -19722,6 +20172,22 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel
return ec.fieldContext_Vendor_termsOfServiceUrl(ctx, field)
case "privacyPolicyUrl":
return ec.fieldContext_Vendor_privacyPolicyUrl(ctx, field)
case "serviceLevelAgreementUrl":
return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field)
case "dataProcessingAgreementUrl":
return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field)
case "certifications":
return ec.fieldContext_Vendor_certifications(ctx, field)
case "securityPageUrl":
return ec.fieldContext_Vendor_securityPageUrl(ctx, field)
case "trustPageUrl":
return ec.fieldContext_Vendor_trustPageUrl(ctx, field)
case "headquarterAddress":
return ec.fieldContext_Vendor_headquarterAddress(ctx, field)
case "legalName":
return ec.fieldContext_Vendor_legalName(ctx, field)
case "websiteUrl":
return ec.fieldContext_Vendor_websiteUrl(ctx, field)
case "createdAt":
return ec.fieldContext_Vendor_createdAt(ctx, field)
case "updatedAt":
@@ -22475,7 +22941,7 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context,
asMap[k] = v
}
fieldsInOrder := [...]string{"organizationId", "name", "description", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl"}
fieldsInOrder := [...]string{"organizationId", "name", "description", "headquarterAddress", "legalName", "websiteUrl", "privacyPolicyUrl", "category", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "certifications", "securityPageUrl", "trustPageUrl", "statusPageUrl", "termsOfServiceUrl", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -22498,11 +22964,95 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context,
it.Name = data
case "description":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description"))
data, err := ec.unmarshalNString2string(ctx, v)
data, err := ec.unmarshalOString2string(ctx, v)
if err != nil {
return it, err
}
it.Description = data
case "headquarterAddress":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("headquarterAddress"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.HeadquarterAddress = data
case "legalName":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("legalName"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.LegalName = data
case "websiteUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("websiteUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.WebsiteURL = data
case "privacyPolicyUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("privacyPolicyUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.PrivacyPolicyURL = data
case "category":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.Category = data
case "serviceLevelAgreementUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceLevelAgreementUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.ServiceLevelAgreementURL = data
case "dataProcessingAgreementUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataProcessingAgreementUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.DataProcessingAgreementURL = data
case "certifications":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("certifications"))
data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v)
if err != nil {
return it, err
}
it.Certifications = data
case "securityPageUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("securityPageUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.SecurityPageURL = data
case "trustPageUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("trustPageUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.TrustPageURL = data
case "statusPageUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusPageUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.StatusPageURL = data
case "termsOfServiceUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("termsOfServiceUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.TermsOfServiceURL = data
case "serviceStartAt":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceStartAt"))
data, err := ec.unmarshalNDatetime2timeᚐTime(ctx, v)
@@ -22531,27 +23081,6 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context,
return it, err
}
it.RiskTier = data
case "statusPageUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusPageUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.StatusPageURL = data
case "termsOfServiceUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("termsOfServiceUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.TermsOfServiceURL = data
case "privacyPolicyUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("privacyPolicyUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.PrivacyPolicyURL = data
}
}
@@ -23819,7 +24348,7 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context,
asMap[k] = v
}
fieldsInOrder := [...]string{"id", "name", "description", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl"}
fieldsInOrder := [...]string{"id", "name", "description", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -23896,6 +24425,69 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context,
return it, err
}
it.PrivacyPolicyURL = data
case "serviceLevelAgreementUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceLevelAgreementUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.ServiceLevelAgreementURL = data
case "dataProcessingAgreementUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataProcessingAgreementUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.DataProcessingAgreementURL = data
case "websiteUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("websiteUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.WebsiteURL = data
case "legalName":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("legalName"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.LegalName = data
case "headquarterAddress":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("headquarterAddress"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.HeadquarterAddress = data
case "category":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.Category = data
case "certifications":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("certifications"))
data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v)
if err != nil {
return it, err
}
it.Certifications = data
case "securityPageUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("securityPageUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.SecurityPageURL = data
case "trustPageUrl":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("trustPageUrl"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.TrustPageURL = data
}
}
@@ -28595,9 +29187,6 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o
}
case "description":
out.Values[i] = ec._Vendor_description(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "complianceReports":
field := field
@@ -28657,6 +29246,25 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o
out.Values[i] = ec._Vendor_termsOfServiceUrl(ctx, field, obj)
case "privacyPolicyUrl":
out.Values[i] = ec._Vendor_privacyPolicyUrl(ctx, field, obj)
case "serviceLevelAgreementUrl":
out.Values[i] = ec._Vendor_serviceLevelAgreementUrl(ctx, field, obj)
case "dataProcessingAgreementUrl":
out.Values[i] = ec._Vendor_dataProcessingAgreementUrl(ctx, field, obj)
case "certifications":
out.Values[i] = ec._Vendor_certifications(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "securityPageUrl":
out.Values[i] = ec._Vendor_securityPageUrl(ctx, field, obj)
case "trustPageUrl":
out.Values[i] = ec._Vendor_trustPageUrl(ctx, field, obj)
case "headquarterAddress":
out.Values[i] = ec._Vendor_headquarterAddress(ctx, field, obj)
case "legalName":
out.Values[i] = ec._Vendor_legalName(ctx, field, obj)
case "websiteUrl":
out.Values[i] = ec._Vendor_websiteUrl(ctx, field, obj)
case "createdAt":
out.Values[i] = ec._Vendor_createdAt(ctx, field, obj)
if out.Values[i] == graphql.Null {

View File

@@ -182,16 +182,25 @@ type CreateTaskPayload struct {
}
type CreateVendorInput struct {
OrganizationID gid.GID `json:"organizationId"`
Name string `json:"name"`
Description string `json:"description"`
ServiceStartAt time.Time `json:"serviceStartAt"`
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
RiskTier coredata.RiskTier `json:"riskTier"`
StatusPageURL *string `json:"statusPageUrl,omitempty"`
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
OrganizationID gid.GID `json:"organizationId"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
HeadquarterAddress *string `json:"headquarterAddress,omitempty"`
LegalName *string `json:"legalName,omitempty"`
WebsiteURL *string `json:"websiteUrl,omitempty"`
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
Category *string `json:"category,omitempty"`
ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"`
DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"`
Certifications []string `json:"certifications,omitempty"`
SecurityPageURL *string `json:"securityPageUrl,omitempty"`
TrustPageURL *string `json:"trustPageUrl,omitempty"`
StatusPageURL *string `json:"statusPageUrl,omitempty"`
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
ServiceStartAt time.Time `json:"serviceStartAt"`
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
RiskTier coredata.RiskTier `json:"riskTier"`
}
type CreateVendorPayload struct {
@@ -671,16 +680,25 @@ type UpdateTaskPayload struct {
}
type UpdateVendorInput struct {
ID gid.GID `json:"id"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
ServiceStartAt *time.Time `json:"serviceStartAt,omitempty"`
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
ServiceCriticality *coredata.ServiceCriticality `json:"serviceCriticality,omitempty"`
RiskTier *coredata.RiskTier `json:"riskTier,omitempty"`
StatusPageURL *string `json:"statusPageUrl,omitempty"`
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
ID gid.GID `json:"id"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
ServiceStartAt *time.Time `json:"serviceStartAt,omitempty"`
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
ServiceCriticality *coredata.ServiceCriticality `json:"serviceCriticality,omitempty"`
RiskTier *coredata.RiskTier `json:"riskTier,omitempty"`
StatusPageURL *string `json:"statusPageUrl,omitempty"`
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"`
DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"`
WebsiteURL *string `json:"websiteUrl,omitempty"`
LegalName *string `json:"legalName,omitempty"`
HeadquarterAddress *string `json:"headquarterAddress,omitempty"`
Category *string `json:"category,omitempty"`
Certifications []string `json:"certifications,omitempty"`
SecurityPageURL *string `json:"securityPageUrl,omitempty"`
TrustPageURL *string `json:"trustPageUrl,omitempty"`
}
type UpdateVendorPayload struct {
@@ -721,19 +739,27 @@ type UserEdge struct {
}
type Vendor struct {
ID gid.GID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"`
ServiceStartAt time.Time `json:"serviceStartAt"`
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
RiskTier coredata.RiskTier `json:"riskTier"`
StatusPageURL *string `json:"statusPageUrl,omitempty"`
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ID gid.GID `json:"id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"`
ServiceStartAt time.Time `json:"serviceStartAt"`
ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"`
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
RiskTier coredata.RiskTier `json:"riskTier"`
StatusPageURL *string `json:"statusPageUrl,omitempty"`
TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"`
PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"`
ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"`
DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"`
Certifications []string `json:"certifications"`
SecurityPageURL *string `json:"securityPageUrl,omitempty"`
TrustPageURL *string `json:"trustPageUrl,omitempty"`
HeadquarterAddress *string `json:"headquarterAddress,omitempty"`
LegalName *string `json:"legalName,omitempty"`
WebsiteURL *string `json:"websiteUrl,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
func (Vendor) IsNode() {}

View File

@@ -45,17 +45,25 @@ func NewVendorEdge(v *coredata.Vendor, orderBy coredata.VendorOrderField) *Vendo
func NewVendor(v *coredata.Vendor) *Vendor {
return &Vendor{
ID: v.ID,
Name: v.Name,
Description: v.Description,
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
ServiceStartAt: v.ServiceStartAt,
ServiceTerminationAt: v.ServiceTerminationAt,
ServiceCriticality: v.ServiceCriticality,
RiskTier: v.RiskTier,
StatusPageURL: v.StatusPageURL,
TermsOfServiceURL: v.TermsOfServiceURL,
PrivacyPolicyURL: v.PrivacyPolicyURL,
ID: v.ID,
Name: v.Name,
Description: v.Description,
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
ServiceStartAt: v.ServiceStartAt,
ServiceTerminationAt: v.ServiceTerminationAt,
ServiceCriticality: v.ServiceCriticality,
RiskTier: v.RiskTier,
StatusPageURL: v.StatusPageURL,
TermsOfServiceURL: v.TermsOfServiceURL,
PrivacyPolicyURL: v.PrivacyPolicyURL,
ServiceLevelAgreementURL: v.ServiceLevelAgreementURL,
DataProcessingAgreementURL: v.DataProcessingAgreementURL,
Certifications: v.Certifications,
SecurityPageURL: v.SecurityPageURL,
TrustPageURL: v.TrustPageURL,
HeadquarterAddress: v.HeadquarterAddress,
LegalName: v.LegalName,
WebsiteURL: v.WebsiteURL,
}
}

View File

@@ -355,18 +355,30 @@ func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeleteP
func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) {
svc := r.GetTenantServiceIfAuthorized(ctx, input.OrganizationID.TenantID())
vendor, err := svc.Vendors.Create(ctx, probo.CreateVendorRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Description: input.Description,
ServiceStartAt: input.ServiceStartAt,
ServiceTerminationAt: input.ServiceTerminationAt,
ServiceCriticality: input.ServiceCriticality,
RiskTier: input.RiskTier,
StatusPageURL: input.StatusPageURL,
TermsOfServiceURL: input.TermsOfServiceURL,
PrivacyPolicyURL: input.PrivacyPolicyURL,
})
vendor, err := svc.Vendors.Create(
ctx,
probo.CreateVendorRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Description: input.Description,
ServiceStartAt: input.ServiceStartAt,
ServiceTerminationAt: input.ServiceTerminationAt,
ServiceCriticality: input.ServiceCriticality,
RiskTier: input.RiskTier,
StatusPageURL: input.StatusPageURL,
TermsOfServiceURL: input.TermsOfServiceURL,
PrivacyPolicyURL: input.PrivacyPolicyURL,
ServiceLevelAgreementURL: input.ServiceLevelAgreementURL,
LegalName: input.LegalName,
HeadquarterAddress: input.HeadquarterAddress,
WebsiteURL: input.WebsiteURL,
Category: input.Category,
DataProcessingAgreementURL: input.DataProcessingAgreementURL,
Certifications: input.Certifications,
SecurityPageURL: input.SecurityPageURL,
TrustPageURL: input.TrustPageURL,
},
)
if err != nil {
return nil, fmt.Errorf("cannot create vendor: %w", err)
}
@@ -380,16 +392,25 @@ func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateV
svc := r.GetTenantServiceIfAuthorized(ctx, input.ID.TenantID())
vendor, err := svc.Vendors.Update(ctx, probo.UpdateVendorRequest{
ID: input.ID,
Name: input.Name,
Description: input.Description,
ServiceStartAt: input.ServiceStartAt,
ServiceTerminationAt: input.ServiceTerminationAt,
ServiceCriticality: input.ServiceCriticality,
RiskTier: input.RiskTier,
StatusPageURL: input.StatusPageURL,
TermsOfServiceURL: input.TermsOfServiceURL,
PrivacyPolicyURL: input.PrivacyPolicyURL,
ID: input.ID,
Name: input.Name,
Description: input.Description,
ServiceStartAt: input.ServiceStartAt,
ServiceTerminationAt: input.ServiceTerminationAt,
ServiceCriticality: input.ServiceCriticality,
RiskTier: input.RiskTier,
StatusPageURL: input.StatusPageURL,
TermsOfServiceURL: input.TermsOfServiceURL,
PrivacyPolicyURL: input.PrivacyPolicyURL,
ServiceLevelAgreementURL: input.ServiceLevelAgreementURL,
DataProcessingAgreementURL: input.DataProcessingAgreementURL,
SecurityPageURL: input.SecurityPageURL,
TrustPageURL: input.TrustPageURL,
HeadquarterAddress: input.HeadquarterAddress,
LegalName: input.LegalName,
WebsiteURL: input.WebsiteURL,
Category: input.Category,
Certifications: input.Certifications,
})
if err != nil {
return nil, fmt.Errorf("cannot update vendor: %w", err)