From 9fa33726e7cd1af166e6a13bdc3368b38f81f7d2 Mon Sep 17 00:00:00 2001 From: gearnode Date: Thu, 10 Apr 2025 17:19:35 -0700 Subject: [PATCH] Enhance vendor management with extended data fields Signed-off-by: gearnode --- CHANGELOG.md | 16 +- LICENSE | 173 ++++- apps/console/public/data/vendors/LICENSE.md | 24 + apps/console/public/data/vendors/vendors.json | 309 ++++++++ .../organizations/vendors/VendorListView.tsx | 107 ++- .../organizations/vendors/VendorView.tsx | 192 ++++- ...dorListViewCreateVendorMutation.graphql.ts | 15 +- .../VendorListView_vendors.graphql.ts | 4 +- .../__generated__/VendorViewQuery.graphql.ts | 112 ++- .../VendorViewUpdateVendorMutation.graphql.ts | 83 +- pkg/coredata/migrations/20250410T160300Z.sql | 12 + pkg/coredata/migrations/20250410T160700Z.sql | 1 + pkg/coredata/migrations/20250410T161200Z.sql | 1 + pkg/coredata/migrations/20250410T162000Z.sql | 6 + pkg/coredata/vendor.go | 158 ++-- pkg/probo/vendor_service.go | 155 +++- pkg/server/api/console/v1/schema.graphql | 36 +- pkg/server/api/console/v1/schema/schema.go | 708 ++++++++++++++++-- pkg/server/api/console/v1/types/types.go | 92 ++- pkg/server/api/console/v1/types/vendor.go | 32 +- pkg/server/api/console/v1/v1_resolver.go | 65 +- 21 files changed, 2013 insertions(+), 288 deletions(-) create mode 100644 apps/console/public/data/vendors/LICENSE.md create mode 100644 apps/console/public/data/vendors/vendors.json create mode 100644 pkg/coredata/migrations/20250410T160300Z.sql create mode 100644 pkg/coredata/migrations/20250410T160700Z.sql create mode 100644 pkg/coredata/migrations/20250410T161200Z.sql create mode 100644 pkg/coredata/migrations/20250410T162000Z.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index ed30607e2..21c5e1680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/LICENSE b/LICENSE index 655d3b00a..52e8e47e0 100644 --- a/LICENSE +++ b/LICENSE @@ -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. diff --git a/apps/console/public/data/vendors/LICENSE.md b/apps/console/public/data/vendors/LICENSE.md new file mode 100644 index 000000000..1b29b58ec --- /dev/null +++ b/apps/console/public/data/vendors/LICENSE.md @@ -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/ diff --git a/apps/console/public/data/vendors/vendors.json b/apps/console/public/data/vendors/vendors.json new file mode 100644 index 000000000..bb0c58c53 --- /dev/null +++ b/apps/console/public/data/vendors/vendors.json @@ -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/" + } +] diff --git a/apps/console/src/pages/organizations/vendors/VendorListView.tsx b/apps/console/src/pages/organizations/vendors/VendorListView.tsx index 4bd23fa07..4ceaec9d8 100644 --- a/apps/console/src/pages/organizations/vendors/VendorListView.tsx +++ b/apps/console/src/pages/organizations/vendors/VendorListView.tsx @@ -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([]); + const [filteredVendors, setFilteredVendors] = useState([]); + const [vendorsData, setVendorsData] = useState([]); + const [isLoadingVendors, setIsLoadingVendors] = useState(false); const [createVendor] = useMutation(createVendorMutation); const [deleteVendor] = useMutation(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(vendorsData, { keys: ["name"], threshold: 0.3, }); @@ -269,16 +282,22 @@ function VendorListContent({ setFilteredVendors(results); } }} + disabled={isLoadingVendors} /> + {isLoadingVendors && ( +
+
+
+ )} {searchTerm.trim() !== "" && (
- {filteredVendors.map((vendor: VendorItem) => ( + {filteredVendors.map((vendor) => ( +
+ ))} + + setNewTag(e.target.value)} + onKeyDown={handleAddTag} + placeholder="Type and press Enter to add a certification" + className="mt-2" + /> + + ); +} + 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(updateVendorMutation); const [deleteVendorComplianceReport] = useMutation( 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)} /> + handleFieldChange("legalName", value)} + /> + + handleFieldChange("headquarterAddress", value)} + /> + + handleFieldChange("websiteUrl", value)} + /> +
@@ -628,16 +728,29 @@ function VendorViewContent({ "General vendor with minimal risk"}

+
+ +
+ +
+
+

URLs

+

+ Important URLs related to the vendor +

+
+ +
handleFieldChange("statusPageUrl", value)} /> handleFieldChange("termsOfServiceUrl", value) } @@ -645,11 +758,76 @@ function VendorViewContent({ handleFieldChange("privacyPolicyUrl", value) } /> + + + handleFieldChange("serviceLevelAgreementUrl", value) + } + /> + + + handleFieldChange("dataProcessingAgreementUrl", value) + } + /> + + + handleFieldChange("securityPageUrl", value) + } + /> + + handleFieldChange("trustPageUrl", value)} + /> +
+
+
+ + +
+
+

Certifications

+

+ List of certifications held by the vendor +

+
+ +
+
+
+ + +
+ + handleFieldChange("certifications", [ + ...formData.certifications, + tag, + ]) + } + onRemove={(tag) => + handleFieldChange( + "certifications", + formData.certifications.filter((t) => t !== tag) + ) + } + /> +
diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorListViewCreateVendorMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorListViewCreateVendorMutation.graphql.ts index 38ee3755e..bb96005a4 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorListViewCreateVendorMutation.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorListViewCreateVendorMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<38a771b621d1e813bc7dbdd6d5bcf323>> + * @generated SignedSource<> * @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 | 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; @@ -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; diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorListView_vendors.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorListView_vendors.graphql.ts index 1b1e5f857..904a2f30d 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorListView_vendors.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorListView_vendors.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<7b424e7690762d554e28421c32fdee78>> + * @generated SignedSource<> * @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; diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts index 5282ebb22..62a0c7a7a 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -16,6 +16,7 @@ export type VendorViewQuery$variables = { }; export type VendorViewQuery$data = { readonly node: { + readonly certifications?: ReadonlyArray; 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; diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts index 4d5d9e075..e6ea62d6f 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts @@ -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 | 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; + 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; diff --git a/pkg/coredata/migrations/20250410T160300Z.sql b/pkg/coredata/migrations/20250410T160300Z.sql new file mode 100644 index 000000000..b3aa2b29b --- /dev/null +++ b/pkg/coredata/migrations/20250410T160300Z.sql @@ -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[]; + + diff --git a/pkg/coredata/migrations/20250410T160700Z.sql b/pkg/coredata/migrations/20250410T160700Z.sql new file mode 100644 index 000000000..6878ae1df --- /dev/null +++ b/pkg/coredata/migrations/20250410T160700Z.sql @@ -0,0 +1 @@ +UPDATE vendors SET category = 'Other' WHERE category IS NULL; \ No newline at end of file diff --git a/pkg/coredata/migrations/20250410T161200Z.sql b/pkg/coredata/migrations/20250410T161200Z.sql new file mode 100644 index 000000000..27294c1e1 --- /dev/null +++ b/pkg/coredata/migrations/20250410T161200Z.sql @@ -0,0 +1 @@ +ALTER TABLE vendors ALTER COLUMN description DROP NOT NULL; \ No newline at end of file diff --git a/pkg/coredata/migrations/20250410T162000Z.sql b/pkg/coredata/migrations/20250410T162000Z.sql new file mode 100644 index 000000000..ba7931986 --- /dev/null +++ b/pkg/coredata/migrations/20250410T162000Z.sql @@ -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; \ No newline at end of file diff --git a/pkg/coredata/vendor.go b/pkg/coredata/vendor.go index 578bb060e..f33ccb7bd 100644 --- a/pkg/coredata/vendor.go +++ b/pkg/coredata/vendor.go @@ -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()) diff --git a/pkg/probo/vendor_service.go b/pkg/probo/vendor_service.go index ff017d748..766cae5e6 100644 --- a/pkg/probo/vendor_service.go +++ b/pkg/probo/vendor_service.go @@ -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( diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index 867095f5b..eecae5b4c 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -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 { diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index e9091230d..2424e9db5 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -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.marshalOString2ᚖstring(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.unmarshalOString2ᚖstring(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 { diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index bf71054ad..31db7c132 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -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() {} diff --git a/pkg/server/api/console/v1/types/vendor.go b/pkg/server/api/console/v1/types/vendor.go index ffa7bfcfe..ad8bd55c3 100644 --- a/pkg/server/api/console/v1/types/vendor.go +++ b/pkg/server/api/console/v1/types/vendor.go @@ -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, } } diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 972bfb94d..535857a3c 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -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)